Now that we have looked at a simple example, I can declare that the same guidelines and trends apply when creating composite controls… in addition:
The containing control should inherit from a basic control or a template server control
This is a fast and hard guideline. If your control inherits from the Panel control or similar controls, then expect the functionality to break. The reason is: with the attributes that are applied to the Panel class, makes the text inside the control to be treated as child controls… not as part of the containing control (as what the previous sample demonstrated and discussed briefly on).
Create a property and with a value type of ITemplate interface.
This is to allow the other control developers to extend your template based control. Your template should be a “pluggable” property – either can be set programmatically or my mark-up: the later was demonstrated on the first page of this article and the other (the first mention) will be demonstrated later in the article. There is one exception for this trend:
If you need to provide a type of default template for the template property, follow the same rules as if the ITemplate was a server control.
There will be some times that you will want a “default” template. This situation will only occur if one is trying to programmatically set the template property. Instead of having an ITemplate interface as the property’s data type, the template should be a class.
This template class, that implements the ITemplate interface, should follow the same general guidelines and trends as if it is a server control. The reason for this is that you do not want to limit the extension of your server control at all (and hiding templates should not hinder the consistency at all). For example, let’s say that you had a template class:
public class MyTemplate : ITemplate {
public virtual void InstantiateIn(Control container) {
Label label = new Label();
// ...
container.Controls.Add(label);
}
}
The “template class” should have the ability to be extended such as (just in the same fashion as with actual server controls):
public class MyExtendedTemplate : MyTemplate {
public overrides void InstantiateIn(Control container) {
Button button = new Button();
// ...
base.InstantiateIn(container);
container.Controls.Add(button);
}
}
The properties that expose the templates should have the getter and setter methods.
This is required by ASP.NET. Do not fall into this trap because this is a very common mistake made by control developers and normally find themselves dumb-founded when ASP.NET throws an error.
All controls created by the template, should not have an ID set
There may be problems if you set the ID’s of the controls inside the template, to something. Rather let ASP.NET control the ID for the controls inside the template.
The container control should implement the INamingContainer interface
Brutally said, this is to avoid complications with the previous guideline. Things can get hairy without this interface and most of the time; this will bail you out of the mess. Obviously, this “hair” will only grow if the controls inside the template actually do post backs to the server.
Suffix your property name with “Template” if it exposes a template
This is a naming convention for your properties. For example, if you had a control that you wanted to expose a template property by the name of “Foo”, then the name of the property should be “FooTemplate”. This describes what the property is and also keeps consistency with the framework (you have the ItemTemplate template in the Repeater control and so forth).
Always create new instances of controls in the InstantiateIn method
This is a trap that most developers fall into when creating “repeater” controls. This is just a guideline and the reason for people running into this trap is for the simple reason that .NET handles all variables as pointers/references instead of objects.