Programming Microsoft ASP.NET 4 - Dino Esposito [271]
The Render Method
Typically, an ASP.NET control renders out through the Render method. To take total control of the control’s rendering, you therefore override the Render method and write markup code to the specified HTML text writer object:
protected override void Render(HtmlTextWriter writer)
The HTML text writer object is a sort of buffer where you can accumulate all the text to be output—nearly the same as a string builder. You can compose markup using the methods of the HtmlTextWriter object or by building plain strings. Writing to the text writer is indeed the fastest way for controls to generate their markup, but unfortunately it doesn’t result in easily readable code. If you take this route for a reasonably complex control, your final code will look like an intricate mess of nested if-then-else statements. Your code will be hard to read and maintain.
There’s another aspect to consider about direct markup output. Consider the following code snippet:
protected override void Render(HtmlTextWriter writer)
{
writer.Write("");
}
The final page contains an input field of type text with an ID of TextBox1. The server environment, though, doesn’t know anything about this element and might not be able to process server events for this element correctly. In other words, you should render the markup directly only for controls that output raw HTML that don’t match ASP.NET controls and don’t need to raise or handle server events such as postbacks or post-data-changed events. If you’re going to write a server control that renders an HTML marquee or a table of data, writing to the control’s text writer buffer is fine. If you’re building a control that results from the composition of other controls, you’re better off taking another approach—building the control tree programmatically.
Building the Control Tree
When your control embeds constituent child controls, you have a composite control. In this case, it is recommended that you build the final tree of controls programmatically by overriding the CreateChildControls method defined on the Control class. You do this by adding all constituent controls to the Controls collection of the control being developed. Here’s an example:
protected override void CreateChildControls()
{
// Clears child controls
Controls.Clear();
// Build the control tree
CreateControlHierarchy();
// Clear the view state of child controls
ClearChildViewState();
}
ClearChildViewState is a method on the Control class that deletes the view-state information for all the server child controls. CreateControlHierarchy, on the other hand, is an arbitrary name and represents a user-defined method that builds the control’s tree. You should feel free to replace that function with your own function or plain code. As a matter of fact, though, most ASP.NET built-in composite controls define a protected, overridable method with just that name. Here’s a possible implementation for CreateControlHierarchy that creates a text box with a leading label. Note that not only is the name of CreateControlHierarchy arbitrary, but its prototype also is.
protected void CreateControlHierarchy()
{
// Add the label
var lbl = new Label();
lbl.Text = "Some text";
Controls.Add(lbl);
// Add a blank literal control for spacing
Controls.Add(new LiteralControl(" "));
// Add the text box
var txt = new TextBox();
txt.Text = String.Empty;
Controls.Add(txt);
// Specifies that child controls have been created
ChildControlsCreated = true;
}
The ultimate goal of CreateControlHierarchy is populating the Controls collection of the current control with all child controls in the proper position in the final hierarchy. The ChildControlsCreated Boolean property is defined on the Control class and indicates whether all child controls