Chapter 30. Developing ASP.NET Controls

IN THIS CHAPTER

ASP.NET radically increases the productivity of web developers by running atop the .NET Framework and providing a large suite of powerful controls that do everything from accept simple input to display complex, interactive, data-bound grids.

Occasionally you may run into a situation where you have a need for a reusable control that isn’t already implemented by the base set of controls that ship with ASP.NET. In that case, you can use C#, object-oriented programming, and existing ASP.NET classes to create your own custom controls to extend ASP.NET’s already powerful feature set. This chapter shows you how to create everything from simple user controls to complex, nested server controls that maintain their own view state.

Building User Controls

User controls are essentially miniature versions of a standard ASP.NET Web Form. They have markup source that is converted into a partial class as well as underlying code that combines with the markup code to produce an executable unit of user interface very similar to a Web Form.

If you want to create a control that you can reuse multiple times throughout your application and you want to do it quickly, creating a user control is probably your best option. The only real downside to user controls is that they don’t lend themselves to being reused among multiple projects. If you are creating a library of reusable controls that will be used by multiple applications or even by your own customers, you would be better served by using server controls (discussed in the next section).

To start with, create the most basic control: a control that displays "Hello World". Create a new ASP.NET application called ControlsDemo. Right-click the project and select Add New Item. Select Web User Control and call that control HelloWorld.ascx.

Set the source view of the page to the following code:

<%@ Control Language="C#" AutoEventWireup="true"
CodeFile="HelloWorld.ascx.cs" Inherits="HelloWorld" %>
Hello World

It’s a pretty simple control. The Control tag looks very similar to the Page tag that you find on standard pages. You can configure various options such as content caching using this tag.

To use this control on a page, go to the design view of any page in your web application and simply drag HelloWorld.ascx from the Solution Explorer onto the design surface. Unlike previous versions of ASP.NET, version 2.0 does not require you to manually register the control, as dragging the file into the designer autogenerates the following control registration at the top of the file:

<%@ Register Src="HelloWorld.ascx" TagName="HelloWorld" TagPrefix="uc1" %>


Note

This only works when dragging onto the design surface. If you drag a control from the Solution Explorer into an HTML view, you will end up with a URL pointing to that file, and not the registered control reference.


You can change the tag’s prefix if you like, but the control will appear on the .aspx page using the uc# prefix by default, as shown in the following line:

<uc1:HelloWorld ID="HelloWorld1" runat="server" />

When ASP.NET encounters a user control tag like the preceding one when rendering a page, it stops what it’s doing and renders the user control in place. This operation is a nested operation, so if that user control contains further user controls, those will be rendered in their appropriate relative positions. When you run the page with your “Hello World” control on it, you get a fairly predictable output that is shown in Figure 30.1.

Obviously you’re going to want to create more than just a control that displays simple text. In this next sample, you’ll create a user control that combines several child controls to create a reusable piece of UI functionality.

Start by adding a new web user control to the project called LabelledTextBox.ascx. Drag a Label and a TextBox into this control. The .ascx source should look something like this:

<%@ Control Language="C#" AutoEventWireup="true"
CodeFile="LabelledTextBox.ascx.cs" Inherits="LabelledTextBox" %>
<asp:Label ID="lblText" runat="server" />&nbsp;
<asp:TextBox ID="txtText" runat="server" />

Figure 30.1 A simple user control.

Image

Because the user control is just another class, you can expose properties on that class to control its behavior. For example, you can create properties on the user control that can be used to set properties on the Label and TextBox, as shown in the source for LabelledTextBox.ascx.cs:

Image

Properties on a custom ASP.NET control can be set programmatically or they can be set declaratively in the markup. The ASP.NET engine will take all declarative property assignments and try to match them to properties on the underlying class. Take a look at the following code that sets the Text and LabelText properties of the user control:

Image

You can also programmatically change property values on a web user control from within the code-behind (.cs file) for a page or parent control:

LabelledTextBox1.LabelText = "Enter your Favorite Color";

As mentioned earlier, an ASP.NET web user control functions exactly like a “mini” ASP.NET page, so you can leverage all of the skills you have developed for building ASP.NET pages and apply them to building ASP.NET web user controls.

Creating Server Controls

A server control trades off the ease of use of having separate UI and code elements by giving the developer tighter control of the rendering process. This control comes at a price, however: It is often more time-consuming to produce server controls than user controls. Despite the relative difficulty, many developers prefer using server controls because they are easy to share among multiple projects and the developer has precise control over the control’s output and its behavior. Server controls also have the advantage of being easily bundled and can be sold to other developers by component and control vendors.

Within the narrow scope of this single chapter, you will not get a thorough and comprehensive coverage of all aspects of creating server controls within ASP.NET. However, this next section will get you started creating those controls and possibly whet your appetite for a book like Stephen Walther’s ASP.NET 2.0 Unleashed (ISBN: 0672328232).

Before getting into the specifics of creating a custom server control, you should familiarize yourself with the capabilities of the WebControl class. You create custom server controls by creating classes that inherit from WebControl. Tables 30.1 and 30.2 contain a list of commonly used properties and methods of the WebControl class.

Table 30.1 WebControl Properties

Image

Table 30.2 WebControl Methods

Image

As you saw in the preceding example, you can define properties on a control class that can be set declaratively at design time or programmatically at runtime. With a custom server control, it is more difficult to determine the context of those properties because you don’t have editable access to the control tree at design time as you do with a web user control. To help the user figure out what each property means and how it should be used, there are several attributes that you can use to decorate a server control property. Some of the more common ones are

  • Bindable—This attribute indicates whether the associated property can be bound to a data source.
  • Category—This attribute indicates the category within the property editor in which the property should appear. For example, properties such as Font, ForeColor, and BackColor all show up in the Appearance category.
  • DefaultValue—This attribute indicates the default value of the property when no value has been supplied at design time or runtime.
  • Description—This attribute provides a long description of the property.
  • Localizable—This attribute indicates whether the property will have different values based on different cultural locations and language settings.

To follow along, add a new Class Library project to the solution in which the control website was created. Add a reference to System.Web from within this class library and you’re ready to start creating server controls in this library.

Add a new class to the class library called TextBoxButton. This class is going to be a server control that will contain a text box and a button to illustrate the principle of a custom server control with child controls. In addition, you will also see how to “bubble” events from within a server control up to the page in which the control resides.

Make sure the code for the TextBoxButton class looks like the code in Listing 30.1.

Listing 30.1 The TextBoxButton Class

Image

Image

Image

However tempting it may be, you should never instantiate new child controls from within a control’s constructor. It is often difficult to remember that the instantiation and configuration of controls is done in an entirely separate stage of the control life cycle than the rendering. Because of this, use the CreateChildControls method to establish the control tree and use the RenderContents method to make any specific changes to the child controls.

In Listing 30.1 the property definitions should be fairly self-explanatory. The property values are derived from property values on child controls, and thus require the use of the EnsureChildControls() method to make sure that the child controls exist before retrieving or setting their properties.

To let the page hosting the control respond to the event when a user clicks the nested button within TextBoxButton, you need to support a process called “bubbling.” When an event is fired and handled within one class and that class then publishes an event representing the same occurrence to another class, the event is considered to be “bubbled.” The phrase comes from an analogy related to bubbles rising to the surface of a liquid.

For this control to support event bubbling, it needs to publish an event using the following line of code:

public event EventHandler buttonClick;

When this control handles the Click event from the child Button control, it allows any container control to respond to the same event by bubbling it up one level:

void btn_Click(object sender, EventArgs e)
{
    if (buttonClick != null)
        buttonClick(sender, e);
}

Build the class library and then add a reference to the CustomControls project from the web application project. After building the solution this way, create a new Web Form. An extremely useful feature is that the Toolbox has detected the presence of a web control within an assembly in the solution and has added it in a category called “ControlsDemo Components” (assuming your web project is called ControlsDemo).

When you drag the control from the special category on the control Toolbox, you will see a preview of the control’s rendered output using default values. The Properties Editor panel will contain all of the custom properties that you defined on your control and will reflect the settings of the custom attributes applied to those properties, as shown in Figure 30.2.

Figure 30.2 Properties Editor panel for a custom server control.

Image

Using your knowledge of C#, object-oriented programming, the ASP.NET page life cycle, and the functionality and features of the WebControl class, you can create some very powerful controls.

Managing State Within Server Controls

With the introduction of ASP.NET 2.0, there are now two kinds of state management at the disposal of control developers: view state and control state. ASP.NET 2.0 makes a distinction between page-wide view state and control state to allow developers to turn off view state for an entire page to speed up performance, and selectively allow individual controls to maintain their state.

View state is a feature of ASP.NET that allows controls and the page itself to maintain state between requests by storing that state information in a hidden form variable. The contents of that hidden form variable are exposed through an instance of the StateBag class as the ViewState object. You can read and write name-value pairs using the following syntax:

int selectedIndex = ViewState["selectedIndex"];
ViewState["selectedIndex"] = comboBox1.SelectedIndex;

Although view state is an incredibly powerful tool and facilitates many things in ASP.NET that required a lot of tedious programming before ASP.NET was released, it can become a performance problem. For example, in ASP.NET 1.1, if a DataGrid was bound to several hundred rows of data, all of that data could end up in view state in order to avoid requerying the server. The nature of the view state hidden form variable led to incredibly large page sizes in this situation. Before ASP.NET 2.0, control builders either had to rely on view state or they had to use some other mechanism to maintain state between page requests.

The size of view state became a burden for controls that only needed to maintain small amounts of data between requests. With ASP.NET 2.0, control state can be used to maintain small pieces of information between requests, whereas view state is still useful for storing large amounts of data.

Control state management follows a different model than view state. Rather than accessing the name/value pairs stored in the ViewState object, any control that you build should override the LoadControlState(object) and SaveControlState() methods that are now part of the WebControl class.

The LoadControlState method is used to restore the control’s state from the object supplied as a method parameter. SaveControlState is used to return the object that constitutes the control’s state. These two methods combined allow the control to manage its own state without resorting to the ViewState object. Keep in mind that control state should only be used for small values and control state cannot be disabled. Even if the page or the control has had EnableViewState set to false, control state code will still work properly.

Listing 30.2 contains the source code for a custom server control named StateControl. It is a control that uses ViewState for storing a list of strings to which the control is bound and it uses ControlState for storing the currently selected index to highlight an individual string.

Listing 30.2 Custom Control Using View State and Control State

Image

Image

Image

The DataSource property makes use of the ViewState object to retrieve the data from view state if it wasn’t set during the page load. This allows the control to maintain the list of strings between page requests without requiring the host page to set them every time. The LoadControlState and SaveControlState overridden methods load and store the value of selectedIndex, and the DataBind() method uses that value to selectively determine which row to highlight in light blue. Finally, the following line tells the page framework that this control takes part in control state persistence:

Page.RegisterRequiresControlState(this);

Without this line of code, ASP.NET will not restore the control’s state. Listing 30.3 contains the code for the page that hosts this control.

Listing 30.3 A Page Hosting a State-Persisting Control

Image

Image

This code illustrates how you can create custom server controls that take part in view state and control state.

Summary

Despite the vast array of functionality provided by the controls that come with ASP.NET 2.0, there will undoubtedly be occasions when developers need to create their own controls. These controls can be simple user controls or custom server controls. This chapter showed you how easy it can be to create both types of controls, as well as how to manage state from within controls. After reading this chapter, you should be familiar with the concepts involved in creating user controls and know enough to continue your learning with a more detailed reference if you plan on creating more powerful and complex controls.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.16.66.237