Take the community feedback survey now.

Linus Ekström
Oct 24, 2012
  14865
(5 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

Björn Olsson
Björn Olsson Oct 24, 2012 10:32 AM

This looks very promising, it would be nice if it was possible to pass custom variables to the renderer using the RenderSettings (And UI hint perhaps). Let's say you would like to implement a "DateTime-renderer", with a customizable date-format, which would go something like this:





Or...





Etc..

You digg? :)

Linus Ekström
Linus Ekström Oct 24, 2012 01:23 PM

Björn: You can add any attribute to the RenderSettings property and you can access them in your property control like this:
var customVariable = RenderSettings["CustomVariable"];

This property is currently only accessible for if you create a class derived from PropertyData and not when creating a user control as a renderer.

Björn Olsson
Björn Olsson Oct 24, 2012 01:46 PM

Sweet, sounds perfect.

akeegan@adagetechnologies.com
akeegan@adagetechnologies.com Jan 24, 2014 03:22 AM

Hello, I am currently attempting something similar to Björn in that I would like to render a DateTime property using a specific format. Unfortunately, even when I create a control which inherits from PropertyDateControl and implements IRenderTemplate, it doesn't seem to do anything.

I've tagged the DateTime property via its RenderSettings, but I'm still not seeing any effect. Is there something I am doing wrong?

Here is my property code:

[TemplateDescriptor(Tags = new string[] { Constants.RenderingTagNames.DateTime })]
public class FormattedPropertyDateControl : PropertyDateControl, IRenderTemplate
{
public override void CreateDefaultControls()
{
Label lblDateTime = new Label();
lblDateTime.Text = Date.ToString(RenderSettings["DateFormat"].ToString());
Controls.Add(lblDateTime);
}
}

Linus Ekström
Linus Ekström Jan 29, 2014 11:16 AM

I tested your code and found out that the property data type in this case is defined as Nullable. Perhaps a bit confusing since I guess that the typed model uses DateTime but changing to IRenderTemplate> should make the control active.

Please login to comment.
Latest blogs
Dynamic CSP Management for Headless and Hybrid Optimizely CMS with Next.js

In the evolving realm of web security, Content Security Policy (CSP) is essential for defending against XSS and injection attacks. Traditional...

Minesh Shah (Netcel) | Sep 8, 2025

Create a Simple home page in Optimizely CMS

  Introduction In this blog post, I will walk you through a step by step process to create a very basic home page on a Optimizley CMS Empty site....

Ratish | Sep 7, 2025 |

AEO, GEO and SEO with Epicweb AI-Assistant in Optimizely

As search evolves beyond traditional SEO, businesses must adapt to Answer Engine Optimization (AEO) and Generative Engine Optimization (GEO). This...

Luc Gosso (MVP) | Sep 7, 2025 |

Meet the newest OMVPs – summer 2025 cohort

We’re excited to welcome the latest group of Optimizely Most Valuable Professionals (OMVPs) into the program! This summer’s cohort highlights a ble...

Satata Satez | Sep 5, 2025

The Sweet Spot: Hybrid Headless Architecture

When it comes to content management architecture, the pendulum often swings between tightly coupled “headed” CMS setups and the flexibility of full...

Minesh Shah (Netcel) | Sep 4, 2025

Preview Unpublished Pages and Blocks on the Frontend (Optimizely CMS 12)

Introduction In my previous post , I explained how to customize the ContentArea rendering pipeline in Optimizely CMS 12 so editors can see...

Adnan Zameer | Sep 4, 2025 |