I wanted to share some code I developed to enable a very flexible page design system using Sitecore and Reflection.
What this class does is associate a WebControl with a specific item template. I use this object heavily within columns which allow a variety of items to be rendered. If I have a new design element which I need to add to Sitecore, I first design and configure the element within Sitecore.
To render this new item all I need to do is implement a new version of my abstract class within the class ContentRenderHelper and publish a new version on my application DLL.
A few caveats with this system. First all exceptions during an item's rendering will be thrown at the line "thisType.InvokeMember" This can make it difficult to troubleshoot problems, so be sure to utilize Sitecore's logging and/or tracing functionality. However you can add stop points and step through all this code, so debugging in a development environment is easy. Second this code does not limit what items can be rendered where. There are two possible solutions for this. Either keep a list of items in Sitecore than be rendered where and reference this data within the parent class and/or use a TreeList and configure which items can be add to each list.
public class ContentRenderHelper : Sitecore.Web.UI.WebControl
{
/// <summary>
/// Stores the item to render
/// </summary>
private Sitecore.Data.Items.Item itemToRender;
/// <summary>
/// Creates a new content render helper
/// </summary>
/// <param name="itemToRender">Item that needs to be rendered</param>
public ContentRenderHelper(Sitecore.Data.Items.Item itemToRender)
{
this.itemToRender = itemToRender;
}
/// <summary>
/// Gets or sets Item that needs to be rendered
/// </summary>
public Sitecore.Data.Items.Item ItemToRender
{
get { return this.itemToRender; }
set { this.itemToRender = value; }
}
/// <summary>
/// Converts a string guid to a template id
/// </summary>
/// <param name="guid">string value of guid</param>
/// <returns>Template ID from guid</returns>
protected static Sitecore.Data.TemplateID GetTemplateID(string guid)
{
return new Sitecore.Data.TemplateID(new Sitecore.Data.ID(guid));
}
/// <summary>
/// Render the correct control for this item
/// </summary>
/// <param name="output">Current HtmlTextWriter object</param>
protected override void DoRender(HtmlTextWriter output)
{
// Go get all of the nested types of this object
Type[] typeArray = this.GetType().GetNestedTypes(BindingFlags.NonPublic | BindingFlags.Public);
foreach (Type thisType in typeArray)
{
// Make sure this type isn't null, is a class, and implements ContentWebControl
if (thisType != null && thisType.IsClass && thisType.BaseType.Name == "ContentWebControl")
{
// Invoke the object
object targetObject = Activator.CreateInstance(thisType, new object[] { this.itemToRender });
// Get its template ID
Sitecore.Data.TemplateID thisTemplateId = (Sitecore.Data.TemplateID)thisType.InvokeMember("TemplateId", BindingFlags.GetProperty, null, targetObject, null);
if (thisTemplateId == this.itemToRender.TemplateID)
{
// If this templateID matches render the control
thisType.InvokeMember("RenderControl", BindingFlags.Default | BindingFlags.InvokeMethod, null, targetObject, new object[] { output });
}
}
}
}
/// <summary>
/// This abstract class is to be implemented to be rendered by the parent class
/// </summary>
protected abstract class ContentWebControl : Sitecore.Web.UI.WebControl
{
/// <summary>
/// This is the item a base control will use to render
/// </summary>
private Sitecore.Data.Items.Item itemToRender;
/// <summary>
/// Creates new ContentWebControl
/// </summary>
/// <param name="itemToRender">The sitecore item to render</param>
protected ContentWebControl(Sitecore.Data.Items.Item itemToRender)
{
this.itemToRender = itemToRender;
}
/// <summary>
/// Gets or sets Sitcore item to render
/// </summary>
public Sitecore.Data.Items.Item ItemToRender
{
get { return this.itemToRender; }
set { this.itemToRender = value; }
}
/// <summary>
/// Gets the TemplateId this WebControl Renders
/// </summary>
public abstract Sitecore.Data.TemplateID TemplateId
{
get;
}
/// <summary>
/// Overrides this function to return itemToRender passed during constructor
/// </summary>
/// <returns>The item control needs to render</returns>
protected override Sitecore.Data.Items.Item GetItem()
{
return this.itemToRender;
}
}
/// <summary>
/// Renders rich text
/// </summary>
protected class RichText : ContentWebControl
{
/// <summary>
/// Implemented as required by abstract class
/// </summary>
/// <param name="itemToRender">The sitecore item to render</param>
public RichText(Sitecore.Data.Items.Item itemToRender) : base(itemToRender)
{
}
/// <summary>
/// Gets the template associated this control
/// </summary>
public sealed override Sitecore.Data.TemplateID TemplateId
{
}
/// <summary>
/// Render this control
/// </summary>
/// <param name="output">Current HtmlTextWriter object</param>
protected override void DoRender(HtmlTextWriter output)
{
output.Write(GetItem()["Copy"]);
}
}
}
get { return GetTemplateID("{49990698-20E5-4948-913A-4E643D4583B9}"); }