Take the community feedback survey now.

Linus Ekström
Oct 24, 2012
  11328
(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
A day in the life of an Optimizely OMVP - Opticon London 2025

This installment of a day in the life of an Optimizely OMVP gives an in-depth coverage of my trip down to London to attend Opticon London 2025 held...

Graham Carr | Oct 2, 2025

Optimizely Web Experimentation Using Real-Time Segments: A Step-by-Step Guide

  Introduction Personalization has become de facto standard for any digital channel to improve the user's engagement KPI’s.  Personalization uses...

Ratish | Oct 1, 2025 |

Trigger DXP Warmup Locally to Catch Bugs & Performance Issues Early

Here’s our documentation on warmup in DXP : 🔗 https://docs.developers.optimizely.com/digital-experience-platform/docs/warming-up-sites What I didn...

dada | Sep 29, 2025

Creating Opal Tools for Stott Robots Handler

This summer, the Netcel Development team and I took part in Optimizely’s Opal Hackathon. The challenge from Optimizely was to extend Opal’s abiliti...

Mark Stott | Sep 28, 2025

Integrating Commerce Search v3 (Vertex AI) with Optimizely Configured Commerce

Introduction This blog provides a technical guide for integrating Commerce Search v3, which leverages Google Cloud's Vertex AI Search, into an...

Vaibhav | Sep 27, 2025

A day in the life of an Optimizely MVP - Opti Graph Extensions add-on v1.0.0 released

I am pleased to announce that the official v1.0.0 of the Opti Graph Extensions add-on has now been released and is generally available. Refer to my...

Graham Carr | Sep 25, 2025