, ,

One of the least inspiring things of producing Sitecore SubLayouts is binding the field controls to the fields of the data item in a repeater. Sitecore field controls are: sc:text, sc:link and sc:image. These controls are convenient for rendering a field of Sitecore item on the page, as plain text, a link, or an image.

For example, we have a product item. This item can contain fields for a title, description, image, etc. Let’s imagine the item has 10 fields. If we want to show a list of products on the page, we would probably use a asp:Repeater which is filled with all the products. So in the repeater’s ItemTemplate we will put markup like this:

<sc:Text runat="server" ID="TextProductTitle" field="ProductTitle" />
<sc:Image runat="server" ID="ImageProductImage" field="ProductImage" />

Then in the Repeater’s ItemDataBound event handler, this would result in an enormous bulk of tedious code, what Scott Hanselman calls “left-hand/right-hand code”. First you have to get all the Sitecore field controls from the RepeaterItem, and then you have to set the DataSource property for all these controls with the same datasource string. This would look something like this:

private void Repeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
	var item = (Item)e.Item.DataItem;

	var textTitle = (Text)e.Item.FindControl("TextTitle");
	var textDescription = (Text)e.Item.FindControl("TextDescription");
	var imageProductImage = (Text)e.Item.FindControl("ImageProductImage");
	var textField1 = (Text)e.Item.FindControl("TextField1");
	var textField2 = (Text)e.Item.FindControl("TextField2");
	var textField3 = (Text)e.Item.FindControl("TextField3");
	var textField4 = (Text)e.Item.FindControl("TextField4");
	var textField5 = (Text)e.Item.FindControl("TextField5");

	textTitle.DataSource = item.Paths.FullPath;
	textDescription.DataSource = item.Paths.FullPath;
	imageProductImage.DataSource = item.Paths.FullPath;
	textField1.DataSource = item.Paths.FullPath;
	textField2.DataSource = item.Paths.FullPath;
	textField3.DataSource = item.Paths.FullPath;
	textField4.DataSource = item.Paths.FullPath;
	textField5.DataSource = item.Paths.FullPath;


Imagine doing this for 10 fields. It’s not pretty. This is something that must be automated. To automate the previous bulk of code, you would want to loop through the control collection, and set the datasource to all these controls at once. But the ControlCollection class is not Enumerable, so looping through it is not yet possible. For this we need an extension method, and I found one here. I extraced the logic, and made it into the extension method MakeEnumerable(). With this we could use LINQ on the ControlCollection to get all the controls that inherit from FieldControl, like sc:Text, sc:Link, sc:Image, etc.. For each of these controls, we can now set the datasource, and prevent to write the same code over and over:

private void Repeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
	var item = (Item)e.Item.DataItem;

	IEnumerable<Control> sitecoreFieldControls = e.Item.Controls.MakeEnumerable().Where(c => c is FieldControl);
	foreach (FieldControl control in sitecoreFieldControls)
		control.DataSource = item.Paths.FullPath;