Creating Sitecore Sublayouts Dynamically

September 06, 2013

Preface

On a recent project I was looking to replace some existing infrastructure that built a sidebar on a page using a list of content items (non-page items) that were selected by the content editor. The existing system was using a single sublayout which had several templated server controls that defined the display for different types of content. This was a global resource and any individual site that wanted to modify the display would have to copy the file in it's entirety even if it only wanted to modify a single line. It also didn't provide a default display for items that weren't explicitly defined. Only predefined types were displayed so there was some confusion as to why some things wouldn't be displayed.

There's, of course, a lot of ways to do this, especially within Sitecore. My plan was to keep the sidebar sublayout as the parent display object but I wanted to be able to create individual sublayouts for each content type. Then I would add each to the parent sublayout. I didn't want to load the ascx files as user controls because I wanted to be able to control the settings such as datasource, parameters, caching etc. This lead me to adding Sitecore sublayout objects to the page dynamically. It also allowed me to follow certain conventions and build the sublayouts with respect to the datasource instead of the context item.

Now if a single site wanted to override how the contact information was displayed, it would only have to override that single sublayout and it wouldn't affect anything else. It also allowed me to remove a lot of duplication in the system.

Solution

In this case I had business logic that already determined which display objects were used for which content types, I modified it to replace the server control references with paths to the sublayout files and then set that path on the Sitecore sublayouts. Here I also set the datasource on the sublayout to the item ID of the content item, I pass in a parameter to let each sublayout know what it's sort order is and then (I don't but it's possible) set the cache settings as well. Here's the ascx method I use that creates the sublayout and attaches it to the page:

protected void AddFeature(Item i, string filePath) {
	Sitecore.Web.UI.WebControls.Sublayout s = new Sitecore.Web.UI.WebControls.Sublayout();
	s.Path = filePath;
	s.DataSource = i.ID.ToString();
	s.Parameters = string.Format("Order={0}", Order.ToString());
	s.Cacheable = true;
	s.VaryByData = true;  
	this.Controls.Add(s);
	Order++;
}

I'm also using a BaseSublayout class to manage the accessor properties for the Datasource and Parameters

public class BaseSublayout : System.Web.UI.UserControl { 
	private Item _DataSourceItem; public Item DataSourceItem {  
		get {   
			if (_DataSourceItem == null)    
				_DataSourceItem = Sitecore.Context.Database.GetItem(((Sublayout)Parent).DataSource);   
			return _DataSourceItem;  
		}  
		set { _DataSourceItem = value;  } 
	}
	private NameValueCollection _Parameters; 
	public NameValueCollection Parameters {  
		get {   
			if (_Parameters == null)    
				Parameters = Sitecore.Web.WebUtil.ParseUrlParameters(((Sublayout)Parent).Parameters);   
			return _Parameters;  
		}  
		set {   _Parameters = value;  } 
	}
}