ASP.net(C#): Custom Templated Control



Source Code

What is a templated control exactly?

Its basically a control that provides us with greater control over the markup rendered by our controls, an example of a templated control in .net is the ListView control.

 
<asp:ListView runat="server" ID="lv" ItemPlaceholderID="ph">
    <LayoutTemplate>
        <table>
            <tr>
                <td>
                    ID
                </td>
                <td>
                    Title
                </td>
            </tr>
        </table>
    </LayoutTemplate>
    <ItemTemplate>
        <tr>
            <td>
                <%# Eval("ID") %>
            </td>
            <td>
                <%# Eval("Title") %>
            </td>
        </tr>
    </ItemTemplate>
</asp:ListView>
 

In the preceding snippet LayoutTemplate & ItemTemplate represents templated parts of the control.

In order to add this functionality to our own controls, we make use of the ITemplate interface like in the following basic snippet:
 
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
 
namespace CustomControls
{
    [ParseChildren(ChildrenAsProperties = true)]
	[Designer(typeof(CustomTemplateDesigner))]
    public class CustomTemplateControl : CompositeControl, INamingContainer
    {
        [Browsable(false)]
        [PersistenceMode(PersistenceMode.InnerProperty)]
        [TemplateContainer(typeof(CustomTemplateControl))]
        public ITemplate FirstTemplate
        {
            get;
            set;
        }
 
        [Browsable(false)]
        [PersistenceMode(PersistenceMode.InnerProperty)]
        [TemplateContainer(typeof(CustomTemplateControl))]
        public ITemplate SecondTemplate
        {
            get;
            set;
        }
 
        protected override void CreateChildControls()
        {
            if (FirstTemplate != null)
            {
                FirstTemplate.InstantiateIn(this);
            }
            if (SecondTemplate != null)
            {
                SecondTemplate.InstantiateIn(this);
            }
 
            base.CreateChildControls();
        }
    }
}
 

Notice the properties FirstTemplate & SecondTemplate, these properties expose our templates. Remember to set the PersistenceMode Attribute on these properties in order to persist the contents of these controls (a few MSDN examples excluded it).

Once we drop our control onto a page, these templates become available like this:
 
<cc:CustomTemplateControl ID="CustomTemplateControl1" runat="server">
    <SecondTemplate>
        2
    </SecondTemplate>
    <FirstTemplate>
        1
    </FirstTemplate>
</cc:CustomTemplateControl>
 

We can also add some design time support to our templated control like demonstrated in the following crude snippet:
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Design;
using System.Web.UI.Design;
using System.Web.UI;
using System.Web.UI.Design.WebControls;
using System.ComponentModel;
 
namespace CustomControls
{
    public class CustomTemplateDesigner : CompositeControlDesigner
    {
        private CustomTemplateControl _Control;
 
        public override void Initialize(IComponent component)
        {
            base.Initialize(component);
            _Control = (CustomTemplateControl)component;
 
        }
 
        private EditableDesignerRegion GetEditableRegion(ITemplate template, string title, string index, StringBuilder sb)
        {
            IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));
 
            sb.Append(String.Format(@"<tr>
                                        <td style=""font-family: Arial;background-color:#CCC"">
                                            {0}
                                        </td>
                                     </tr>
                                     <tr>
                                        <td {1}='{2}'>
                                            {3}
                                        </td>
                                     </tr>", title,
                            DesignerRegion.DesignerRegionAttributeName, index,
                            ControlPersister.PersistTemplate(template, host)));
 
            return new EditableDesignerRegion(this, String.Concat(DesignerRegion.DesignerRegionAttributeName, index), false);
        }
 
        public override string GetDesignTimeHtml(DesignerRegionCollection regions)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(@"<table style=""border:1px solid #CCC"">");
            EditableDesignerRegion region = GetEditableRegion(_Control.FirstTemplate, "First", "0", sb);
            EditableDesignerRegion region2 = GetEditableRegion(_Control.SecondTemplate, "Second", "1", sb);
            sb.Append("</table>");
            regions.Add(region);
            regions.Add(region2);
            return sb.ToString();
        }
 
        public override string GetEditableDesignerRegionContent(EditableDesignerRegion region)
        {
            IDesignerHost host = (IDesignerHost)Component.Site.GetService(typeof(IDesignerHost));
            if (host != null)
            {
                ITemplate template = (region.Name == String.Concat(DesignerRegion.DesignerRegionAttributeName, "0")) ? _Control.FirstTemplate : _Control.SecondTemplate;
                if (template != null)
                    return ControlPersister.PersistTemplate(template, host);
            }
            return String.Empty;
        }
 
        public override void SetEditableDesignerRegionContent(EditableDesignerRegion region, string content)
        {
            if (content == null)
                return;
 
            IDesignerHost host = (IDesignerHost)Component.Site.GetService(typeof(IDesignerHost));
            if (host != null)
            {
                ITemplate template = ControlParser.ParseTemplate(host, content);
                if (region.Name == String.Concat(DesignerRegion.DesignerRegionAttributeName, "0"))
                    _Control.FirstTemplate = template;
                else
                    _Control.SecondTemplate = template;
            }
        }
    }
}
 

In a future post we will have a look at how to databind templated controls.







Post comment

Name *
Email
Title
Body *
Security Code
*
* Required fields

Related Posts

ASP.net (C#) - WebControlAdapter


2010-03-11 21:47:12

Latest Posts

Be the best stalker you can be


2011-12-13 22:33:54

Syntactic sugar (C#): Enum


2011-08-04 16:50:18

Top 5 posts

Simple WYSIWYG Editor


Creating a WYSIWYG textbox for your website is actually quite simple.
2007-02-01 12:00:00

Moving items between listboxes in ASP.net/PHP example


Move items between two listboxes in ASP.net(C#, VB.NET) and PHP
2008-06-12 17:07:43

Cross Browser Issues: Firefox Word Wrapping


Firefox word wrapping issues
2008-06-09 09:51:21

Populate a TreeView Control C#


Populate a TreeView control in a windows application.
2009-08-27 16:01:03

C# YouTube : Google API


Post on how to integrate with YouTube using the Google Data API
2011-03-12 08:37:51