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:
- The control automatically gets the Item from the DataSource of the control instead of getting it from Sitecore.Context.Item (which should be avoided).
This eliminates the need for specifying an Item datasource for every field rendered. - Enclosingtag property adds tags such as H1 or DIV tags around the text.
- Properties CssClass and CssStyle adds class and style tags to the Enclosing tag.
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.
