<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">Blog posts by Miroslaw Jedynak</title><link href="http://world.optimizely.com" /><updated>2013-02-22T08:00:00.0000000Z</updated><id>https://world.optimizely.com/blogs/Miroslaw-Jedynak/</id> <generator uri="http://world.optimizely.com" version="2.0">Optimizely World</generator> <entry><title>Geo Point Picker property for EPiServer 7 from Making Waves</title><link href="http://blog.m.jedynak.pl/2013/02/geo-point-picker-property-for-episerver.html" /><id>&lt;b&gt;Piotr Dela&lt;/b&gt; from &lt;a href=&quot;http://makingwaves.com&quot;&gt;Making Waves&lt;/a&gt; created &lt;b&gt;&lt;a href=&quot;http://openwaves.codeplex.com/wikipage?title=OpenWaves.EPiServer.GeoPickerProperty&quot;&gt;Geo Point Picker&lt;/a&gt;&lt;/b&gt; property for EPiServer7  &lt;br /&gt;&lt;br /&gt;GeoPicker property is based on Google Maps API and provides a rich interface for selecting a geo-coordinates – perfect for editing location of points of interests we want to show on a map. &lt;br /&gt;&lt;ul&gt;&lt;li&gt;Source code is available at: &lt;a href=&quot;https://openwaves.codeplex.com/SourceControl/changeset/view/85301#1685614&quot;&gt;https://openwaves.codeplex.com/SourceControl/changeset/view/85301#1685614&lt;/a&gt;&lt;/li&gt;&lt;li&gt; Documentation is at: &lt;a href=&quot;http://openwaves.codeplex.com/wikipage?title=OpenWaves.EPiServer.GeoPickerProperty&quot;&gt;http://openwaves.codeplex.com/wikipage?title=OpenWaves.EPiServer.GeoPickerProperty&lt;/a&gt;&lt;/li&gt;&lt;li&gt;NuGet package: &lt;a href=&quot;http://nuget.org/packages/OpenWaves.EPiServer.GeoProperties/&quot;&gt;http://nuget.org/packages/OpenWaves.EPiServer.GeoProperties/&lt;/a&gt; &lt;/li&gt;&lt;/ul&gt;  &lt;br /&gt;&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Installation&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Install &lt;b&gt;OpenWaves.EPiServer.GeoProperties&lt;/b&gt; NuGet package from &lt;a href=&quot;http://nuget.org/packages/OpenWaves.EPiServer.GeoProperties/&quot;&gt;http://nuget.org/packages/OpenWaves.EPiServer.GeoProperties/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Getting started&lt;/span&gt;&lt;/b&gt;&lt;br /&gt; To use the property set the type of the property to GeoPoint. &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;using OpenWaves.EPiServer.GeoProperties;&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;[UIHint(PropertyGeoPoint.UiHint)]&lt;br /&gt;public virtual GeoPoint CustomLocation { get; set; }&lt;/code&gt;&lt;/pre&gt; &lt;br /&gt;&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;From edit mode&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Property editor lets editors type the geo-coordinates in Lat/Long number inputs or click on the location thumbnail to display a richer UI. &lt;br /&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-7q5CAmbiTxg/USXgylKi_LI/AAAAAAAAAqk/cb3yKxjCnJ8/s1600/geo_point_picker_1.png&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://1.bp.blogspot.com/-7q5CAmbiTxg/USXgylKi_LI/AAAAAAAAAqk/cb3yKxjCnJ8/s320/geo_point_picker_1.png&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The popup lets editors search for locations and/or select a point by dragging a marker over the map. &lt;br /&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-zuA1oW_iF-g/USXgypg0HII/AAAAAAAAAqg/Z7AxXptDJ_s/s1600/geo_point_picker_2.png&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://3.bp.blogspot.com/-zuA1oW_iF-g/USXgypg0HII/AAAAAAAAAqg/Z7AxXptDJ_s/s320/geo_point_picker_2.png&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;After the location is selected, property editor shows a thumbnail of the location and its geo-coordinates. &lt;br /&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-4Dyi0emUusE/USXgymtAIXI/AAAAAAAAAqc/1KyGY4adq7c/s1600/geo_point_picker_3.png&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://3.bp.blogspot.com/-4Dyi0emUusE/USXgymtAIXI/AAAAAAAAAqc/1KyGY4adq7c/s320/geo_point_picker_3.png&quot; /&gt;&lt;/a&gt;</id><updated>2013-02-22T08:00:00.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>OpenWaves.EPiServer.Localization: Strongly typed strongly typed access to EPiServer language files</title><link href="http://blog.m.jedynak.pl/2013/02/openwavesepiserverlocalization-strongly.html" /><id>Recently Making Waves released OpenWaves.EPiServer.Localization NuGet package. It provides strongly typed access to EPiServer lang.  Now you can use: &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&lt;br /&gt;string text = TranslationKeys.MyPage.MyCategory.Intro.GetString();&lt;br /&gt;&lt;br /&gt;// instead of&lt;br /&gt;// string text = LocalizationService.Current.GetString(&quot;/myPage/myCategory/intro&quot;);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Benefits&lt;/span&gt;&lt;/b&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Intelli Sense support&lt;/b&gt;&lt;/li&gt;&lt;li&gt;Compile time check for correct language keys&lt;/li&gt;&lt;li&gt;When refactoring all occurrences are renamed&lt;/li&gt;&lt;li&gt;Supports &quot;Find all usages&quot; of language keys&lt;/li&gt;&lt;/ul&gt; &lt;br /&gt;&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Usage&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Add NuGet package OpenWaves.EPiServer.Localization    &lt;br /&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-qXYQC1xSiPc/USNXyEjq5eI/AAAAAAAAAqE/qRDgDE5_2tU/s1600/manage_packages.png&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://4.bp.blogspot.com/-qXYQC1xSiPc/USNXyEjq5eI/AAAAAAAAAqE/qRDgDE5_2tU/s320/manage_packages.png&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-MLWvT5CVONU/USNXyGxhlXI/AAAAAAAAAqA/3kgM8FV7-Fs/s1600/install.png&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://3.bp.blogspot.com/-MLWvT5CVONU/USNXyGxhlXI/AAAAAAAAAqA/3kgM8FV7-Fs/s320/install.png&quot; /&gt;&lt;/a&gt;&lt;/li&gt; &lt;li&gt;It&#39;s ready to use!&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;NOTE: After changing language file (*.xml) you have to&quot;Run Custom Tool&quot; manually to regenerate translation key classes&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;   &lt;a href=&quot;http://4.bp.blogspot.com/-bzGiRwQYzm0/USNXyH3qu2I/AAAAAAAAAp8/N64i_bvmcms/s1600/run_custom_tool.png&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://4.bp.blogspot.com/-bzGiRwQYzm0/USNXyH3qu2I/AAAAAAAAAp8/N64i_bvmcms/s320/run_custom_tool.png&quot; /&gt;&lt;/a&gt;</id><updated>2013-02-19T11:49:00.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>OpenWaves.EPiServer.Localization: Strongly typed access to EPiServer language files</title><link href="http://blog.m.jedynak.pl/2013/02/openwavesepiserverlocalization-strongly.html" /><id>Recently Making Waves released OpenWaves.EPiServer.Localization NuGet package. It provides strongly typed access to EPiServer lang.  Now you can use: &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&lt;br /&gt;string text = TranslationKeys.MyPage.MyCategory.Intro.GetString();&lt;br /&gt;&lt;br /&gt;// instead of&lt;br /&gt;// string text = LocalizationService.Current.GetString(&quot;/myPage/myCategory/intro&quot;);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt; &lt;br /&gt;&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;UPDATE: EPiServer 6 &amp; 7 supported&lt;/span&gt;&lt;/b&gt;&lt;p&gt;Localization package support both EPiServer 6 &amp; 7. To change version change &lt;b&gt;Resources\TranslationKeys.tt&lt;/b&gt;&lt;/p&gt;&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&lt;br /&gt;...&lt;br /&gt;&lt;#@ import namespace=&quot;OpenWaves.EPiServer.Localization.Transformations&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;#&gt;&lt;br /&gt;    var epiServerVersion = 7;&lt;br /&gt;    // for EPiServer 6.x version    &lt;br /&gt;    // var epiServerVersion = 6;&lt;br /&gt;...&lt;br /&gt;&lt;/#&gt;&lt;/#@&gt;&lt;/code&gt;&lt;/pre&gt; &lt;br /&gt;&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Benefits&lt;/span&gt;&lt;/b&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Intelli Sense support&lt;/b&gt;&lt;/li&gt;&lt;li&gt;Compile time check for correct language keys&lt;/li&gt;&lt;li&gt;When refactoring all occurrences are renamed&lt;/li&gt;&lt;li&gt;Supports &quot;Find all usages&quot; of language keys&lt;/li&gt;&lt;/ul&gt; &lt;br /&gt;&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Usage&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Add NuGet package OpenWaves.EPiServer.Localization    &lt;br /&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-qXYQC1xSiPc/USNXyEjq5eI/AAAAAAAAAqE/qRDgDE5_2tU/s1600/manage_packages.png&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://4.bp.blogspot.com/-qXYQC1xSiPc/USNXyEjq5eI/AAAAAAAAAqE/qRDgDE5_2tU/s320/manage_packages.png&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-MLWvT5CVONU/USNXyGxhlXI/AAAAAAAAAqA/3kgM8FV7-Fs/s1600/install.png&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://3.bp.blogspot.com/-MLWvT5CVONU/USNXyGxhlXI/AAAAAAAAAqA/3kgM8FV7-Fs/s320/install.png&quot; /&gt;&lt;/a&gt;&lt;/li&gt; &lt;li&gt;It&#39;s ready to use!&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;NOTE: After changing language file (*.xml) you have to&quot;Run Custom Tool&quot; manually to regenerate translation key classes&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;   &lt;a href=&quot;http://4.bp.blogspot.com/-bzGiRwQYzm0/USNXyH3qu2I/AAAAAAAAAp8/N64i_bvmcms/s1600/run_custom_tool.png&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://4.bp.blogspot.com/-bzGiRwQYzm0/USNXyH3qu2I/AAAAAAAAAp8/N64i_bvmcms/s320/run_custom_tool.png&quot; /&gt;&lt;/a&gt;</id><updated>2013-02-19T11:49:00.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Mobile URL Rewriter</title><link href="http://blog.m.jedynak.pl/2011/03/mobile-url-rewriter.html" /><id>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://lh4.googleusercontent.com/-2_a6vhqdYwE/TXC06nxptAI/AAAAAAAAAgA/haYoiZnEGng/s1600/template_matching.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;/a&gt;&lt;/div&gt;Recently &lt;a href=&quot;http://makingwaves.no/&quot;&gt;Making Waves&lt;/a&gt; has published &lt;a href=&quot;https://www.coderesort.com/p/epicode/wiki/MakingWaves.MobileUrlRewriter&quot;&gt;Mobile Url Rewriting&lt;/a&gt; module on EPiCode. It’s friendly Url engine, which translates incoming Url, so it points to specific template based on configured rules. Most useful scenario is providing device-specific versions (e.g. for mobile devices) using different templates while retrieving data from a single data source (Page Data). &lt;br /&gt;&lt;br /&gt;This flexible solution is editor-friendly because only one form for each page must be filled and it becomes a source for different page templates.&lt;br /&gt;&lt;br /&gt;For latest documentation, source code and binaries visit &lt;a href=&quot;https://www.coderesort.com/p/epicode/wiki/MakingWaves.MobileUrlRewriter&quot;&gt;module&#39;s home page page&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;How it works&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;To illustrate how it works, consider differences between using default friendly Url provider and Making Waves’ rule based Url provider &lt;br /&gt;&lt;br /&gt;For default friendly url provider &lt;br /&gt;&lt;ul&gt;&lt;li&gt;/Articles/Website-Launch url is translated to /Templates/Articles/NewsTemplate.aspx?id=1234 &lt;/li&gt;&lt;li&gt;/Articles/Website-Launch/Mobile returns 404 error &lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;For rule based url rewrite provider with configured mobile rule (as suffix rule) &lt;br /&gt;&lt;ul&gt;&lt;li&gt;/Articles/Website-Launch is translated to /Templates/Articles/News.aspx?id=1234 &lt;/li&gt;&lt;li&gt;/Articles/Website-Launch/&lt;b&gt;Mobile &lt;/b&gt;is translated to /&lt;b&gt;Mobile&lt;/b&gt;/Templates/Articles/News.aspx?id=123&amp;amp;Rule=”Mobile” &lt;/li&gt;&lt;li&gt;/Articles/Website-Launch/&lt;b&gt;Lite &lt;/b&gt;is translated to /&lt;b&gt;Lite&lt;/b&gt;/Templates/Articles/News.aspx?id=123&amp;amp;Rule=”Lite” (e.g. Lite/Full website version like MSDN) &lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Additionaly further template selection can be made based on User Agent (sent by browser), so for example IPhone users can be served a different version then other mobile devices, which may have low resolution displays. &lt;br /&gt;&lt;br /&gt;Note: Url suffix (“Mobile”) and path for templates (“/Mobile/Templates/”) are examples and can be configured in web.config &lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://lh5.googleusercontent.com/-N7-P0n78T_M/TXC3mmn-OrI/AAAAAAAAAgI/wWHre2cFqxU/s1600/template_matching.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://lh5.googleusercontent.com/-N7-P0n78T_M/TXC3mmn-OrI/AAAAAAAAAgI/wWHre2cFqxU/s1600/template_matching.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You can check how it works in production at Making Waves’ website. Additionaly if you visit this website from mobile device you will be automatically redirected to mobile version. &lt;br /&gt;&lt;ul&gt;&lt;li&gt; &lt;a href=&quot;http://makingwaves.no/&quot;&gt;http://makingwaves.no&lt;/a&gt; – regular website version &lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.blogger.com/%20http://m.makingwaves.no&quot;&gt; http://m.makingwaves.no&lt;/a&gt; - mobile version using same page data as source for a template &lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Rule selection&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;When client tries to access any Url rule based rewriter, selects rule which will perform further processing. All rules are probed for matching and first, which accepts url, is responsible for template selection. &lt;br /&gt;&lt;br /&gt;In an example below, third rule matches url and then selects the fourth template. After page is rendered, the rule is also responsible for transforming non-friendly urls into corresponding friendly urls for this rule from page markup. &lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://lh3.googleusercontent.com/-fLpZ0UUSyzU/TXC4tAHC3KI/AAAAAAAAAgM/wxwJAwTwEYY/s1600/rule_selection.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://lh3.googleusercontent.com/-fLpZ0UUSyzU/TXC4tAHC3KI/AAAAAAAAAgM/wxwJAwTwEYY/s1600/rule_selection.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;b&gt;Features&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Configurable in web.config and programmatically &lt;/li&gt;&lt;li&gt;Extensible rule selection engine &lt;/li&gt;&lt;li&gt;Translates urls in rendered page using rule choosen to select template &lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;b&gt;Supported rules&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://agentbasedsubdomainmatchingurlrewriterule/&quot;&gt;AgentBasedSubDomainMatchingUrlRewriteRule&lt;/a&gt; - Uses sub domain to match rule.&amp;nbsp; &lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://www.coderesort.com/p/epicode/wiki/MakingWaves.MobileUrlRewriter/SuffixMatchingUrlRewriteRule&quot;&gt;SuffixMatchingUrlRewriteRule&lt;/a&gt; - Uses suffix to match rule. &lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://www.coderesort.com/p/epicode/wiki/MakingWaves.MobileUrlRewriter/AgentBasedSuffixMatchingUrlRewriteRule&quot;&gt;AgentBasedSuffixMatchingUrlRewriteRule&lt;/a&gt; - Works like suffix rule but additionaly template selection can be performed based on User Agent sent by browser. &lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://prefixmatchingurlrewriterule/&quot;&gt;PrefixMatchingUrlRewriteRule&lt;/a&gt; - Uses prefix to match rule.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;b&gt;Download&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;Visit &lt;a href=&quot;https://www.coderesort.com/p/epicode/wiki/MakingWaves.MobileUrlRewriter#Download&quot;&gt;dowload section&lt;/a&gt; at Module&#39;s &lt;a href=&quot;https://www.coderesort.com/p/epicode/wiki/MakingWaves.MobileUrlRewriter&quot;&gt;page&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;b&gt;Sample Configuration&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In web.config &lt;br /&gt;&lt;pre class=&quot;language-xml&quot;&gt;&lt;code&gt;&amp;nbsp;&amp;lt;configSections&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;section name=&quot;makingWaves.urlRewrite&quot; type=&quot;MakingWaves.Common.EPiServer.UrlRewriting.Configuration.UrlRewriteSection, MakingWaves.Common.EPiServer.UrlRewriting&quot;/&amp;gt;&lt;br /&gt;&amp;nbsp; ...&lt;br /&gt;&amp;lt;/configSections&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;makingWaves.urlRewrite&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;rules&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;add name=&quot;MobileRule&quot;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; type=&quot;MakingWaves.Common.EPiServer.UrlRewriting.AgentBasedSuffixMatchingUrlRewriteRule, MakingWaves.Common.EPiServer.UrlRewriting&quot;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; rootPath=&quot;MobilePath/Regular&quot;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; urlSuffix=&quot;Mobile&quot;&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;ruleProperties&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;add propertyType=&quot;agent&quot; agentPattern=&quot;.*Android.*&quot; pathSuffix=&quot;MobilePath/Android&quot;/&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;add propertyType=&quot;agent&quot; agentPattern=&quot;.*IPhone.*&quot; pathSuffix=&quot;MobilePath/IPhone&quot;/&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/ruleProperties&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/add&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;/rules&amp;gt;&lt;br /&gt;&amp;lt;/makingWaves.urlRewrite&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In episerver.config &lt;br /&gt;&lt;pre class=&quot;language-xml&quot;&gt;&lt;code&gt;&amp;lt;episerver&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;urlRewrite&lt;br /&gt;&amp;nbsp; defaultProvider=&quot;RuleBasedUrlRewriteProvider&quot;&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;providers&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;add name=&quot;RuleBasedUrlRewriteProvider&quot;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; description=&quot;My provider supporting multiple templates&quot;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; type=&quot;MakingWaves.Common.EPiServer.UrlRewriting.RuleBasedUrlRewriteProvider,MakingWaves.Common.EPiServer.UrlRewriting&quot;/&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ...&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/providers&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;/urlRewrite&amp;gt;&lt;br /&gt;&amp;lt;/episerver&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Additionally, if you want a mobile client to be redirected to a proper version of a page consider using the following snippet using extension method GetLinkUrlByRule: &lt;br /&gt;&lt;pre class=&quot;language-xml&quot;&gt;&lt;code&gt;if (HttpContext.Current.Request.Browser.IsMobileDevice)&lt;br /&gt;{&lt;br /&gt;    this.Response.Redirect(CurrentPage.GetLinkUrlByRule(&quot;MobileRule&quot;));&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Contributed by&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Andrzej Zapotoczny (andrzej.zapotoczny _mail_at_ makingwaves.pl)&lt;/li&gt;&lt;li&gt;Mirosław Jedynak (miroslaw.jedynak _mail_at_ makingwaves.pl)&lt;/li&gt;&lt;li&gt;Krzysztof Danielewisz (krzysztof.danielewicz_mail_at_makingwaves.pl)&amp;nbsp;&lt;/li&gt;&lt;/ul&gt;from Making Waves ( &lt;a href=&quot;http://www.makingwaves.com/&quot;&gt;http://www.makingwaves.com&lt;/a&gt;)</id><updated>2011-03-04T11:05:00.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Writing custom properties: #3 Edit control</title><link href="http://blog.m.jedynak.pl/2011/02/writing-custom-properties-3-edit.html" /><id>In this post I will present how to create initial version of edit control for Guid property, which was introduced in previous posts. &lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://blog.m.jedynak.pl/2011/02/writing-custom-properties-1-custom.html&quot;&gt;Writing custom properties: #1 Custom value type&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://blog.m.jedynak.pl/2011/02/writing-custom-properties-2-default.html&quot;&gt;Writing custom properties: #2 Default value&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Writing custom properties: #3 Edit control&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Features&lt;/span&gt;&lt;/b&gt; &lt;br /&gt;Created control will have:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Text input for Guid &lt;/li&gt;&lt;li&gt;Button for creating new Guid&lt;/li&gt;&lt;/ul&gt;This post is first step in more complex implementation which will come with AJAX functionality and On-Page-Edit support.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Controls render types&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;EPiServer properties can be rendered in one of the following modes (defined by &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;&quot;&gt;EPiServer.Core.RenderType&lt;/span&gt;): &lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Default&lt;/b&gt; – when viewing property in View Mode. It’s used e.g. when you display property using &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;&quot;&gt;&lt;episerver:property propertyname=&quot;”..”/&quot;&gt;&lt;/episerver:property&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;&quot;&gt;&amp;lt;episerver:property PropertyName=”..”/&amp;gt;&lt;/span&gt; . In this mode &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;&quot;&gt;CreateDefaultControls&lt;/span&gt; method is invoked.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Edit &lt;/b&gt;– when editing page in Edit Mode or in Quick Edit Mode. In this mode &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;&quot;&gt;CreateEditControls&lt;/span&gt; method is invoked.&lt;/li&gt;&lt;li&gt;&lt;b&gt;OnPageEdit&lt;/b&gt; – if &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;&quot;&gt;PropertyDataControl.SupportsOnPageEdit&lt;/span&gt; returns true and &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;&quot;&gt;&amp;lt;episerver:property PropertyName=”..”/&amp;gt; &lt;/span&gt;is used&amp;nbsp; property is rendered in this mode. Otherwise uses default view. These mode will be covered in more details soon.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Basic server control implementation&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;All controls for editing custom properties in EPiServer must inherit from &lt;b style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;PropertyDataControl &lt;/b&gt;or derived class.&lt;br /&gt;&lt;br /&gt;In simplest scenario when supporting only edit mode functionally &lt;b style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;CreateEditControls &lt;/b&gt;must create controls which are used in edit mode. Edited values should be saved in &lt;b style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;ApplyEditChanges &lt;/b&gt;method.&lt;br /&gt;Additionaly &lt;b style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;SetupEditControls &lt;/b&gt;updates visual representation value based on data from &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;&quot;&gt;PropertyData &lt;/span&gt;&lt;br /&gt;&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;public class GuidPropertyControl : PropertyDataControl&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; protected TextBox EditBox { get; set; }&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public GuidProperty GuidProperty&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; get { return (GuidProperty)this.PropertyData; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public override void CreateEditControls()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //create text box&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.EditBox = new TextBox { MaxLength = 0xff };&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.ApplyControlAttributes(this.EditBox);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.Controls.Add(this.EditBox);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //button for generating new guid&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //consider using LanguageManager for texts&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var button = new Button { Text = &quot;New&quot; };&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.ApplyControlAttributes(button);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; button.Click +=&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; (sender, e) =&amp;gt; { this.EditBox.Text = FormatGuid(Guid.NewGuid()); };&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.Controls.Add(button);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.SetupEditControls();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private static string FormatGuid(Guid guid)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return guid.ToString();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; //Saves value in underlying PropertyData &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public override void ApplyEditChanges()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Guid value;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (string.IsNullOrEmpty(this.EditBox.Text))&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; value = Guid.Empty;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; else&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; try&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; value = new Guid(this.EditBox.Text);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; catch (FormatException e)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.AddErrorValidator(e.Message);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.SetValue(value);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; protected override void SetupEditControls()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.EditBox.Text = FormatGuid(this.GuidProperty.Guid);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; //representation in View Mode&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public override&amp;nbsp; void CreateDefaultControls()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Label target = new Label();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; target.Text = FormatGuid(GuidProperty.Guid);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.CopyWebAttributes(target);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.Controls.Add(target);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Post back support&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;If you would try to click “New button” in edit mode you would notice strange behavior: Message box warning about leaving page and loosing unsaved value.&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-5CBKWmCw900/TWLXPj70M4I/AAAAAAAAAf8/7tn3MZtosE0/s1600/page_leave_check.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://2.bp.blogspot.com/-5CBKWmCw900/TWLXPj70M4I/AAAAAAAAAf8/7tn3MZtosE0/s1600/page_leave_check.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The reason for this is that Javascipt &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;&quot;&gt;OnBeforeUnload &lt;/span&gt;event is raised and EPiServer warns you that pages is going to be left with possible data loss.&lt;br /&gt;There are two solutions for this:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Use &lt;b style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;ToolButton &lt;/b&gt;from EPiServer namespace instead of regular ASP &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;&quot;&gt;Button &lt;/span&gt;and set &lt;b style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;DisablePageLeaveCheck &lt;/b&gt;to &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;&quot;&gt;true&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;public override void CreateEditControls()&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; //same code creating TextBox&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; var button = new ToolButton&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Text = &quot;New&quot;, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; DisablePageLeaveCheck = true&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; };&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; //same code using button&lt;br /&gt;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; SetupEditControls()&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Use &lt;b style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;ScriptDisablePageLeaveEvent &lt;/b&gt;to disable checking specific event raised from our control. This approach is more flexible because not only button is supported and it’s possible to specify which event should suppress checking.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;public override void CreateEditControls()&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; //same code creating TextBox&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; //same code creating Button&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ScriptDisablePageLeaveEvent scriptDisablePageLeaveEvent =&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; new ScriptDisablePageLeaveEvent&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; EventTarget = button,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; EventType = EventType.Click&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; };&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.Controls.Add(scriptDisablePageLeaveEvent);&lt;br /&gt;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; SetupEditControls()&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Page leave check considerations&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;You may wonder how it happed that without writing any code EPiServer can discover that value of Guid property has changed and warn about it. In fact EPiServer PageLeaveCheck attach to each html’s input event onchange and whenever this event is raise IsPageChanged is set to true. No magic!&lt;br /&gt;&lt;br /&gt;This approach is working really well in most scenarios, since it’s common to store value in text boxes (sometimes in read-only mode like for Page Reference property). However, if you go into scenario where values are stored only in hidden field and displayed to user directly (without textbox) you will notice that Page Leave Check does not work anymore.&lt;br /&gt;&lt;br /&gt;In that case you may manually mark page as changed using following Javascript&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;savePropetyValue: function (value) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; //change hidden field value&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; $(&quot;#hidden_field&quot;).val(&quot;...&quot;) ;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; //mark page as changed&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (EPi.PageLeaveCheck.enabled) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; EPi.PageLeaveCheck.SetPageChanged(true);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;};&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Please be patient: more advanced Javascript usage in custom controls will be covered in future posts. It will include using JQuery, packaging javacripts, AJAX support, etc.</id><updated>2011-02-21T22:24:00.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Writing custom properties: #2 Default value</title><link href="http://blog.m.jedynak.pl/2011/02/writing-custom-properties-2-default.html" /><id>In previous post I presented how to create simple property returning Guid values. In this post I will briefly describe how to deal with default values for custom properties. &lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;http://blog.m.jedynak.pl/2011/02/writing-custom-properties-1-custom.html&quot;&gt;Writing custom properties: #1 Custom value type&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Writing custom properties: #2 Default value&amp;nbsp;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://blog.m.jedynak.pl/2011/02/writing-custom-properties-3-edit.html&quot;&gt;Writing custom properties: #3 Edit control&lt;/a&gt; &lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Admin UI based approach&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;The easiest way is to use admin UI and set default values for properties using three available modes: &lt;br /&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-TPsByZpLxVY/TVhOALkFC0I/AAAAAAAAAfk/mYcwf9VUMRo/s1600/property_default_value.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://1.bp.blogspot.com/-TPsByZpLxVY/TVhOALkFC0I/AAAAAAAAAfk/mYcwf9VUMRo/s1600/property_default_value.png&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Unfortunately this approach has several drawbacks:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Error-prone: &lt;i&gt;It’s possible that for some reason administrator will not set this value. Application logic may not be prepared for this case.&lt;/i&gt;&lt;/li&gt;&lt;li&gt;Default value is applied only when creating page:&amp;nbsp;&lt;i&gt; If you add new property to page type, value will not be updated for empty properties.&lt;/i&gt;&lt;/li&gt;&lt;li&gt;Editor can remove default value&lt;i&gt; so property will fall back to empty/null value&lt;/i&gt;&lt;/li&gt;&lt;li&gt;String representation:&lt;i&gt; It may be not easy/possible to specify string representation&lt;/i&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;In my opinion this value should be used as suggestion for editor, not as way to enforce data correctness.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Ensuring default value in custom property&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;Second approach for defining default value is setting it inside custom property.&lt;br /&gt;&lt;br /&gt;There is method &lt;b style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;PropertyData.SetDefaultValue()&lt;/b&gt;, which is called when property is created (even if is null) or when cleared.&lt;br /&gt;&lt;br /&gt;Together with &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;SetDefaultValue&lt;/span&gt;, you will usually need implement &lt;b style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;IsNull &lt;/b&gt;property returning value indicating if current property value is equal to it&#39;s default.&lt;br /&gt;&lt;br /&gt;Sample implementation for GuidPropety may be following:&lt;br /&gt;&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;[PageDefinitionTypePlugIn]&lt;br /&gt;public class GuidProperty : PropertyString&lt;br /&gt;{ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // for rest of code check previous post&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; //.....&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; protected override void SetDefaultValue()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; base.SetDefaultValue();&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.value = Guid.Empty;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //or set custom default value – default product code in store etc.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //this.value = new Guid(“12345678-1234-1234-1234-123456789012”);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public override bool IsNull&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; get&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return this.value == Guid.Empty;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //return this.value == new Guid(“12345678-1234-1234-1234-123456789012”);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Some readers may ask why setting guid field to Guid.Empty is necessary, when Sytem.Guid is value type and it’s default value is Guid.Empty. Answer is that SetDefaultValue is called when property is cleared with PropertyData.Clear() so reseting to default value is necessary.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Usage&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;For newly created page or property added to exiting page&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;var value = CurrentPage[&quot;Guid&quot;]; // “00000000-0000-0000-0000-000000000000”&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // or e.g “12345678-1234-1234-1234-123456789012”&lt;br /&gt;&lt;br /&gt;var isNull = CurrentPage.Property[&quot;Guid&quot;].IsNull; // returns true&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Collection based custom properties &lt;/span&gt;&lt;/b&gt;&lt;br /&gt;For collection types Microsoft design guidelines state:&lt;br /&gt;&lt;blockquote&gt;&lt;i&gt;Array (and collection) properties should never return a null reference. Null can be difficult to understand in this context.&lt;/i&gt;&lt;/blockquote&gt;&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/k2604h5s.aspx&quot;&gt;http://msdn.microsoft.com/en-us/library/k2604h5s.aspx&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;To follow this guideline using SetDefaultValue is invaluable. Having custom property GuidCollectionProperty it can be implemented like below:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;[PageDefinitionTypePlugIn] &lt;br /&gt;public class GuidCollectionProperty : PropertyString&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // for rest of code check previous post&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; //.....&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; protected override void SetDefaultValue()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; base.SetDefaultValue();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.value = new List&amp;lt;Guid&amp;gt;();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public override bool IsNull&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; get&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return this.value == null || this.value.Count == 0;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Note: Admin default value override &lt;/span&gt;&lt;/b&gt;&lt;br /&gt;It’s still possible to set default value using admin UI to override default value set by property creator. Good thing is that default value format will be verified, so it is not allowed to set “abc” as default value for GuidProperty.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;b&gt;Note: Virtual call in constructor&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;Current implementation of PropertyData base class calls virtual method SetDefaultValue() in constructor. This is discouraged because calling virtual method in base class can cause accessing uninitialized values in derived class, since derived constructor would not be invoked by that time.&lt;br /&gt;&lt;blockquote&gt;&lt;i&gt;Do not call virtual members from constructors. Calling virtual methods during construction will cause the most derived override to be called, even though the most derived constructor has not been fully run yet&lt;/i&gt;&lt;/blockquote&gt;&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/ms182331%28v=vs.80%29.aspx&quot;&gt;http://msdn.microsoft.com/en-us/library/ms182331(v=vs.80).aspx&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;http://blogs.msdn.com/b/brada/archive/2004/08/12/213951.aspx&quot;&gt;http://blogs.msdn.com/b/brada/archive/2004/08/12/213951.aspx&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;What does it mean for us? In order to preserve backward compatibility this behavior, I guess, won’t be fixed soon. Therefore we should be aware what we use in SetDafaultValue() and check if it has been initialized in constructor before accessing value.</id><updated>2011-02-13T22:49:00.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Writing custom properties: #1 Custom value type</title><link href="http://blog.m.jedynak.pl/2011/02/writing-custom-properties-1-custom.html" /><id>This is first post from series showing how to implement custom property in EPiServer in &quot;proper&quot; way without unnecessary hacking.&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Writing custom properties: #1 Custom value type&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://blog.m.jedynak.pl/2011/02/writing-custom-properties-2-default.html&quot;&gt;Writing custom properties: #2 Default value&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://blog.m.jedynak.pl/2011/02/writing-custom-properties-3-edit.html&quot;&gt;Writing custom properties: #3 Edit control&lt;/a&gt; &lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Introduction&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;In EPiServer all custom properties must inherit from abstract base class &lt;b&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,&amp;quot;Courier&amp;quot;,monospace;&quot;&gt;PropertyData&lt;/span&gt;&lt;/b&gt;.&amp;nbsp; It’s value can be stored using one of following underlying types:&lt;br /&gt;•&amp;nbsp;&amp;nbsp;&amp;nbsp; Boolean&lt;br /&gt;•&amp;nbsp;&amp;nbsp;&amp;nbsp; Category&lt;br /&gt;•&amp;nbsp;&amp;nbsp;&amp;nbsp; Date&lt;br /&gt;•&amp;nbsp;&amp;nbsp;&amp;nbsp; FloatNumber&lt;br /&gt;•&amp;nbsp;&amp;nbsp;&amp;nbsp; LinkCollection &lt;br /&gt;•&amp;nbsp;&amp;nbsp;&amp;nbsp; LongString&lt;br /&gt;•&amp;nbsp;&amp;nbsp;&amp;nbsp; Number&lt;br /&gt;•&amp;nbsp;&amp;nbsp;&amp;nbsp; PageReference &lt;br /&gt;•&amp;nbsp;&amp;nbsp;&amp;nbsp; PageType&lt;br /&gt;•&amp;nbsp;&amp;nbsp;&amp;nbsp; String&lt;br /&gt;&lt;br /&gt;Those types are defined in enumeration &lt;b&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,&amp;quot;Courier&amp;quot;,monospace;&quot;&gt;EPiServer.Core.PropertyDataType&lt;/span&gt;&lt;/b&gt; and when creating custom property you have to decide which storage type is closest to your requirements. From my experience you will usually use number or variations of string storage. The easiest way to start is to use one of default property type defined in EPiServer as your base class. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Guid Property&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;In this tutorial series I will show how to create complete custom property used for storing and editing Guid value. Using Guid as example will be easy to understand but still possible to show many features available for custom properties.&lt;br /&gt;&lt;br /&gt;As usage example you may consider integrating with external system where product identifiers are stored as Guids and editor is responsible for providing them to our CMS. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Analysis&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Guid are easily stored in string using different formats (the most popular is “&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,&amp;quot;Courier&amp;quot;,monospace;&quot;&gt;{96C7DFDF-668C-4A71-AA79-1E8898B1A0E4}&lt;/span&gt;”), therefore as base type I will use PropertyString – originally used for storing up to 255 characters.&lt;br /&gt;&lt;br /&gt;If we would leave property unchanged, editor could easily mistype value, which may cause system failure when application will be parsing invalid string. Creating custom property can prevent human error.&lt;br /&gt;&lt;br /&gt;It’s also crucial to return proper object type, so developer can avoid parsing and, what is even worse, invalid format error handling in every place value is used.&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;//bad – requires parsing and error handling&lt;br /&gt;Guid value=new Guid(CurrentPage[“GuidProperty”].Value); &lt;br /&gt;&lt;br /&gt;//good – returned value is System.Guid&lt;br /&gt;Guid value= (Guid) CurrentPage[“GuidProperty”].Value; &lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Implementation&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;[PageDefinitionTypePlugIn]&lt;br /&gt;public class GuidProperty : PropertyString&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private Guid value;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public override Type PropertyValueType&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; get { return typeof(Guid); }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public override object Value&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; get { return this.value; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; set&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.SetPropertyValue(value, delegate&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //currenty we don&#39;t have custom editor control for guid, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //therefore if standard string control value sets value from editor&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //we try to parse it. Throwing exception in this place will show nice&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //message that provided value &quot;is not valid value for property &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //&#39;YourPropertyName&#39;&quot;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.value = value is string? new Guid((string)value) : (Guid)value;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (Equals(value, Guid.Empty))&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.Clear();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; else&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.Modified();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; });&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public override void LoadData(object newValue)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.Value = this.DeserializeValue(newValue as string);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public override object SaveData(PropertyDataCollection properties)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return this.SerializeValue(this.value);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; protected string SerializeValue(Guid value)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return value.ToString();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; protected Guid DeserializeValue(string value)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (string.IsNullOrEmpty(value))&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return Guid.Empty;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return new Guid(value);&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&amp;nbsp;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;b&gt;Usage&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;var value = CurrentPage[&quot;Guid&quot;]; // e.g. c75dfcdb-258c-47a0-a2ea-81f0b92341e4&lt;br /&gt;var type = CurrentPage[&quot;Guid&quot;].GetType(); //System.Guid (not System.String!)&lt;/code&gt;&lt;/pre&gt;</id><updated>2011-02-07T10:02:00.0000000Z</updated><summary type="html">Blog post</summary></entry></feed>