Login | Register   
RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Web Control Templates Explained : Page 2

Programming for extensibility assures ease of maintainability in your design. Control templates offer this functionality to custom Web controls.

Template Containers
A template container is actually another composite control that you'll use to contain the template(s) that you will define. Often you'll use a panel control for this purpose but for reasons that I will explain later, I like to use another custom control. This control must inherit from the WebControl class and implement the INamingContainer interface which makes it a valid Web control and also gives it the ability to properly and uniquely name any contained child controls. This control will contain the child controls that a page developer will drag into that template later. Remember, a template will be represented as an area of your control that a page developer will use into which to drag other controls, thereby extending your control visually. This code snippet illustrates how I'll create an empty composite control that will serve as my template container.

Public Class TemplateItem Inherits System.Web.UI.WebControls.CompositeControl End Class

Note that I don't even have to have the ToolboxData attribute set since I won't actually drag and drop this control onto a form. Also notice that I'm inheriting from the CompositeControl class which is new in ASP.NET 2.0. This automatically inherits from WebControl and implements INamingContainer. So you have an empty control that will serve as the container for your template(s) and whose Controls collection you'll use (or should I say, the page developer will use).

I'll leave the template container control as-is for now in order to get running with the first template example, but I'll get back to it later on. Now I'll show you how to define your templates.

Figure 1: The EmailContact control (with styling).
Defining Templates
Since I want to add template functionality to my EmailContact control, I have to start by determining where I want this. If you go back to the articles where I developed this control you will see that it renders a form for a user to fill out like you would see in a "Contact Us" scenario (see Figure 1). The control displayed a heading at the top of the form and a "send" button below the form fields. I want to add two templates to this control; one directly below the heading and one directly above the button. I want to give the page developer the ability to put whatever he or she wants in these areas, thus enhancing what the control will display. In fact, since this control has the ability to turn off the heading and the button, the positions of these two templates can give the page developer complete flexibility in what will display around the e-mail form.

Now you know that I want to add two templates to this control and where I want to add them. It will not come as a surprise that I will call them HeaderTemplate and FooterTemplate. So let's talk about what these names mean.

The names HeaderTemplate and FooterTemplate are going to be exposed as properties in my EmailContact control, and are to represent the templates I will offer page developers so they can extend this control. However, while in the past I taught you how to create Web control properties using the ViewState storage technique, I'll code these properties using member variables as if they were contained in ordinary objects. You don't need to include ViewState in this because the page developer will fill these properties during page-design time. This means that their contents will be coded into the ASPX page so state management is unnecessary.

So I'll start by creating two member variables of the type ITemplate.

Protected _HeaderTemplate As ITemplate Protected _FooterTemplate As ITemplate

The EventHandler delegate has an overload that accepts an event argument object type in a generic. This eliminates the need to create a custom delegate to handle a custom event argument object.
This interface defines one method called InstantiateIn which I will use shortly. Now I'll create two properties that expose these member variables in the standard fashion that object properties do all the time.

Public Property HeaderTemplate() As ITemplate Get Return _HeaderTemplate End Get Set(ByVal value As ITemplate) _HeaderTemplate = value End Set End Property Public Property FooterTemplate() As ITemplate Get Return _FooterTemplate End Get Set(ByVal value As ITemplate) _FooterTemplate = value End Set End Property

The properties (or member variables) do not need a concrete instantiation because they will receive one as soon as the page developer fills the template.

Believe it or not, we're half way there. I've created a control to act as my template container (if you're still confused as to why I will soon make this clear), and I've created a couple of properties to represent my templates. Before I actually use these properties and the container control, I have to decorate the properties with the TemplateContainer and PersistenceMode attributes.

<TemplateContainer(GetType(TemplateItem)), _ PersistenceMode(PersistenceMode.InnerProperty)> _ Public Property HeaderTemplate() As ITemplate Get Return _HeaderTemplate End Get Set(ByVal value As ITemplate) _HeaderTemplate = value End Set End Property <TemplateContainer(GetType(TemplateItem)), _ PersistenceMode(PersistenceMode.InnerProperty)> _ Public Property FooterTemplate() As ITemplate Get Return _FooterTemplate End Get Set(ByVal value As ITemplate) _FooterTemplate = value End Set End Property

The TemplateContainer attribute tells this property where the template it represents will be contained. I've mentioned that repeatedly already and when I add the templates to my control hierarchy, things will become clearer on this topic. The second attribute, PersistenceMode merits a more detailed explanation.

If you've read my previous Web control articles, I used an attribute on properties of the Style object so it may be a little familiar to you. Let me start by reminding you what happens when you drag an EmailContact Web control onto a Web Form. If you switch to ASPX view, you would see the control like this:

<dnd:EmailContact2 ID="EmailContact1" runat="server"> </dnd:EmailContact2>

The PersistenceMode attribute, when used with the enum value PersistenceMode.InnerProperty, orders this property to display as an inner tag within the tags that make this control. The properties I created, HeaderTemplate and FooterTemplate, will by default, display as attributes in the EmailContact2 tags displayed above. By marking it as an "InnerProperty," they will display like this:

<dnd:EmailContact2 ID="EmailContact1" runat="server"> <HeaderTemplate></HeaderTemplate> <FooterTemplate></FooterTemplate> </dnd:EmailContact2>

When you add controls to these templates, the reasons for this will become clear.

Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.



Thanks for your registration, follow us on our social networks to keep up-to-date