Composite Controls
Because ASP.NET has so many useful controls, you might rightfully feel that there's no reason to reinvent the wheel with your own control implementation. Instead, a combination of controls might accomplish what you're after. Fortunately you can build composite controls to do just that. If you've ever ventured into the world of Windows forms, building a composite control will seem very familiar to you.Building a composite control is simply a matter of instantiating existing controls and adding them to the Controls property of the base CompositeControl class. In fact, the first requirement to build a composite control is that your class must inherit from CompositeControl. You don't need to choose between the three choices we mentioned for our from-scratch server control.The second requirement is to override CompositeControl's CreateChildControls() method. This is where the real magic happensit's where we create, name, and add controls to the Controls property of the base CompositeControl class (the property happens to be of the type ControlCollection).Let's build a simple composite control that has little to no real use but that shows how easy it is to build a composite control. Let's say we need a TextBox, a Label, and a Button control. Clicking on the button should cause the text in the TextBox to display in the label.Using what we know about class design and event handlers, we can quickly build the class. We'll need private variables to hold each of our three controls. We'll need an event handler that will copy the text of the TextBox to the Text property of the label. Finally, we'll need a place to create all of these controls, and that place is of course the CreateChildControls() method we mentioned earlier. Listing 9.10 shows the entire class (as well as its use in a page), while Figure 9.3 shows how the controls will be rendered in the browser.
Listing 9.10. A simple composite control
C#
VB.NET
using System;
using System.Collections.Specialized;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace SimpleComposite
{
public class MyCompositeControl : CompositeControl
{
private TextBox _textBox;
private Label _label;
private Button _button;
protected override void CreateChildControls()
{
_textBox = new TextBox();
_textBox.ID = "MyTextBox";
this.Controls.Add(_textBox);
_label = new Label();
_label.ID = "MyLabel";
this.Controls.Add(_label);
_button = new Button();
_button.ID = "MyButton";
_button.Text = "Click me!";
_button.Click += new EventHandler(this.ButtonClickHandler);
this.Controls.Add(_button);
}
private void ButtonClickHandler(object sender, EventArgs e)
{
_label.Text = _textBox.Text;
}
}
}
.aspx page
Imports System
Imports System.Collections.Specialized
Imports System.Text
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
Namespace SimpleComposite
Public Class MyCompositeControl
Inherits CompositeControl
Private _textBox As TextBox
Private _label As Label
Private _button As Button
Protected Overrides Sub CreateChildControls()
_textBox = New TextBox()
_textBox.ID = "MyTextBox"
Me.Controls.Add(_textBox)
_label = New Label()
_label.ID = "MyLabel"
Me.Controls.Add(_label)
_button = New Button()
_button.ID = "MyButton"
_button.Text = "Click me!"
_button.Click += New EventHandler(Me.ButtonClickHandler)
Me.Controls.Add(_button)
End Sub
Private Sub ButtonClickHandler(sender As Object, e As EventArgs)
_label.Text = _textBox.Text
End Sub
End Class
End Namespace
<%@ Page Language="C#" Codefile="Default.aspx.cs" Inherits="Default_aspx" %>
<%@ Register Assembly="SimpleComposite" Namespace="SimpleComposite" TagPrefix="Sample" %>
<html>
<body>
<form id="form1" runat="server">
<Sample:MyCompositeControl ID="CompositeTest" Runat="Server" />
</form>
</body>
</html>
Figure 9.3. Our composite control rendered in the browser

Listing 9.11. The Render() method and the HTML rendered for the browser
C#
VB.NET
protected override void Render(HtmlTextWriter writer)
{
writer.RenderBeginTag(HtmlTextWriterTag.Table);
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.RenderBeginTag(HtmlTextWriterTag.Td);
_textBox.RenderControl(writer);
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.RenderBeginTag(HtmlTextWriterTag.Td);
_button.RenderControl(writer);
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.RenderBeginTag(HtmlTextWriterTag.Td);
_label.RenderControl(writer);
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderEndTag();
}
HTML source sent to browser[View full width]
Protected Overrides Sub Render(writer As HtmlTextWriter)
writer.RenderBeginTag(HtmlTextWriterTag.Table)
writer.RenderBeginTag(HtmlTextWriterTag.Tr)
writer.RenderBeginTag(HtmlTextWriterTag.Td)
_textBox.RenderControl(writer)
writer.RenderEndTag()
writer.RenderEndTag()
writer.RenderBeginTag(HtmlTextWriterTag.Tr)
writer.RenderBeginTag(HtmlTextWriterTag.Td)
_button.RenderControl(writer)
writer.RenderEndTag()
writer.RenderEndTag()
writer.RenderBeginTag(HtmlTextWriterTag.Tr)
writer.RenderBeginTag(HtmlTextWriterTag.Td)
_label.RenderControl(writer)
writer.RenderEndTag()
writer.RenderEndTag()
writer.RenderEndTag()
End Sub
<table>
<tr>
<td><input name="CompositeTest$MyTextBox" type="text" value="Hello!"id="CompositeTest_MyTextBox" /></td>
</tr><tr>
<td><input type="submit" name="CompositeTest$MyButton" value="Click me!"id="CompositeTest_MyButton" /></td>
</tr><tr>
<td><span id="CompositeTest_MyLabel">Hello!</span></td>
</tr>
</table>
Figure 9.4. Our formatted composite control as seen in the browser

You might be wondering why we marked our methods "protected." Recall from Chapter 2, "Classes: The Code Behind the Objects," that a protected member can only be called from within the class or from within the derived class. If someone were to derive from our class to make their own implementation, we don't want users of the derived control calling the member of the base class (our class) because it would cause confusion between the original member and the derived member. Therefore, we "protect" the original version. |