Creating Composite Controls

I l @ ve RuBoard

Composite controls are a bit more advanced than the controls we have seen thus far, but they are still fairly simple to build. For one thing, you still do not need to worry about handling PostBacks , because you can rely on all the features of the included controls to work just as if they were placed on the page themselves . Composite controls, because they typically encapsulate several pieces of UI code, are very close in function to user controls, so you will want to consider the differences between user controls and custom controls before you decide which method to use to create the functionality you need.

For this example, we will simply give the user the option of making the YesNoListBox required. To do this, we will actually go ahead and use our existing YesNoListBox control and include it along with a RequiredFieldValidator in a new control called ReqYesNoListBox . The complete code for this new control is in Listing 12.5.

Listing 12.5 ReqYesNoDropDownList.cs
 using ASPNETByExample; using System.Web.UI.WebControls; namespace ASPNETByExample {     public class ReqYesNoDropDownList : System.Web.UI.Control, System.Web.UI.  INamingContainer     {         // Declare child controls         protected YesNoDropDownList ynList;         protected RequiredFieldValidator ynRequired;         public ReqYesNoDropDownList()         {             this.ynList = new YesNoDropDownList();             this.ynRequired = new RequiredFieldValidator();             ynList.ID = "YesNo" + this.UniqueID;             ynRequired.ControlToValidate = ynList.ID;             ynRequired.Display = ValidatorDisplay.Dynamic;             ynRequired.Enabled = true;             ynRequired.EnableViewState = false;             ynRequired.Text = "*";             ynRequired.ErrorMessage    = "You must select either Yes or No.";         }         public string Value         {             get             {                 return this.ynList.Value;             }             set             {                 this.ynList.Value = value;             }         }         protected override void CreateChildControls()         {             this.Controls.Clear();             this.Controls.Add(ynList);             this.Controls.Add(ynRequired);         }     } } 

USE Trace TO DEBUG CUSTOM CONTROLS

If you want to add Trace statements to your custom controls so that you can debug their execution using ASP.NET's built-in tracing support, you need to reference the HttpContext.Current instance. For example, the following line of code would output a line to the trace results of the ASP.NET page that the control was listed on:

System.Web.HttpContext.Current.Trace.Write("Render","Rendering ");

Because we're going to be using our existing YesNoDropDownList control, I've gone ahead and included the ASPNETByExample namespace, along with the System.Web.UI.WebControls namespace, which holds the definition for the RequiredFieldValidator control. As with our HelloWorld control, we are inheriting from the Control class. This time, however, we are also implementing the INamingContainer interface. This interface is important to custom controls, because it ensures that any control created on an ASP.NET page will have a unique ID on the page. When building custom controls, you should always use this interface. You only need to worry about this if you are inheriting directly from Control ”all the existing Web controls already implement this interface (so, for example, our YesNoDropDownList doesn't need to specify this interface, since DropDownList already implements it).

After declaring the controls that we will include in our composite control, we initialize their values in the ReqYesNoDropDownList() constructor. There's a little bit of a trick to note here. Since validator controls require a ControlToValidate property to be set, you need to know the name of the YesNoDropDownList . However, unless we set its ID ourselves , we have no way of knowing what unique ID the ASP.NET processor will give to this control. Worse, if we just hard-coded the ID field, we would never be able to use more than one of our controls on a page, because the names would conflict. The solution to this problem is to create an ID dynamically using the UniqueID of our composite control as part of the name of the child control. In this way, we can know the name of the control for the validator to reference, and we can still have as many of these composite controls on a page as we want.

After dealing with the issue of IDs, we set some default properties for the RequiredFieldValidator , ynRequired . Because these child controls are declared as protected, the user cannot access any of these properties directly, so the only way they can be set is within the composite control. If you want your control's child controls to be available to users directly, you can either declare them as public (which is not usually recommended), or you can set up properties that map to the child control's properties. This is what we have done for the YesNoDropDownList Value property. Our ReqYesNoDropDownList exposes a public property of Value , which simply delegates its sets and gets to the ynList child control.

Finally, we come to the most important method of a composite control, the CreateChildControls() method. This method is similar to Render() in that it is built into the Control object and must be overridden in our composite control in order for us to use it. In this case, we are programmatically adding our child controls to this control's Controls collection, using the collection's Add() method. The controls are automatically rendered by the Control class in the order in which we have added them.

NOTE

It is quite possible to build custom controls that inherit from other custom controls, ad infinitum. Some very powerful suites of controls can be built in this fashion. If you have several layers of controls that need to render user interface logic, either with the Render() method or the CreateChildControls() method, you can make sure that your superclass performs its rendering by using the base keyword in C# (which is analogous to the MyBase keyword in VB.NET, or the super keyword in Java). So, within the Render() method, you would call base.Render() , and within the CreateChildControls() method, you would call base.CreateChildControls() .


To test out our new control, let's take a look at ReqYesNo.aspx, which is listed in its entirety in Listing 12.6.

Listing 12.6 ReqYesNo.aspx
 <%@ Register TagPrefix="YN" Namespace="ASPNETByExample" Assembly="YesNoDropDownList" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" > <html>     <body>         <form id="YesNo" method="post" runat="server">             You must answer yes or no:             <YN:ReqYesNoDropDownList runat="server" id="fun" />             <asp:Button Runat="server" text="Go" />             <hr />             <asp:ValidationSummary Runat="server" />             <h1>                 <%=fun.Value%>             </h1>         </form>     </body> </html> 

For this test, we've modified the YesNo.aspx file so that it uses the ReqYesNoDropDownList (which was compiled into the same assembly as before), and removed the default value for the list so that the user will have to choose either Yes or No. We've also added a ValidationSummary control to display any error messages that are generated by our validation controls. Attempting to submit the form without choosing a value results in the error message being displayed, as in Figure 12.1.

Figure 12.1. Testing our required YesNo DropDownList.

Now that we have seen how to build custom controls from scratch or by inheriting from existing controls, let's dig a little bit deeper and look at some of the more advanced options available. Note that control-building techniques could easily fill a book themselves, so we will only be able to provide cursory coverage of some of these topics.

When developing your own controls, there are several more advanced pieces of functionality that you may want to add. These include

  • Handling control events

  • Handling PostBack s

  • Using templates

  • Raising events

  • Databinding

These techniques are covered in the rest of the chapter.

I l @ ve RuBoard


Asp. Net. By Example
ASP.NET by Example
ISBN: 0789725622
EAN: 2147483647
Year: 2001
Pages: 154

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