Creating Composite Controls
Introduction
So far in this series you developed controls by emitting raw HTML markup. As you will agree with me this can be tedious at times. Won't it be nice if you can assemble existing controls of ASP.NET and render them as a part of your control? In fact this is a common requirement in many cases and ASP.NET provides an easy way out. In this part you will develop a custom control that assembles existing server controls such as Label and TextBox.
The CompositeControl class
In the examples so far you inherited your custom controls from Control or WebControl base class. If you wish to develop a composite control then you need also need to do the following additional tasks:
Implement INamingContainer interface. This interface ensures that all the child controls of your control get a unique ID. This way your custom control can keep track of its constituent controls.
Call EnsureChildControl() method of Control class to ensure that the child controls are fully loaded before accessing their properties.
One can of course code the above steps manually. However, if you inherit from CompositeControl class instead of Control or WebControl class then these steps are automatically done for you.
Once you create a class that inherits from CompositeControl class then you need to override the CreateChildControls() method of the Control base class (CompositeControl class inherits from WebControl class that in turn inherits from Control class). Inside the CreateChildControls() method you will instantiate the child controls and add them to the Controls collection.
Example - Address control
In order to see how a composite control can be developed you will develop an Address control. The Address control renders various controls for accepting street address, city, state, country and postal code. You can then use the Address control in any web form. The following figure shows how the Address control looks like:
As you can see it renders field captions (Street, City etc.) along with entry controls (TextBox, DropDownList etc.)
To begin your development, create a new web site using Visual Studio. Add App_Code folder to your web site with one class named AddressControl.namespace
BinaryIntellect
{
public class AddressControl : CompositeControl
{
...
}
}
Remember to place the custom control class inside a namespace.
Now declare the following class level variables. These are the child controls of the Address control:
private Label lblStreet;
private Label lblCity;
private Label lblState;
private Label lblCountry;
private Label lblPostalCode;
private TextBox txtStreet;
private TextBox txtCity;
private TextBox txtState;
private DropDownList ddlCountry;
private TextBox txtPostalCode;
private Table tblContainer;
Now add the following public properties that simply set and get the values for Address control. public string Street
{
get
{
return txtStreet.Text;
}
set
{
txtStreet.Text = value;
}
} public string City
{
get
{
return txtCity.Text;
}
set
{
txtCity.Text = value;
}
} public string State
{
get
{
return txtState.Text;
}
set
{
txtState.Text = value;
}
} public string Country
{
get
{
return ddlCountry.SelectedValue;
}
set
{
ListItem li = ddlCountry.
Items.FindByValue(value);
if (li != null)
{
li.Selected=true;
}
}
} public string PostalCode
{
get
{
return txtPostalCode.Text;
}
set
{
txtPostalCode.Text = value;
}
}
For the sake of proper laying out the controls you use table as a container to them. To simply your job of adding controls to the table you develop a helper method as shown below:
private void AddControlsToTable
(Label lbl, Control ctrl)
{
TableRow row = new TableRow();
TableCell cell1 = new TableCell();
TableCell cell2 = new TableCell();cell1.Controls.Add(lbl);
cell2.Controls.Add(ctrl);row.Cells.Add(cell1);
row.Cells.Add(cell2);tblContainer.Rows.Add(row);
}
The AddControlsToTable() method accepts two parameters - a Label that is acting as a field caption and a control to be added. Inside it simply creates a TableRow and TableCell objects and adds the supplied Label and Control to them. The TableRow is finally added to the container table.
Finally, override the CreateChildControls() method as shown below:
protected override void CreateChildControls()
{
tblContainer = new Table();lblStreet = new Label();
lblStreet.Text = "Street :";
lblCity = new Label();
lblCity.Text = "City :";
lblState = new Label();
lblState.Text = "State :";
lblCountry = new Label();
lblCountry.Text = "Country :";
lblPostalCode = new Label();
lblPostalCode.Text = "Postal Code :";txtStreet = new TextBox();
txtStreet.Text = Street;
txtCity = new TextBox();
txtCity.Text = City;
txtState = new TextBox();
txtStreet.Text = State;
ddlCountry = new DropDownList();
ddlCountry.Items.Add("India");
ddlCountry.Items.Add("USA");
ddlCountry.Items.Add("UK");
if (Country != null)
{
ddlCountry.Items.FindByValue(Country).Selected = true;
}
txtPostalCode = new TextBox();
txtPostalCode.Text = PostalCode;AddControlsToTable(lblStreet, txtStreet);
AddControlsToTable(lblCity, txtCity);
AddControlsToTable(lblState, txtState);
AddControlsToTable(lblCountry, ddlCountry);
AddControlsToTable(lblPostalCode, txtPostalCode);Controls.Add(tblContainer);
}
In the CreateChildControls() method you initialize various controls and set their properties. You then call AddControlsToTable() helper method to add the appropriate controls to the table.
That's it. You can now use the Address control on a test web form to see it in action.