Global Office Directory
More Products
Share this page
Home > Community > Technical Blogs > John West Sitecore Blog > Repost: Cascade the Data Source of a Sublayout down to Nested Controls
You can use the techniques described in this post with the Sitecore ASP.NET Content Management System to apply the data source passed to a sublayout as the data source for controls nested within that sublayout. This can be especially useful when nesting the FieldRenderer within sublayouts. For more information about data sources, see my previous blog post, How to Apply Data Sources to Sitecore ASP.NET Presentation Components.
This is a repost of http://sitecorejohn.spaces.live.com/blog/cns!960125F1D4A59952!821.entry.
As described in the Presentation Component Cookbook, you can pass a data source to a sublayout or a rendering to indicate an item containing data for the presentation component to process. The context item, which corresponds to the URL requested by the browser, is the default data source for all presentation components.
The SublayoutParameterHelper Sitecore Shared Source project provides code that you can use to retrieve the data source and other parameters passed to a sublayout. The remainder of this post assumes that your sublayout inherits from the base class provided by SublayoutParameterHelper. To use that base class, add two classes to your project, and ensure your sublayouts inherit from one of them.
You can use the FieldRenderer from a presentation component to retrieve a field value, expand dynamic URLs in that value, insert inline editing controls around that value when editing in the Page Editor, and to enable other features around field values. For example, in an .ascx file, to retrieve the field named title:
<sc:fieldrenderer runat="server" fieldname="title" id="fldTitle" />
Like all presentation controls, the default data source for the FieldRenderer is the context item. In cases where you use the FieldRenderer from a sublayout, you might want the data source for the FieldRenderer to be the data source of the sublayout. You can explicitly set the data source from code:
protected void Page_Load(object sender, EventArgs e){ fldTitle.DataSource = this.DataSourceItem.Paths.FullPath; …
I guess it’s best to be explicit like this, but it might be annoying if there were many fields, and I could easily forget one.
To automatically set the data source on all FieldRenderer controls to the data source passed to the sublayout, add a method to the base class for sublayouts to iterate the controls recursively:
protected void ProcessDataSource(Control control, bool fieldsOnly){ Sitecore.Web.UI.WebControl wc = control as Sitecore.Web.UI.WebControl; Sitecore.Web.UI.WebControls.FieldRenderer fr = control as Sitecore.Web.UI.WebControls.FieldRenderer;
if (wc != null && (fr != null || !fieldsOnly)) { string source = wc.DataSource;
if (String.IsNullOrEmpty(source) || String.Compare(source, Sitecore.Context.Item.Paths.FullPath, true) == 0) { wc.DataSource = this.DataSourceItem.Paths.FullPath; } }
foreach (Control child in control.Controls) { this.ProcessDataSource(child, fieldsOnly); }}
Call that method from the Page_Load event of the sublayout:
protected void Page_Load(object sender, EventArgs e){ if (this.DataSourceItem != null && this.DataSourceItem != Sitecore.Context.Item) { this.ProcessDataSource(this, true); }}
This approach only has an effect after the Page_Load event, and only on the controls explicitly affected by the recursive method. You can pass false as the second parameter to the ProcessDataSource() method to apply the data source to all nested controls, not just FieldRenderers. You can probably find a way to avoid explicitly calling this method from every sublayout, such as adding that call to the Page_PreLoad event in the base class for the sublayout.
Alternatively, you can to add a method to the SublayoutBase base class for sublayouts to override the context item during the Render stage of the ASP.NET page lifecycle:
protected override void Render(HtmlTextWriter writer){ Sitecore.Data.Items.Item context = Sitecore.Context.Item; if (this.DataSourceItem != null) { context = this.DataSourceItem; } using (new Sitecore.Data.Items.ContextItemSwitcher(context)) { base.Render(writer); } }
This second approach is simpler, affects all nested Sitecore controls that access the context item, and works automatically for all sublayouts that inherit from the base class and either don’t override the Render() method or wrap base.Render() as this override does. This solution has no impact on code that runs outside of the Render stage of the ASP.NET page lifecycle.
Tags: API, Infrastructure
- Ming Chien February 23, 2011 at 4:44 PM
- John West March 07, 2011 at 9:06 AM
- John West April 27, 2011 at 9:58 AM
John has over ten years of experience in the CMS industry. His areas of focus include the Sitecore community, Web industry research, Sitecore technical documentation, and product management.
This website is designed to be fully functional with scripts disabled in browser. Please contact the webmaster for any suggestions