Extend the Sitecore FieldRenderer

The Sitecore FieldRenderer is the render controls used to render fields from Sitecore in a way that makes them page editable from the Page Editor (or Experience Editor as it is called in Sitecore 8).

The FieldRenderer has been known since Sitecore 5, and is still the preferred method of rendering fields when using User Controls (Sublayouts):

<%@ Register TagPrefix="sc" Namespace="Sitecore.Web.UI.WebControls" Assembly="Sitecore.Kernel" %>

<sc:FieldRenderer runat="server" FieldName="MyField" />
<sc:Text ID="txtText" runat="server" Field="FlowProfileEulaAndTermsSubTitle" Item="<%# this.DataSource %>"/>

The examples above shows how to use the FieldRenderer from User Controls. The sc:FieldRenderer is the base class, and the sc:Text is a text specific renderer inheriting from the FieldRenderer.

This is an example of an extended FieldRenderer I have been using for the last couple of years. The extension is used to render simple text fields such as headers, text etc. To make this easier we have added a few properties to our FieldRenderer such as:

To create a new FieldRenderer you need to inherit from Sitecore.Web.UI.WebControls.FieldControl.
The important method is protected override void DoRender(HtmlTextWriter output). Inside this method you instantiate your own FieldRenderer control, and voila, your control is Page Editable.

Here is the structure in pseudocode:

using System;
using System.ComponentModel;
using System.Web.UI;
using Sitecore.Collections;
using Sitecore.Data.Items;
using Sitecore.Diagnostics;
using Sitecore.Web;
using Sitecore.Web.UI.WebControls;
using Sitecore.Xml.Xsl;

namespace MyFieldRendererControls
{
  [ParseChildren(false)]
  [PersistChildren(true)]
  public class FieldRendererExt : FieldControl
  {
 
    protected override void DoRender(HtmlTextWriter output)
    {
      string renderValue = "";
      string renderFirstPart = "";
      string renderLastPart = "";
      var fr = new FieldRenderer
        {
		  ...
		  ...
        };

      RenderFieldResult rendered = fr.RenderField();
      renderFirstPart = rendered.FirstPart;
      renderLastPart = rendered.LastPart;
      renderValue = rendered.ToString();


      output.Write(renderFirstPart);
      RenderChildren(output);
      output.Write(renderLastPart);
    }
  }
}

And here is the complete code for the enhanced FieldRenderer:

using System;
using System.ComponentModel;
using System.Web.UI;
using Sitecore.Collections;
using Sitecore.Data.Items;
using Sitecore.Diagnostics;
using Sitecore.Web;
using Sitecore.Web.UI.WebControls;
using Sitecore.Xml.Xsl;

namespace MyFieldRendererControls
{
  [ParseChildren(false)]
  [PersistChildren(true)]
  public class TextExt : FieldControl
  {
    private string after = string.Empty;
    private string before = string.Empty;
    private string cssClass = string.Empty;
    private string cssId = string.Empty;
    private string cssStyle = string.Empty;
    private string enclosingTag = string.Empty;
    private string fieldName = string.Empty;

    [Category("Method"), Description("Always output enclosing tag regardless of it being empty or not")]
    public bool AlwaysEnclosingTag
    { get; set; }

    [Category("Method"), Description("HTML tag to wrap the field value with")]
    public string EnclosingTag
    {
      get { return enclosingTag; }
      set { enclosingTag = value; }
    }

    [Category("Method"), Description("CSS class-attribute on enclosing tag")]
    public new string CssClass
    {
      get { return cssClass; }
      set { cssClass = value; }
    }

    [Category("Method"), Description("CSS style-attribute on enclosing tag")]
    public new string CssStyle
    {
      get { return cssStyle; }
      set { cssStyle = value; }
    }

    [Category("Method"), Description("CSS id-attribute on enclosing tag - will be overridden if control ClientIDMode == Static")]
    public string CssId
    {
      get { return cssId; }
      set { cssId = value; }
    }

    [Category("Method"), Description("FieldName to be rendered from datasource")]
    public string FieldName
    {
      get { return fieldName; }
      set { fieldName = value; }
    }

    [Category("Method"), Description("Disables the page editor for the control")]
    public new bool DisableWebEditing
    { get; set; }

    [Category("Method"), Description("Put some text before")]
    public string Before
    {
      get { return before; }
      set { before = value; }
    }

    [Category("Method"), Description("Put some text after")]
    public string After
    {
      get { return after; }
      set { after = value; }
    }

    [Category("Method"), Description("Set explicit what item to process")]
    public new Item Item
    { get; set; }

    protected override void DoRender(HtmlTextWriter output)
    {
      if (string.IsNullOrEmpty(Field))
      {
        Field = FieldName;
      }

      // GET ITEM
      Item currentContextItem = null;
      try
      {
        currentContextItem = GetItem();
      }
      catch (Exception ex)
      {
        Log.Error("currentContextItem exception", ex, this);
      }

      // RENDER ITEM VALUE
      bool itemValid;
      try
      {
        itemValid = (currentContextItem != null && currentContextItem.Fields[Field] != null);
      }
      catch (Exception)
      {
        itemValid = false;
      }

      string renderValue = "";
      string renderFirstPart = "";
      string renderLastPart = "";
      if (itemValid)
      {
        var fr = new FieldRenderer
        {
          Before = Before,
          After = After,
          DisableWebEditing = DisableWebEditing,
          EnclosingTag = "",
          Item = currentContextItem,
          FieldName = Field,
          Parameters = WebUtil.BuildQueryString(GetParameters(), false)
        };

        RenderFieldResult rendered = fr.RenderField();
        renderFirstPart = rendered.FirstPart;
        renderLastPart = rendered.LastPart;
        renderValue = rendered.ToString();
      }


      // OUTPUT DATA
      if (string.IsNullOrEmpty(EnclosingTag) || (string.IsNullOrEmpty(renderValue) && (!AlwaysEnclosingTag)))
      {
        // Simple value...
        output.Write(renderFirstPart);
        RenderChildren(output);
        output.Write(renderLastPart);
      }
      else
      {
        // Otherwise...
        string attributes = "";

        if (ClientIDMode == ClientIDMode.Static)
        {
          attributes += " id='" + ID + "'";
        }
        else if (!string.IsNullOrEmpty(CssId))
        {
          attributes += " id='" + CssId + "'";
        }

        if (!string.IsNullOrEmpty(CssClass))
        {
          attributes += " class='" + CssClass + "'";
        }

        if (!string.IsNullOrEmpty(CssStyle))
        {
          attributes += " style='" + CssStyle + "'";
        }

        // Wrap it in enclosing tag and attributes
        output.Write("<" + EnclosingTag + attributes + ">");
        output.Write(renderFirstPart);
        RenderChildren(output);
        output.Write(renderLastPart);
        output.Write("</" + EnclosingTag + ">");
      }
    }

    protected override Item GetItem()
    {
      var datasource = GetDatasource();
      if (datasource != null)
      {
        return datasource;
      }

      return Item ?? base.GetItem();
    }

    protected SafeDictionary<string> GetParameters()
    {
      var parameters = new SafeDictionary<string>();

      if (Controls.Count > 0)
      {
        parameters.Add("haschildren", "true");
      }

      foreach (string key in Attributes.Keys)
      {
        string str = Attributes[key];
        parameters.Add(key, str);
      }

      return parameters;
    }

    private Item GetDatasource()
    {
      var layout = GetParent(this);

      if (layout == null)
      {
        return null;
      }

      return string.IsNullOrEmpty(layout.DataSource) ? null : Sitecore.Context.Database.GetItem(layout.DataSource);
    }

    private Sublayout GetParent(Control control)
    {
      if (control.Parent == null)
      {
        return null;
      }

      var sublayout = control.Parent as Sublayout;
      return sublayout ?? GetParent(control.Parent);
    }

  }
}

To use the new control:

<%@ Register tagPrefix="EXT" namespace="MyFieldRendererControls" assembly="MyFieldRendererControls" %>

<EXT:TextExt FieldName="NameOfField" ID="fldTitle" runat="server" EnclosingTag="h1" CssClass="class" CssStyle="color:red" />

Several of my colleagues has worked on this extension, and I would like to thank them all.

 

Advertisements

About briancaos

Developer at Pentia A/S since 2003. Have developed Web Applications using Sitecore Since Sitecore 4.1.
This entry was posted in c#, Sitecore 5, Sitecore 6, Sitecore 7, Sitecore 8 and tagged , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s