Five New Optimizely Certifications are Here! Validate your expertise and advance your career with our latest certification exams. Click here to find out more

Linus Ekström
Oct 24, 2012
  11295
(0 votes)

Custom renderers for properties

In my previous blog post about updates to typed models in EPiServer 7 I mentioned that we have added the possibility to select renderer for properties, pretty much the same way as you can assign renderers for blocks and pages. Let’s look a bit more into how this works. We begin with defining a simple page type with a single property:

using System.ComponentModel.DataAnnotations;
using EPiServer.Core;
using EPiServer.DataAnnotations;
using EPiServer.Web;
 
namespace EPiServer.Templates.Alloy.Models.Pages
{
    [ContentType(GUID = "F8D47655-7B50-4319-8646-3369BA9AF05E")]
    public class MyPage : PageData
    {
        [UIHint("email")]
        public virtual string Email { get; set; }
    }
}

Let’s create a simple renderer for the property. We’ll start by creating a property that inherits from one of the built in Property Controls: PropertyStringControl.

using System.Web.UI.WebControls;
using EPiServer.Framework.DataAnnotations;
using EPiServer.Web.PropertyControls;
using EPiServer.Web;
 
[TemplateDescriptor(TagString = "email")]
public class EmailPropertyControl : PropertyStringControl, IRenderTemplate<string>
{
    public override void CreateDefaultControls()
    {
        var link = new HyperLink();
        link.Text = PropertyData.Value.ToString();
        link.NavigateUrl = "mailto:" + PropertyData.Value.ToString();
        Controls.Add(link);
    }
}

This class is very similar to what you would do in EPiServer CMS 5 and 6. There are two differences though. The first is that it implements the IRenderTemplate<T> interface. The second is the TemplateDescriptor attribute. This tells the system that this editor is preferred when rendering a model property with a UIHint attribute that matches the TemplateDescriptor Tag/TagString properties(Tag and TagString are basically the same property but with different types. Tags is defined as a string array which is not possible if you have an CLS-compliant project).

In our page template we add a standard EPiServer property web control to display the property:

<EPiServer:Property PropertyName="Email" runat="server" />

When viewing a page of this type we get a simple a tag with a mailto-link:

SimpleProperty

Defining tags in the template

In the first example we added a UIHint attribute to our model. But what if we want to display the model differently in different templates? This can be done by assigning a tag in the RenderSettings property of the EPiServer property web control. Let us assume that we are working for a fictitious client that imports bananas. Their web strategists have decided that they should have a lot of images of bananas on their web site and what better way to implement this than with the great dancing banana image. Lets add a tag to the property:

<EPiServer:Property PropertyName="Email" runat="server" />
    <RenderSettings Tag="emailgoesbananas" />
</EPiServer:Property>

And we’ll create a new renderer that will add a dancing banana next to the mail link:

 
using System.Web.UI.WebControls;
using EPiServer.Framework.DataAnnotations;
using EPiServer.Web.PropertyControls;
using EPiServer.Web;
 
[TemplateDescriptor(TagString = "emailgoesbananas")]
public class BananaEmailPropertyControl
     : PropertyStringControl, IRenderTemplate<string>
{
    public override void CreateDefaultControls()
    {
        var link = new HyperLink();
        link.Text = PropertyData.Value.ToString();
        link.NavigateUrl = "mailto:" + PropertyData.Value.ToString();
        Controls.Add(link);
 
        Controls.Add(new Image() 
        { ImageUrl = "http://www.sherv.net/cm/emo/funny/2/banana.gif" });
    }
}

DancingBananaScreenShot

And behold: We have a dancing banana!

Using a user control to render the property

Another new feature is the ability to define a user control to render your property. To do this you have to inherit from the generic class PropertyControlBase:

using EPiServer.Framework.DataAnnotations;
using EPiServer.Web;
 
namespace EPiServer.Templates.Alloy.Views.Pages.Partials
{
    [TemplateDescriptor(TagString = "bananasgoesbananas")]
    public partial class EvenMoreBananas : PropertyControlBase<string>
    {
    }
}

Let’s say the customer was thrilled with the dancing banana and just want more. To speed up the development we’ll add these to the user control instead:

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="EvenMoreBananas.ascx.cs"
    Inherits="EPiServer.Templates.Alloy.Views.Pages.Partials.EvenMoreBananas" %>
<asp:Panel runat="server" ID="BananaWrapper">
    <a href='mailto:<%=CurrentData %>'>
        <%
   1: =CurrentData 
%></a>
    <img src="http://www.sherv.net/cm/emo/funny/2/banana.gif" />
    <img src="http://www.sherv.net/cm/emo/funny/2/upside-down-banana-smiley-emoticon.gif" />
    <img src="http://www.sherv.net/cm/emo/funny/2/banana-with-bagpipes-smiley-emoticon.gif" />
    <img src="http://www.sherv.net/cm/emo/funny/2/woohoo-dancing-banana-smiley-emoticon.gif" />
</asp:Panel>

Note: CurrentData in this case is our model value typed as a string as defined in our inheritance declaration.

We change the tag in our page template to the one defined in the user control, bananasgoesbananas, and reloading the page gives us:

ManyDancingBananas

When clicking on the email text we still get the default editing (inline editing for strings). This is because the user control is wrapped in a generic property control that handles editing attributes so that you don’t have to care about this.

EditingEmailString

Sum up

With these additions working with complex models, like pages and blocks, and simple properties become pretty much the same. You can:

  • Register renderers for them using the TemplateDescriptor attribute.
  • Select renderer using the UIHint attribute..
  • …or by defining a tag in RenderSettings Property for the EPiServer property web control.

If no renderer is found given the specified tags PropertyControlClassFactory will fall back to the current behavior.

Oct 24, 2012

Comments

Please login to comment.
Latest blogs
Optimizely Configured Commerce and Spire CMS - Figuring out Handlers

I recently entered the world of Optimizely Configured Commerce and Spire CMS. Intriguing, interesting and challenging at the same time, especially...

Ritu Madan | Mar 12, 2025

Another console app for calling the Optimizely CMS REST API

Introducing a Spectre.Console.Cli app for exploring an Optimizely SaaS CMS instance and to source code control definitions.

Johan Kronberg | Mar 11, 2025 |

Extending UrlResolver to Generate Lowercase Links in Optimizely CMS 12

When working with Optimizely CMS 12, URL consistency is crucial for SEO and usability. By default, Optimizely does not enforce lowercase URLs, whic...

Santiago Morla | Mar 7, 2025 |

Optimizing Experiences with Optimizely: Custom Audience Criteria for Mobile Visitors

In today’s mobile-first world, delivering personalized experiences to visitors using mobile devices is crucial for maximizing engagement and...

Nenad Nicevski | Mar 5, 2025 |

Unable to view Optimizely Forms submissions when some values are too long

I discovered a form where the form submissions could not be viewed in the Optimizely UI, only downloaded. Learn how to fix the issue.

Tomas Hensrud Gulla | Mar 4, 2025 |

CMS 12 DXP Migrations - Time Zones

When it comes to migrating a project from CMS 11 and .NET Framework on the DXP to CMS 12 and .NET Core one thing you need to be aware of is the...

Scott Reed | Mar 4, 2025