Composite Controls

Composite Controls

Occasionally, building custom controls by combining other controls is useful. A control that serves as a container for other controls is called a composite control, and it, too, is an important element of ASP.NET s server control architecture.

All Control-derived classes have the innate ability to act as containers for other controls. Contained controls, or child controls, are exposed through the parent control s Controls property, which is inherited from Control. Controls type is ControlCollection, which provides methods and properties for adding controls, removing controls, enumerating controls, and more. System.Web.UI.Page counts Control among its base types. Its Controls collection defines all the controls on the page.

Composite controls come in two basic varieties: declarative and programmatic. A declarative custom control contains other controls declared in a Web form. The FCL s Panel control is one example of a declarative composite. It acts as a container for other controls and allows them to be manipulated programmatically, but it doesn t create the controls that it contains: you create these controls by declaring them between <asp:Panel> and </asp:Panel> tags. By contrast, a programmatic composite creates the controls that it hosts programmatically. Both types of composites are discussed in the sections that follow.

Declarative Composites

Here s the simplest composite control you can build:

using System.Web.UI; namespace Wintellect { public class CompositeControl : Control { } }

On the surface, it doesn t seem as if this control could do anything useful. But check this out:

<%@ Register TagPrefix="win" Namespace="Wintellect"  Assembly="CompositeControl" %> <html> <body> <form runat="server"> <win:CompositeControl  RunAt="server"> <asp:Label Text="Hello!" RunAt="server" /><br> <asp:Label Text="Goodbye!" Runat="server" /> </win:CompositeControl> </form> </body> </html>

In this example, CompositeControl serves as a container for a pair of Label controls. ASP.NET automatically adds the Label controls to the CompositeControl s Controls collection. Furthermore, CompositeControl s inherited Render method calls the child controls Render methods. If a server-side script prevents CompositeControl s Render method from being called by setting the control s Visible property (which it inherits from Control) to false, like this:

MyComposite.Visible = false;

the children s Render methods won t be called either. Consequently, the children will disappear from the Web page all because you turned off the control that contains them.

The GroupBox Control

Windows developers are familiar with the group box control, which draws a stylish border around other controls and visually groups them together. HTML 4 and later versions support a <fieldset> element that looks very much like a group box. The following HTML displays three radio buttons surrounded by a group box:

<html> <body> <form> <fieldset> <legend>Colors</legend> <input type="radio" name="Color" value="red">Red<br> <input type="radio" name="Color" value="green">Green<br> <input type="radio" name="Color" value="blue">Blue </fieldset> </form> </body> </html>

The <fieldset> element is an ideal candidate to be encapsulated in a custom control, and a composite control fits the bill perfectly. Figure 8-19 contains the source code for an ASP.NET GroupBox control. It renders its children by calling the base class s Render method, but it surrounds the child controls output with <fieldset> and </fieldset> tags. Figure 8-20 contains a GroupBox test page, and Figure 8-18 shows the output. Clicking the check box at the top of the page toggles the GroupBox control (and by extension, its children) on and off by alternately setting the GroupBox s Visible property to true and false.

RadioButtonList is a composite control, too, so this example nests one composite control inside another. The ListItems are children of the RadioButtonList, and the RadioButtonList is a child of the GroupBox. That means you guessed it the GroupBox has grandchildren!

Figure 8-18

Controls grouped with a GroupBox control.

GroupBox.cs

using System; using System.Web.UI; namespace Wintellect { public class GroupBox : Control { string MyText = ""; public string Text { get { return MyText; } set { MyText = value; } } protected override void Render (HtmlTextWriter writer) { // Output a <fieldset> tag writer.WriteBeginTag ("fieldset"); if (ID != null) writer.WriteAttribute ("id", ClientID); writer.Write (HtmlTextWriter.TagRightChar); // Output a <legend> element if (Text.Length > 0) { writer.WriteBeginTag ("legend"); writer.Write (Text); writer.WriteEndTag ("legend");

 } // Output the content between <fieldset> and </fieldset> tags base.Render (writer); // Output a </fieldset> tag writer.WriteEndTag ("fieldset"); } } }

Figure 8-19

GroupBox control.

GroupBoxPage.aspx

<%@ Register TagPrefix="win" Namespace="Wintellect"  Assembly="GroupBoxControl" %> <html> <body> <form runat="server"> <asp:CheckBox  Text="Show colors"  OnCheckedChanged="OnToggle" AutoPostBack="true" Checked="true" RunAt="server" /><br> <win:GroupBox  Text="Colors" RunAt="server"> <asp:RadioButtonList RunAt="server"> <asp:ListItem Text="Red" Selected="true" RunAt="server" /> <asp:ListItem Text="Green" RunAt="server" /> <asp:ListItem Text="Blue" RunAt="server" /> </asp:RadioButtonList> </win:GroupBox> </form> </body> </html> <script language="C#" runat="server"> void OnToggle (Object sender, EventArgs e) { MyGroupBox.Visible = Toggle.Checked; } </script>
Figure 8-20

GroupBox test page.

Programmatic Composites

Programmatic composite controls create child controls programmatically. All controls inherit a virtual CreateChildControls method from Control that can be overridden in a derived class. The .NET Framework calls CreateChildControls very early in the control s lifetime, so it s the perfect place to instantiate child controls. The following control is the programmatic equivalent of the declarative control presented a few moments ago the one containing Label controls with the greetings Hello! and Goodbye!

using System.Web.UI; using System.Web.UI.WebControls; namespace Wintellect { public class CompositeControl : Control { protected override void CreateChildControls () { Label label1 = new Label (); label1.Text = "Hello!"; Controls.Add (label1); Controls.Add (new LiteralControl ("<br>")); Label label2 = new Label (); label2.Text = "Goodbye!"; Controls.Add (label2); } } }

In its override of CreateChildControls, CompositeControl instantiates the Label controls with new and adds them to its Controls collection with ControlCollection.Add. It also uses a Literal control to insert a <br> element between the Labels.

The LoginControl

The Web page in Figure 8-21 is built around a composite control named LoginControl. LoginControl is functionally similar to the login control presented in Chapter 7. When instantiated, it creates two TextBox controls and a Button control and adopts them as child controls. If the user enters a user name and password and clicks the button, the control fires a Login event. A server-side script can process the event and retrieve the user name and password by reading the control s UserName and Password properties. LoginControl s source code appears in Figure 8-22. You ll find a page to test it with in Figure 8-23.

One nuance of composite controls that you should be aware of regards the INamingContainer interface. All but the most trivial composite controls should derive from INamingContainer. If they don t, they re liable to suffer strange maladies, including events that don t fire properly. INamingContainer s purpose is to allow ASP.NET to assign child controls names that are unique with respect to other controls on the page. Fortunately, INamingContainer requires no implementation. It s a signal interface, meaning it has no methods. Simply including INamingContainer in a control s list of base types is sufficient to implement the interface.

Figure 8-21

Custom login control.

LoginControl.cs

using System; using System.Web.UI; using System.Web.UI.WebControls; namespace Wintellect { public class LoginControl : Control, INamingContainer { TextBox MyUserName = new TextBox (); TextBox MyPassword = new TextBox (); public event EventHandler Login; public string UserName { get { return MyUserName.Text; } set { MyUserName.Text = value ; } } public string Password {

 get { return MyPassword.Text; } set { MyPassword.Text = value ; } } protected override void CreateChildControls () { Controls.Add (MyUserName); Controls.Add (new LiteralControl ("<br>")); Controls.Add (new LiteralControl ("<br>")); MyPassword.TextMode = TextBoxMode.Password; Controls.Add (MyPassword); Controls.Add (new LiteralControl ("<br>")); Controls.Add (new LiteralControl ("<br>")); Button button = new Button (); button.Text = "Log In"; Controls.Add (button); button.Click += new EventHandler (OnLogin); } protected void OnLogin (Object sender, EventArgs e) { if (Login != null && UserName.Length > 0 && Password.Length > 0) Login (this, new EventArgs ()); } } }

Figure 8-22

LoginControl source code.

LoginControlPage.aspx

<%@ Register TagPrefix="win" Namespace="Wintellect" Assembly="LoginControl" %> <html> <body> <h1>Login Control Demo</h1> <hr> <form runat="server"> <win:LoginControl  OnLogin="OnLogin" RunAt="server" /> </form> <hr> <asp:Label  RunAt="server" /> </html>

<script language="C#" runat="server"> void OnLogin (Object sender, EventArgs e) { Output.Text = "Hello, " + Login.UserName; } </script>

Figure 8-23

LoginControl test page.



Programming Microsoft  .NET
Applied MicrosoftNET Framework Programming in Microsoft Visual BasicNET
ISBN: B000MUD834
EAN: N/A
Year: 2002
Pages: 101

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net