ASP.NET Core Server Controls

Overview

It does not matter how slowly you go so long as you do not stop.

-Confucius

ASP.NET pages are made of code, markup tags, literal text, and server controls. Based on the request, the server controls generate the right markup language. The ASP.NET runtime combines the output of all controls and serves the client a page to display in a browser.

The programming richness of ASP.NET springs from the wide library of server controls that covers the basic tasks of HTML interaction—for example, collecting text through input tags—as well as more advanced functionalities such as grid-based data display. In the ASP.NET world, more advanced and very specific controls ensure all basic tasks and common functionalities are available. The AdRotator and Calendar controls are two illustrious examples.

Key to ASP.NET control programming is the runat attribute. If a control is declared without the runat attribute, it is considered plain text and is output verbatim. If a control contains the runat attribute set to the value of "server", ASP.NET creates and handles an instance of the control while processing the page on the server. All this happens transparently to the user and the programmer as part of the ASP.NET runtime infrastructure.

In Chapter 1, we identified two main families of server controls—HTML server controls and Web server controls. In ASP.NET, these controls are typically referred to as HTML controls and Web controls. HTML controls map to HTML tags and are implemented through server-side classes whose programming interface faithfully represents the standard set of attributes for the corresponding HTML tag. Web controls, in turn, are a more abstract library of controls in which adherence to HTML syntax is much less strict. As a result, Web and HTML controls share a large common subset of functionalities and, in spite of a few exceptions, we could say that Web controls, functionally speaking, are a superset of HTML controls. Web controls also feature a richer development environment with a larger set of methods, properties and events.

As we'll see in more detail in the following pages, a second and more thoughtful look at the characteristics of the server controls in ASP.NET reveals the existence of more than just two families of controls. In real-world ASP.NET applications, you'll end up using controls from at least the following categories: HTML controls, Web controls, validation controls, data-bound controls, user controls, mobile controls, and custom controls. Validation controls are a special subset of Web controls and deserve to be treated in a separate section. Data-bound controls are not a category per se, with features that make them different from HTML or Web controls. Data-binding, instead, refers to the control's capability of connecting some of its properties to particular data sources. Hence, data-bound controls fall into any of the previously listed groups of server controls, but deserve a section of their own because of their importance and frequent use. User controls—also referred to as pagelets in relatively outdated literature—are visual aggregates of existing Web and HTML controls that appear as individual, encapsulated, programmable controls to external callers. Mobile controls are used when creating Web applications that target mobile devices. Custom controls refer to server controls you create that derive from a base control class.

In this chapter, we'll cover HTML controls, Web controls, validation controls, and data-bound controls. We'll cover user controls in Chapter 10, mobile controls in Chapter 11, and custom controls in Chapter 18 through Chapter 20.

Generalities of ASP NET Server Controls

All ASP.NET server controls, including HTML and Web controls plus any custom controls you create or download, descend from the Control class. The class is defined in the System.Web.UI namespace and, as we discussed in Chapter 2, also represents the foundation of all ASP.NET pages. The Control class is declared as follows:

public class Control : IComponent, IDisposable, IParserAccessor, IDataBindingsAccessor

The IComponent interface defines the way in which the control interacts with the other components running in the common language runtime (CLR), whereas IDisposable implements the common pattern for releasing unmanaged resources. The IParserAccessor interface enables the control to work as the container of child controls. Finally, the IDataBindingsAccessor interface makes the control capable of supporting data-binding expressions at design time. The IDataBindingsAccessor interface defines a read-only collection—the DataBindings property—that contains all the data bindings for the controls available to rapid application development (RAD) designers such as Microsoft Visual Studio .NET. Note that the collection of data bindings exist only at design time and, as such, is useful only if you write a RAD designer for the control. (Design-time features are discussed further in Chapter 21.)

Properties of the Control Class

The properties of the Control class have no user interface–specific features. The class, in fact, represents the minimum set of functionalities expected from a server control. The list of properties for the Control class is shown in Table 3-1.

Table 3-1: Properties of a Server Control

Property

Description

ClientID

Gets the ID assigned to the control in the HTML page. The string is a slightly different version of the UniqueID property. UniqueID can contain the colon symbol (:), but this symbol is not allowed in ClientID and is replaced with the underscore (_).

Controls

Gets a collection filled with references to all the child controls.

EnableViewState

Gets or sets whether the control should persist its view state—and the view state of any child controls across multiple requests—to the configured location (for example, HTML hidden field, Web server memory, server-side databases or files).

ID

Gets or sets the name that will be used to programmatically identify the control in the ASP.NET page.

NamingContainer

Gets a reference to the control's naming container. A naming container is the namespace to which the control belongs. If the control doesn't define its own naming space, a reference to the parent control (or the page) is returned.

Page

Gets a reference to the Page instance that contains the control.

Parent

Gets a reference to the parent of the control in the page hierarchy.

TemplateSourceDirectory

Gets the virtual directory of the host page.

UniqueID

Gets a hierarchically qualified ID for the control.

Visible

Gets or sets whether ASP.NET has to render the control.

The Control class is the ideal base class for new controls that have no user interface and don't require style information.

Identifying a Server Control

The client ID of a control is generated from the value of the UniqueID property—the truly server-side identifier that ASP.NET generates for each control. The contents of the ClientID property differ from UniqueID simply in that all occurrences of the colon symbol (:) are replaced with the underscore (_). Colons in the UniqueID string are possible only if the control belongs to a naming container different than the current one—typically, the page.

ASP.NET generates the value for the UniqueID property based on the value of the ID property that the programmer indicates. If no ID has been specified, ASP.NET autogenerates a name such as _ctlX, where X is a progressive 0-based index. If the control's naming container is the host page, UniqueID simply takes the value of ID. Otherwise, the value of ID is prefixed with the string representing the naming container and the result is assigned to UniqueID.

  Note

For performance reasons, ASP.NET caches into a static array defined on the Control class the strings ranging from _ctl0 to _ctl127. These autogenerated and cached IDs will be used for the first 128 controls in the page defined with an empty ID string. If you have more than 128 controls with an empty ID, the ID string is generated on the fly for each control instance.

Visibility of a Server Control

If you set Visible to false, ASP.NET doesn't generate any HTML code for the control. However, having Visible set to false doesn't really mean the control's code can't output text. The control is still an active object that exposes methods and handles events. If a method, or an event handler, sends text directly to the output console through Response.Write, this text will be displayed to the user anyway. A control with the Visible attribute set to false is still part of the page and maintains its position in the control tree.

Methods of the Control Class

The methods of the Control class are listed and described in Table 3-2.

Table 3-2: Methods of a Server Control

Method

Description

DataBind

Fires the OnDataBinding event and then invokes the DataBind method on all child controls

Dispose

Gives the control a chance to perform clean-up tasks before it gets released from memory

FindControl

Looks for the specified control in the collection of child controls. Child controls belonging to a different naming container are not sought.

HasControls

Indicates whether the control contains any child controls

RenderControl

Generates the HTML output for the control

ResolveUrl

Resolves a relative URL to an absolute URL based on the value passed to the TemplateSourceDirectory property

At the Control class level, the DataBind method works recursively and simply loops through all the child controls and calls DataBind on each of them. On derived data-bound controls, the method resolves all data-binding expressions and updates the status of the control itself.

Events of the Control Class

The Control class also defines a set of base events that all server controls in the .NET Framework support, as described in Table 3-3.

Table 3-3: Events of a Server Control

Event

Description

DataBinding

Occurs when the DataBind method is called on a control and the control is binding to a data source

Disposed

Occurs when a control is released from memory—the last stage in the control life cycle

Init

Occurs when the control is initialized—the first step in the life cycle

Load

Occurs when the control is loaded into the page. Occurs after Init.

PreRender

Occurs when the control is about to render its content

Unload

Occurs when the control is unloaded from memory

All server controls are rendered to HTML using the RenderControl method and, when this happens, the PreRender event is fired.

HTML Controls

In ASP, HTML tags inserted in the layout of the server page were treated as opaque text and output to the client verbatim. This behavior has been entirely maintained in ASP.NET. A big difference, though, is that in ASP.NET, by simply adding the runat attribute with a value of "server", you can bring to life otherwise-dead HTML text. Once transformed into a living instance of a server-side component, the original tag can be configured programmatically using an object-oriented approach. By design, HTML controls expose a set of methods and properties that carefully reflect the HTML syntax. For example, to set the default text of an input form field, you use a property named Value—case does matter in C# but not in Microsoft Visual Basic .NET—instead of the more expressive Text. The name of the server control is determined by the value of the id attribute. The following code snippet shows how to define a server-side input tag named lastName:

 

The tag declaration does not include an explicit and static value for the Value attribute, which can be configured programmatically as follows:

void Page_Load(object sender, EventArgs e) { lastName.Value = "Esposito"; }

After being processed by the ASP.NET runtime, the preceding declaration generates the following HTML code:

 

Notice that a server-side id attribute expands to a pair of HTML attributes—name and id. Be aware that this happens for browser compatibility. In no way, does this mean that on the server name and id can be interchangeably used to name the server instance of the control. The name of the server control instance is given by id. If you specify both name and id on a server-side tag, the value assigned to name will be silently overridden.

Generalities of HTML Controls

The .NET Framework provides predefined server controls for commonly used HTML elements such as

, , and , as well as for tables, images, and hyperlinks. All the predefined HTML server controls inherit from the same base class—the HtmlControl class. In addition, each control then provides its own set of specific properties and its own events. Controls typically supply properties that allow you to manipulate the HTML attributes programmatically from within server code. HTML controls integrate well with data-binding and the ASP.NET state maintenance, and they also provide full support for postback events and client scripting. For example, for a button that gets clicked, you can have some JavaScript code running on the client responding to the onclick event as well as some code that handles the event on the server if the page posts back as the result of that event. HTML controls are defined in the System.Web.UI.HtmlControls namespace. As mentioned, most HTML tags have a direct class counterpart in the .NET Framework, but not all do. HTML elements that don't map to a made-to-measure class are rendered through the HtmlGenericControl class and have attributes set using generic collections rather than direct properties. Generic controls include , , , , , and . In general, you should bear in mind that every element that can appear in an HTML page can be marked as runat="server" and programmed and styled on the server. The HtmlControl Base Class The HtmlControl class inherits from Control and defines the methods, properties, and events common to all HTML controls. Actually, many properties and all methods and events are simply inherited from the base class. Table 3-4 shows the list of properties specific to HTML controls. Table 3-4: Specific Properties of an HTML Control Property Description Attributes Gets a collection object representing all the attributes set on the control with the corresponding value Disabled Gets or sets a Boolean value, which indicates whether the HTML control is disabled Style Gets a collection object representing all CSS properties applied to the control TagName Gets the name of the HTML tag behind the control A disabled HTML server control is visible and always gets generated as HTML code. If the Disabled property is set to true, the disabled HTML attribute is inserted in the HTML output for the control. As mentioned earlier, if the Visible property is set to false, HTML is not generated for the control. Working with HTML Attributes Each HTML control features more properties than those listed in Table 3-4. Properties of HTML server controls map to HTML attributes, and the values assigned to the properties are replicated in the HTML output. For controls that don't have an HTML direct counterpart, the Attributes collection is used to set attributes on the resulting HTML tag. This collection can also be used to set properties not mapped by the control's interface and, if needed, to define custom HTML attributes. Any content of the Attributes collection is managed as a string. Given the following HTML code snippet, let's see how to programmatically set some attributes on the tag: You bind a JavaScript script to the onload attribute of the tag. The resulting HTML code that the browser displays is as follows: The Attributes property is rendered through a special type of class named AttributeCollection. In spite of the name, the content of the class is not enumerable using the for...each statement because the IEnumerable interface is not supported. The content is instead stored in a StateBag object—the same class used for the ASP.NET view state—which is enumerable. However, the enumerability of the internal data container is exposed to the world. The AttributeCollection class provides ad hoc methods to render attributes of a text writer object and to add and remove elements. Interestingly, if you add an attribute named Style, the class is smart enough to reroute the assigned content to the Style collection. Hierarchy of HTML Controls HTML controls can be grouped into two main categories—container and input controls. One control, though, cannot be easily catalogued in either of the two groups—the HtmlImage control, which is the ASP.NET counterpart of the tag. Figure 3-1 shows the tree of HTML controls. Figure 3-1: A diagram that groups all HTML controls. Notice that the controls in the figure are not grouped based on discretionary and perhaps arguable rules; instead they are grouped simply by looking at the base class of each control. The HtmlImage control forms a group of its own because it inherits directly from HTMLControl without any other intermediary class. The input controls category includes all possible variations of the tag, from submit buttons to check boxes and from text fields to radio buttons. The container controls category lists anchors, tables, forms, and in general, all HTML tags that might contain child elements.

HTML Container Controls

The base class for container controls is the HtmlContainerControl class, which descends directly from HtmlControl. The HTML elements addressed by this tag are elements that must have a closing tag—that is, forms, selection boxes, and tables, as well as anchors and text areas. Compared to the HtmlControl class, a container control features a couple of additional string properties—InnerHtml and InnerText.

Both properties manipulate the reading and writing of literal content found between the opening and closing tags of the tag. Note that you cannot get the inner content of a control if the content includes server controls. InnerHtml and InnerText work only in the presence of all literal content. The tag itself is not considered for the output. Unlike InnerText, though, InnerHtml lets you work with HTML rich text and doesn't automatically encode and decode text. In other words, InnerText retrieves and sets the content of the tag as plain text, whereas InnerHtml retrieves and sets the same content but in HTML format.

Table 3-5 lists the HTML container controls defined in ASP.NET 1.1.

Table 3-5: HTML Container Controls

Class

Description

HtmlAnchor

Represents an HTML anchor—specifically, the tag.

HtmlButton

Represents the HTMLtag. Theelement is defined in the HTML 4.0 specification and supported only in Internet Explorer version 4.0 and later.

HtmlForm

Represents the tag, but can be used only as a container of interactive server controls on a Web page. Cannot really be used to create HTML forms programmable on the server.

HtmlGenericControl

Represents an HTML tag for which the .NET Framework does not provide a direct class. Sample tags include , ,

,
,
, and . You program these controls using the Attributes collection and set attributes indirectly.

HtmlSelect

Represents the tag—that is, an HTML selection box.

HtmlTable

Represents an HTML table—specifically, the

tag.

HtmlTableCell

Represents the

HTML tag—that is, a cell in a table.

HtmlTableRow

Represents the

HTML tag—that is, a row in a table.

HtmlTextArea

Represents a multiline text box, and maps the HTML tag.

Note that the HtmlButton control is different than HtmlInputButton, which represents the button variation of the tag. We'll say more about buttons in the next section while discussing the Web controls. Server-side forms play a key role in the economy of ASP.NET applications, as they are the means for implementing postbacks and guaranteeing state maintenance. For this reason, the HtmlForm control is not simply a form element you can program on the server. In particular, the HtmlForm hides the Action property and cannot be used to post content to a page different than the content that generated the HTML for the browser. We will cover HTML forms in great detail in Chapter 4.

Navigating to a URL

The HtmlAnchor class is the programmatic way of accessing and configuring the tag. With respect to the other container controls, the HtmlAnchor class provides a few extra properties, such as HRef, Name, Target, and Title. The HRef property sets the target of the hyperlink and can be used to navigate to the specified location. The Name property names a section in the ASP.NET page that can be reached from anywhere on the same page through #-prefixed HRefs. The following code demonstrates a bookmarked anchor named MoreInfo:

<a name="MoreInfo"></a>

This anchor can be reached using the following hyperlink:

<a name="MoreInfo"></a>Get More Info

The Target property identifies the target window or the frame where the linked URL will be loaded. Common values for Target are _self, _top, _blank, and _parent, as well as any other name that refers to a page-specific frame. Although the feature is mostly browser dependent, you should always consider these special names as lowercase. Finally, the Title property contains the text that is displayed as a ToolTip when the mouse hovers over the anchor's area.

Handling Events on the Server

In addition to being used for navigating to a different page, the anchor control—as well as the HtmlButton control—can be used to post back the page. Key to this behavior is the ServerClick event, which lets you define the name of the method that will handle, on the server, the event generated when the user clicks the control. The following code demonstrates an anchor in which the click event is handled on both the client and server:

Click

The onclick attribute defines the client-side event handler written using JavaScript; the onserverclick attribute refers to the server-side code that will run after the page posts back. Of course, if both event handlers are specified, the client-side handler executes first before the post back occurs.

The HtmlSelect Control

The HtmlSelect control represents a list of options from which you choose one or more. You control the appearance and behavior of the control by setting the Size and Multiple properties. The Size property specifies the number of rows to be displayed by the control, whereas the Multiple property indicates whether more than one item can be selected in the control. Internal items are grouped in the Items collection, and each element is represented by a ListItem object. Interestingly, the ListItem class is not defined in the HtmlControls namespace but lives instead in the WebControls namespace. To specify the text for each selectable item, you can either set the Text property of the ListItem or simply define a series oftags within the opening and closing tags of the element.

By default, the HtmlSelect control shows up as a drop-down list. However, if multiple selections are allowed or the height is set to more than one row, the control is displayed as a list box. The index of the selected item in a single-selection control is returned through the SelectedIndex property. If the multiple selection is enabled, you just loop through the Items collection and check the Selected property on individual list items.

The HtmlSelect control supports data binding through additional properties. The DataSource property lets you set the data source, which can be any .NET object that implements the ICollection interface. If the data source contains multiple bindable tables (for example, a DataSet object), by using the DataMember property you can choose a particular one. Finally, the DataTextField and DataValueField properties are used to bind the list item's Text and Value properties to columns in the data source.

HTML Tables

In ASP.NET, HTML tables provide a minimum set of functions when rendered using the HtmlTable control. In most cases, you don't need to use server-side tables because you typically rely on richer list and grid controls to do the job of displaying tables or records. So you resort to tables when you need to define a fixed layout for graphical elements of the page, but this is not a feature that requires a server-side table.

However, server-side tables are not as powerful as pure HTML tables—which are created by using the

,
element:

 

Joe Users
Bob Whosthisguy

By design, an HtmlTable control can have only children of the HtmlTableRow class. Any attempt to programmatically add other table elements, such as a

, will generate an exception.

The HtmlTextArea Control

The HtmlTextArea control corresponds to the HTML element and allows you to programmatically create and configure a multiline text box. The HtmlTextArea class provides the Rows and Cols properties to control the number of rows and columns of the text box. The Value property can be used to assign some text to display in the control area.

The HtmlTextArea class also provides a ServerChange event that fires during a postback and allows you to validate on the server the data contained in the control. Note that the HtmlTextArea control does not fire the event itself and does not directly cause the page to post back. Rather, when the page posts back in response to a click on a link or submit button, the HtmlTextArea control intervenes in the server-side chain of events and gives the programmer a chance to run some code if the internal content of the control is changed between two successive postbacks.

All ASP.NET controls that, like HtmlTextArea, implement the IPostBackDataHandler interface can invoke user-defined code when the control's internal state changes. In particular, controls can fire custom events by overriding the RaisePostDataChangedEvent method on the aforementioned interface. The following pseudocode shows what happens in the method's implementation of HtmlTextArea:

void System.Web.UI.IPostBackDataHandler.RaisePostDataChangedEvent() { this.OnServerChange(EventArgs.Empty); }

Finally, note that the control raises the event only if the state has changed between two successive posts. To determine whether that has happened, the control needs to track the content it had the time before. This value can be stored only in the view state. Of course, the ServerChange won't even fire if you disable the view state for the host page or the control.

HTML Input Controls

In HTML, the element has several variations and can be used to provide a submit button as well as a check box or text box. In ASP.NET, each possible instance of the element is mapped to a specific class. All input classes derive from the HtmlInputControl class. HtmlInputControl is the abstract class that defines the common programming interface for all input controls. The class inherits from HtmlControl and simply adds three custom properties to the inherited interface: Name, Type, and Value.

The Name property returns the name assigned to the control. In ASP.NET, this property is peculiar because, although marked as read/write, it actually works as a read-only property. The get accessor returns the control's UniqueID property, while the set accessor is just void. As a result, whatever value you assign to the property, either programmatically or declaratively, is just ignored and no exception or compile error is ever thrown.

The Type property mirrors the type attribute of the HTML input elements. The property is read-only. Finally, the Value property is read/write and represents the content of the input field.

Table 3-6 lists the HTML input controls defined in ASP.NET 1.1.

Table 3-6: HTML Input Controls

Class

Description

HtmlInputButton

Represents the various flavors of a command button supported by HTML. Feasible values for the Type attribute are button, submit, and reset.

HtmlInputCheckBox

Represents an HTML check box—that is, the tag with a type equal to checkbox.

HtmlInputFile

Represents the file uploader—that is, the tag with a type equal to file.

HtmlInputHidden

Represents a hidden buffer of text data—that is, the tag with a type equal to hidden.

HtmlInputImage

Represents a graphic button—that is, the tag with a type equal to image. Note that this tag is supported by all browsers.

HtmlInputRadioButton

Represents a radio button—that is, the tag with a type equal to radio.

HtmlInputText

Represents a text field—that is, the tag with a type of either password or text.

The hidden and text-input controls are nearly identical, and the contents of both are posted back. They basically differ only in that hidden fields are not displayed and, subsequently, don't provide some UI-related properties such as MaxLength and Size.

Command Buttons

The HtmlInputButton class is the most flexible button class in the .NET Framework. It differs from the HtmlButton class we encountered earlier in that it renders through the tag rather than the Internet Explorer–specific tag. This fact ensures for the control much wider support from browsers.

The HTML input button controls support the ServerClick event, which allows you to set the code to run on the server after the button is clicked. Note that if you set the button type to Button and the ServerClick event handler is specified, the control automatically adds the postback script code to the onclick HTML attribute. In this way, any click causes the page to post back and the code to execute. Let's consider the following ASP.NET code:

 

The corresponding HTML code is as follows:

 

The client-side __doPostBack script function is the standard piece of code generated by ASP.NET to implement the postback. The code is actually emitted through a call to the RegisterPostBackScript method of the Page class. If the button type is set to Submit—that is, a value that would always cause a postback—no client-side script code is generated and the onclick attribute is not set.

  Note

The HtmlInputImage control supports a nearly identical pattern for handling server-side events and validation. The HtmlInputImage control features a few more properties specific to the image it shows. In particular, you can set the alternate text for the image, the border, and the alignment with respect to the rest of the page. The ServerClick event handler has a slightly different form and looks like the following:

void ImageClickEventHandler(object sender, ImageClickEventArgs e);

When an image button is clicked, the coordinates of the click are determined by using the X and Y properties of the ImageClickEventArgs data structure.

Controlling Validation

The HtmlInputButton class, as well as the HtmlButton class, support a Boolean property named CausesValidation. The property indicates whether the content of the input fields should be validated when the button is clicked. By default, the property is set to true, meaning the validation always takes place. We'll examine data validation later in the chapter. For now, it suffices to say, you can programmatically enable or disable the validation step by using the CausesValidation property.

Typically, you might want to disable validation if the button that has been clicked doesn't perform a concrete operation but simply clears the user interface or cancels an ongoing operation. By design, in fact, server-side page validation takes place just before the ServerClick event handler is executed. Setting the CausesValidation property to false is the only means you have to prevent an unnecessary validation.

Detecting State Changes of Controls

Earlier in this chapter, while discussing the features of the HtmlTextArea control, we ran into the ServerChange event and described it as the mechanism to detect and validate changes in the control's state between two successive postbacks. The ServerChange event is not an exclusive feature of the HtmlTextArea control but is also supported by other input controls such as HtmlInputCheckBox, HtmlInputRadioButton, HtmlInputHidden, and HtmlInputText. Let's look at an example in which we use the ServerChange event to detect which elements have been checked since last time the control was processed on the server.

We build a page with a list of check boxes and a button to let the user post back to the server when finished. Notice, in fact, that neither the HtmlInputCheckBox control nor any other input control except buttons, post back to the server when clicked. For this reason, you must provide another control on the Web page that supports posting to the server—for example, an HtmlButton or an HtmlInputButton control. The following code implements the page shown in Figure 3-2:

Figure 3-2: The ServerChange event fires only if the status of the control has changed since the last time the control was processed on the server.

One Two Three

The ServerChange event is fired only if the state of the control results changed after two postbacks.

By implementing the IPostBackDataHandler interface, each server control takes a chance to update its current state with data posted by the client. The ASP.NET runtime invokes LoadPostData on each control that implements the interface.

public bool LoadPostData(string postDataKey, NameValueCollection postCollection);

The first argument of LoadPostData is the client ID of the control; the second argument is a name-value collection that contains the posted data. Posted data can either be Request.Form or Request.QueryString depending on the form's method. Each control compares the value posted by an HTML element with the same ID with the contents of a particular property. It is Value for text boxes and Checked for check boxes. The posted value is obtained using the postDataKey string as a key to access the values stored in the collection.

Controls that implement the IPostBackDataHandler interface use a boilerplate piece of code to implement the LoadPostData method. Basically, the method updates the key property of the control with the posted value. The following code shows how LoadPostData works for the HtmlInputText control:

bool LoadPostData(string postDataKey, NameValueCollection postColl) { string oldValue; string postedValue; // At this point, the view state has been restored oldValue = this.Value; // Get the posted value for the HTML element with the same // ID as the control postedValue = postColl[postDataKey]; // Compare the posted value with Text and updates if needed if (oldValue != postedValue) { this.Value = postedValue; return true; } // Return a Boolean value denoting whether the state has changed return false; }

LoadPostData returns true if the state of the control changes as a result of the post back—that is, if the user generated a new state for the control. For this infrastructure to work, it is key that the value of the server control's UniqueID property be assigned to the name attribute of the HTML element. Otherwise, the ASP.NET runtime will not be able to handle postback data for that control.

The ASP.NET runtime tracks all the controls that return true to LoadPostData and then invokes the RaisePostDataChangedEvent method for each of them—the second method on the IPostBackDataHandler interface. The following code snippet reports what that method does for the HtmlInputText control:

// System.Web.UI.IPostBackDataHandler void RaisePostDataChangedEvent() { this.OnServerChange(EventArgs.Empty); }

For the HtmlInputCheckBox control in the preceding sample, a change of state occurs whenever the Checked property changes. Note that a nearly identical mechanism exists for Web controls.

Uploading Files

The HtmlInputFile control is the HTML tool for uploading files from a browser to the Web server. Note that file upload requires Internet Explorer version 3.0 or newer. To exploit the HtmlInputFile control in a form, you should first set the server form's Enctype property to multipart/form-data.

 

The way in which the HtmlInputFile control is rendered to HTML is browser- specific, but it normally consists of a text box and a Browse button. The user selects a file from the local machine and then clicks the button to submit the page to the server. When this occurs, the browser uploads the selected file to the server. Prior to ASP.NET, a server-side process—the posting acceptor—was required to run in the background to handle multipart/form-data submissions. In ASP.NET the role of the posting acceptor is no longer necessary as it is carried out by the ASP.NET runtime itself.

On the server, the file is parked into an object of type HttpPostedFile and stays there until explicitly saved to disk. The HttpPostedFile object provides properties and methods to get information on an individual file and to read and save the file. The following code shows how to save a posted file to disk:

upLoader.PostedFile.SaveAs(serverFile);

You can also use the InputStream property of the HttpPostedFile object to read the posted data without creating a disk file. The HtmlInputFile control also allows you to restrict the file types that can be uploaded to the server. You do this by setting the Accept property with a comma-separated list of MIME types.

  Caution

When you use the SaveAs method, you should pay attention to specify the full path to the output file. If a relative path is provided, ASP.NET attempts to place the file in the system directory. This practice might result in an access-denied error. Furthermore, make sure to provide write permission for the account used by ASP.NET for the directory where you want to store the file.

ASP.NET exercises some control on the amount of data being uploaded. The maxRequestLength attribute in the section of the configuration file sets the maximum allowable file size. An error is generated in the browser when the file exceeds the specified size—4 MB by default. Uploading large files might also generate another runtime error due to an excessive consumption of system memory. As we've seen in Chapter 2, when more than 60% of the available RAM is consumed the ASP.NET runtime recycles the worker process (aspnet_wp.exe). Of course, this fact breaks the upload process. To avoid this error, you should increase the value of the memoryLimit attribute in the element of the configuration file for the application.

The HtmlImage Control

The HtmlImage class is the ASP.NET counterpart of the tag. You can use it to configure on the server the display of an image. Possible parameters you can set are the size of the image, the border, and the alternate text. An instance of the HtmlImage is created only when the runat attribute is added to the tag. If you simply need to display an image within a page, and the image is not dynamically determined or configured, there is no need to resort to the HtmlImage control, which would add unnecessary overhead to the page. The following code snippet shows how to configure a server-side tag called to display an image whose name is determined based on run-time conditions.

theImg.Width = 100; theImg.Height = 100; theImg.src=GetImageUrl(Request);

The HtmlImage control should be used to programmatically manipulate the image to change the source file, the width and height, or the alignment of the image relative to other page elements. The majority of properties of the HtmlImage control are implemented as strings, including Src—the URL of the image—and Align. Feasible values of Align are only a small set of words such as left, right, top, and so forth. These words would have been more appropriately grouped in a custom-enumerated type, thus providing for a strongly typed programming model. If you think so, too, you just grabbed the gist of the difference between HTML and Web server controls! HTML controls just mirror HTML tags; Web controls attempt to provide a more consistent and effective programming interface by exploiting the characteristics of the .NET Framework.

Literal Controls

Literal controls are a special type of server control that ASP.NET creates and uses whenever it encounters plain text that doesn't require server-side processing. In general, everything that appears in the context of an ASP.NET page is treated like a control. If a tag includes the runat="server" attribute, ASP.NET creates an instance of a specific class; otherwise, if no runat attribute has been specified, the text is compiled into a LiteralControl object. Literal controls are simple text holders that are added to and removed from pages using the same programming interface defined for other server controls.

Web Controls

Web controls are defined in the System.Web.UI.WebControls namespace and represent an alternative approach to HTML server controls. Like HTML controls, Web controls are server-side components that spring to life thanks to the runat="server" attribute. Unlike HTML controls, Web controls are designed from scratch without needing to be compliant with the HTML syntax, but generate valid HTML. For this reason, they sometimes appear to be more consistent and abstract in the API design and richer in functionality. When hosted in .aspx pages, Web controls are characterized by the asp namespace prefix.

To a large degree, Web controls and HTML controls overlap and generate almost the same client code, although they do it through different programming interfaces. For example, the Web controls namespace defines the TextBox control and makes it available through the tag; similarly, the HTML controls namespace provides the HtmlInputText control and declares it using the tag. The output that both produce is nearly identical. Using either is mostly a matter of preference; only in a few cases will you run into slight functionality differences. Using Web controls gives you a far richer development model and exception management.

Generalities of Web Controls

The WebControl class is the base class from which all Web controls inherit. The class defines several properties and methods that are shared, but not necessarily implemented, by derived controls. Many of the properties have the look and feel of the controls and are subject to browser and HTML version. For example, although all Web controls provide the ability to define a border, not all underlying HTML tags actually support a border.

Properties of Web Controls

Table 3-7 lists the properties available on the WebControl class.

Table 3-7: Specific Properties of Web Controls

Property

Description

AccessKey

Gets or sets the letter to press (together with ALT) to quickly set focus to the control in a Web form. Supported on Internet Explorer 4.0 and newer.

Attributes

Gets the collection of attributes that do not correspond to properties on the control. Attributes set in this way will be rendered as HTML attributes in the resulting page.

BackColor

Gets or sets the background color of the Web control.

BorderColor

Gets or sets the border color of the Web control.

BorderStyle

Gets or sets the border style of the Web control.

BorderWidth

Gets or sets the border width of the Web control.

ControlStyle

Gets the style of the Web server control. The style is an object of type Style.

ControlStyleCreated

Gets a value that indicates whether a Style object has been created for the ControlStyle property.

CssClass

Get or sets the cascading style sheet (CSS) class associated with the client.

Enabled

Gets or sets whether the control is enabled.

Font

Gets the font properties associated with the Web control.

ForeColor

Gets or sets the foreground color of the Web control mostly used to draw text.

Height

Gets or sets the height of the control. The height is expressed as a member of type Unit.

Style

Gets a CssStyleCollection collection object made of all the attributes assigned to the outer tag of the Web control.

TabIndex

Gets or sets the tab index of the control.

ToolTip

Gets or sets the text displayed when the mouse pointer hovers over the control.

Width

Gets or sets the width of the control. The width is expressed as a member of type Unit.

The ControlStyle and ControlStyleCreated properties are used primarily by control developers, while the Style property is what application developers would typically use to set CSS attributes on the outer tag of the control. The Style property is implemented using an instance of the class CssStyleCollection. The class is a simple collection of string values—the values you set either declaratively or programmatically through the Style property. The ControlStyle property, on the other hand, evaluates to an object of type Style—a class that encapsulates the appearance properties of the control. In other words, the Style class works as the repository of the graphical and cosmetic attributes that characterize all Web controls. All properties are strongly typed. In contrast, the CssStyleCollection class is just the collection of CSS styles defined in the tags. The Style class groups together some of the properties that were shown in Table 3-7. The grouped properties are: BackColor, BorderColor, BorderStyle, BorderWidth, CssClass, Font, ForeColor, Height, and Width. Note that style values set through the CssStyleCollection class are not automatically reflected by the (strongly typed) values in the Style object.

Styling a Web Control

The style properties of a Web control can be programmatically manipulated to some extent. For example, in the Style class, you can count on a CopyFrom method to duplicate the object and you can take advantage of the MergeWith method to combine two style objects.

currentStyle.MergeStyle(newStyle);

The MergeWith method joins the properties of both objects. In doing so, it does not replace any property that is already set in the base object but limits itself to defining uninitialized properties. Finally, the Reset method clears all current attributes in the various properties of the style object.

Methods of Web Controls

The WebControl class supports a few particular methods that are not part of the Control interface. These methods are listed in Table 3-8.

Table 3-8: Specific Methods of Web Controls

Method

Description

ApplyStyle

Copies any nonempty elements of the specified style to the control. Existing style properties are overwritten.

CopyBaseAttributes

Imports from the specified Web control the properties AccessKey, Enabled, ToolTip, TabIndex, and Attributes. Basically, it copies all the properties not encapsulated in the Style object.

MergeStyle

Like ApplyStyle, copies any nonempty elements of the specified style to the control. Existing style properties are not overwritten, though.

RenderBeginTag

Renders the HTML opening tag of the control into the specified writer. The method is called right before the control's RenderControl method.

RenderEndTag

Renders the HTML closing tag of the control into the specified writer. The method is called right after the control's RenderControl method.

All these methods are rarely of interest to application developers. They are mostly designed to help control developers.

Core Web Controls

The set of Web controls can be divided in four main categories: core controls, validators, data-bound controls, and list controls. A fifth category of Web controls—iterative data-bound controls—will be examined separately in future chapters. In addition, the .NET Framework also provides a few miscellaneous controls that provide ad hoc functionalities and are as common on the Web as they are hard to catalogue. We'll cover these controls in the section "Miscellaneous Web Controls." Let's start off with a look at the core Web controls, which are described in Table 3-9.

Table 3-9: Core Web Controls

Control

Description

Button

Implements a submit push button through the tag.

CheckBox

Implements a check box through the tag.

HyperLink

Implements an anchor tag, and lets you specify either the location to jump to or the script code to execute.

Image

Implements a picture box through the tag.

Label

Represents a static, nonclickable piece of text. Implemented through the tag.

Panel

Implements an HTML container using the

block element. Note that in down-level browsers it is rendered as a
.

RadioButton

Implements a single radio button through the tag.

Table

Implements the outer table container. Equivalent to the HTML

element.

TableCell

A table cell; is equivalent to the HTML

element.

TableRow

A table row; is equivalent to the HTML

element.

TextBox

Implements a text box using the or tag as appropriate and according to the requested text mode. Can work in single-line, multiline, or password mode.

The Table class and its related classes allow you to build and configure an HTML table using the same abstract object model used for building other Web controls. The power of the Table class, though, is particularly evident when it comes to building tables programmatically with dynamic contents. No matter how complex the programming model is, all Web controls produce HTML for both up-level and down- level browsers.

Images and Image Buttons

The Image control displays an image on the Web page. The path to the image is set through the ImageUrl property. Image URLs can be either relative or absolute, with most programmers showing a clear preference for relative URLs, which make a Web site inherently easier to move. You can also specify alternate text to display when the image is not available. The property to use in this case is AlternateText. The image alignment with respect to other elements on the page is set by using the ImageAlign property. Feasible values are taken from the homonymous enum type.

The Image control is not a clickable component and is simply limited to displaying an image. If you need to capture mouse clicks on the image, use the ImageButton control instead. The ImageButton class descends from Image and extends it with a couple of events—Click and Command—that are raised when the control is clicked. The OnClick event handler provides you with an ImageClickEventArgs data structure that contains information about the coordinates for the location at which the image is clicked.

The OnCommand event handler makes the ImageButton control behave like a command button. A command button has an associated name that you can control through the CommandName property. If you have multiple ImageButton controls on the same page, the command name allows you to distinguish which one is actually clicked. The CommandArgument property can be used to pass additional information about the command and the control.

Check Boxes and Radio Buttons

Check boxes and radio buttons are implemented through the tag and the type attribute set to checkbox or radio. Unlike using the HTML control versions, the Web control versions of check boxes and radio buttons let you specify the associated text as a property. The HTML elements and the corresponding HTML controls lack an attribute whose content becomes the text near the check box or radio button. In HTML, to make the text near the check box or radio button clickable, you have to resort to the tag with the for attribute.

Check me

Neither the HtmlInputCheckBox nor the HtmlInputRadioButton control add a label, which leaves you responsible for doing that. These Web controls counterpart, on the other hand, are not bound to the HTML syntax and do precisely that—they automatically add a Text property, which results in an appropriate tag. For example, consider the following ASP.NET code:

 

It results in the following HTML code:

Check me

HyperLinks

The HyperLink control creates a link to another Web page and is typically displayed through the text stored in the Text property. Alternatively, the hyperlink can be displayed as an image; in this case, the URL of the image is stored in the ImageUrl property. Note that if both the Text and ImageUrl properties are set, the ImageUrl property takes precedence. In this case, the content of the Text property is displayed as a ToolTip when the mouse hovers over the control's area.

The NavigateUrl property indicates the URL the hyperlink is pointing to. The Target property is the name of the window or frame that will contain the output of the target URL.

Miscellaneous Web Controls

The WebControls namespace also includes a few controls that provide useful functionality that is common in Web applications. In particular, we'll examine the AdRotator control, which works like an advertisement banner, and the Calendar control, which is a flexible and highly interactive control used to specify a date.

The AdRotator Control

Abstractly speaking, the AdRotator control displays an automatically sized image button and updates both the image and the URL each time the page refreshes. The image to display and other information is read from an XML file written according to a specific schema. More concretely, you use the AdRotator control to create an advertisement banner on a Web Forms page. The control actually inserts an image and hyperlink in the page and makes them point to the advertisement page selected. The image is sized by the browser to the dimensions of the AdRotator control, regardless of its actual size. The following code shows a typical XML advertisement file:

6235.gif www.microsoft.com/MSPress/books/6235.asp Applied XML Programming with .NET 50 5727.gif www.microsoft.com/MSPress/books/5727.asp Building Web Solutions with ASP.NET 50

The root node contains multiple elements, one per each image to show. The syntax of the AdRotator control is as follows:

Pro ASP.NET (Ch03)

Dino Esposito's Books

In the XML advertisement file, you use the node to indicate the image to load and the node to specify where to go in case of a click. The node indicates the alternate text to use if the image is unavailable. Finally, indicates how often an image should be displayed in relation to other images in the advertisement file.

Once per roundtrip, the AdRotator control fires the server-side AdCreated event. The event occurs before the page is rendered. The event handler receives an argument of type AdCreatedEventArgs, which contains information about the image, the navigation URL, and the alternate text. The AdRotator control exposes a few custom properties, including Target to set the target of the hyperlink and AdvertisementFile to set the file with image names.

The Calendar Control

The Calendar control displays a one-month calendar and allows you to choose dates and navigate backward and forward through the months of the year. The control is highly customizable both for appearance and functionality. For example, by setting the SelectionMode property, you can decide what the user can select—that is, whether a single date, week, or month can be selected. Figure 3-3 provides a view of the Calendar control.

Figure 3-3: The Calendar control in action.

 

The VisibleDate property sets a date that must be visible in the calendar, while SelectedDate sets with a different style the date that is rendered as selected. The control also fires three ad hoc events: DayRender, SelectionChanged, and VisibleMonthChanged. The DayRender event signals that the control has just created a new day cell. You can hook the event if you think you need to customize the cell output. The SelectionChanged event fires when the selected date changes, while VisibleMonthChanged is raised whenever the user moves to another month using the control's selector buttons.

The Calendar control originates a roundtrip for each selection you make. Although it is cool and powerful on its own, for better performance you might also want to provide a plain text box for manually typing dates.

The Xml Control

The Xml control, defined by the tag, is used to output the content of an XML document directly into an ASP.NET page. The control can display the source XML as-is or as the results of an XSL transformation (XSLT). The Xml control is a sort of declarative counterpart for the XslTransform class and can make use of the .NET Framework XSLT transform class internally.

You use the Xml control when you need to embed XML documents in a Web page. For example, the control is extremely handy when you need to create XML data islands for the client to consume. The control lets you specify a document to work with and, optionally, a transformation to apply. The XML document can be specified in a variety of formats—an XML document object model, string, or file name. The XSLT transformation can be defined through either an already configured instance of the .NET Framework XslTransform class or a file name.

 

If you're going to apply some transformation to the XML data, you could also embed it inline between the opening and closing tags of the control. The control also makes it easier to accomplish a common ASP task: apply browser-dependent transformations to portions of the page expressed in an XML meta language. In this case, you exploit the programming interface of the control as follows:

 

In the Page_Load event, you just check the browser capabilities and decide which transformation should be applied.

void Page_Load(object sender, EventArgs e) { if (IsInternetExplorer(Request.Browser)) theXml.TransformSource = "ie5.xsl"; else theXml.TransformSource = "downlevel.xsl"; }

The PlaceHolder Control

The PlaceHolder control is one of the few controls in the WebControls namespace that isn't derived from the WebControl class. It inherits from Control and is used only as a container for other controls in the page. The PlaceHolder control does not produce visible output of its own and is limited to containing child controls dynamically added through the Controls collection. The following code shows how to embed the PlaceHolder control in a Web page:

 

Once you have a placeholder, you can add controls to it. As mentioned, the placeholder does not add extra functionality, but it provides for grouping and easy and direct identification of a group of related controls. The following code demonstrates how to create a new button and add it to an existing placeholder:

btn = new Button(); btn.Text = "Click me"; theToolbar.Controls.Add(btn);

The PlaceHolder control reserves a location in the control tree and can be extremely helpful in identifying specific areas of the page to customize and extend by adding controls programmatically.

Validation Controls

A key rule for writing more secure applications is to get the data right before you use it. Getting the data right requires you to apply a validation step to any external input. In ASP.NET, validator controls are used to verify the input of the form fields within a Web page. Validation controls provide an easy-to-use mechanism to perform a variety of validation tasks, including testing for valid types, values within a given range, or required fields.

The validator controls are Web server controls and inherit from the BaseValidator class which, in turn, descends from Label. All validator controls defined on a page are automatically grouped in the Validators collection of the Page class. You can validate them all in a single shot using the Validate method in the Page class or individually by calling the Validate method on each validator. The Validate method sets the IsValid property both on the page and on the individual validator. The IsValid property indicates whether the user's entries match the requirements of the validators.

  Note

The Validate method on the validator control performs any needed checks on the associated control and, as a result, updates the control's IsValid property. The Validate method, when called on the page, cumulatively validates all validation controls defined within the page. The page's IsValid property is the logical AND of the values of IsValid on all embedded validation controls.

Other than explicitly using the Validate method, the user's entry is also automatically validated whenever the page posts back. In this case, validation is performed when a button control is clicked. The button controls that can automatically apply validation are Button, HtmlButton, HtmlInputButton, HtmlInputImage, ImageButton, and LinkButton. You can enable or disable a button's validation capability by using the CausesValidation Boolean property.

The .NET Framework also provides complete client-side implementation for validation controls. This allows Dynamic HTML–enabled browsers (such as Internet Explorer version 4.0 and later) to perform validation on the client as soon as the user tabs out of a monitored input field.

Types of Validation Controls

Each validation control references an input control located elsewhere on the page. When the page is going to be submitted, the contents of the monitored server control is passed to the validator for further processing. Each validator would perform a different type of verification. Table 3-10 shows the types of validation supported by the .NET Framework.

Table 3-10: Validator Controls in the .NET Framework

Validator

Description

CompareValidator

Compares the user's entry against a fixed value by using a comparison operator such as LessThan, Equal, or GreaterThan. Can also compare against the value of a property in another control on the same page.

CustomValidator

Employs a programmatically defined validation logic to check the validity of the user's entry. You use this validator when the other validators cannot perform the necessary validation and you want to provide custom code that validates the input.

RangeValidator

Ensures that the user's entry falls within a specified range. Lower and upper boundaries can be expressed as numbers, strings or dates.

RegularExpressionValidator

Validates the user's entry only if it matches a pattern defined by a regular expression.

RequiredFieldValidator

Ensures that the user specifies a value for the field.

Multiple validation controls can be used with an individual input control to validate according to different criteria. For example, you can apply multiple validation controls on a text box that is expected to contain an e-mail address. In particular, you can impose that the field is not skipped (RequiredFieldValidator) and that its content matches the typical format of e-mail addresses (RegularExpressionValidator).

Table 3-10 lacks a reference to the ValidationSummary control. The control does not perform validation tasks itself. It displays a label to summarize all the validation error messages found on a Web page as the effect of other validators. We'll cover the ValidationSummary control later in the chapter.

The BaseValidator Class

Figure 3-4 shows the relationship between the various validation controls and their parent classes.

Figure 3-4: Diagram of validation controls in ASP.NET. Gray boxes represent abstract classes.

Table 3-11 details the specific properties of validation controls. Some properties, such as ForeColor, Enabled, and Text, are overridden versions of base properties on base classes.

Table 3-11: Basic Properties of Validators

Property

Description

ControlToValidate

Gets or sets the input control to validate. The control is identified by name—that is, by using the value of the ID attribute.

Display

If client-side validation is supported and enabled, gets or sets how the space for the error message should be allocated—either statically or dynamically. In case of server-side validation, this property is ignored. A Static display is possible only if the browser supports the display CSS style. The default is Dynamic.

EnableClientScript

True by default; gets or sets whether client-side validation is enabled.

Enabled

Gets or sets whether the validation control is enabled.

ErrorMessage

Gets or sets the text for the error message.

ForeColor

Gets or sets the color of the message displayed when validation fails.

IsValid

Gets or sets whether the associated input control passes validation.

Text

Gets or sets the description displayed for the validator in lieu of the error message. Note, though, this text does not replace the contents of ErrorMessage in the summary text.

All validation controls inherit from the BaseValidator class except for compare validators, for which a further intermediate class—the BaseCompareValidator class—exists. The BaseCompareValidator class serves as the foundation for validators that perform typed comparisons. An ad hoc property, named Type, is used to specify the data type the values are converted to before being compared. The CanConvert static method determines whether the user's entry can be converted to the specified data type. Supported types includes string, integer, double, date, and currency. As shown in Figure 3-4, the classes acting as compare validators are RangeValidator and CompareValidator.

Associating Validators with Input Controls

The link between each validator and its associated input control is established through the ControlToValidate property. The property must be set to the ID of the input control. If you do not specify a valid input control, an exception will be thrown when the page is rendered. The association validator/control is between two controls within the same container—be it a page, user control, or template.

Not all server controls can be validated. Those which can be validated specify their validation property through an attribute named [ValidationPropertyAttribute]. The attribute takes the name of the property that contains the user's entry. For example, the validation property for a TextBox is Text and is indicated as follows:

[ValidationPropertyAttribute("Text")] public class TextBox : WebControl { }

The standard list of validating controls include TextBox, DropDownList, HtmlInputFile, HtmlInputText, HtmlSelect, HtmlTextArea, ListBox, and RadioButtonList. Custom controls can be validated too, as long as they are marked with the aforementioned ValidationPropertyAttribute attribute.

  Note

If the validation property of the associated input control is left empty, all validators accept the value and pass the test. The RequiredFieldValidator control represents a rather natural exception to this rule, as it has been specifically designed to detect fields the user skipped and left blank.

The CompareValidator Control

The CompareValidator control lets you compare the value entered by the user with a constant value or the value specified in another control in the same naming container. The behavior of the control is characterized by the following additional properties:

  • ControlToCompare Represents the ID of the control to compare with the current user's entry. You should avoid setting the ControlToCompare and ValueToCompare properties at the same time. They are considered mutually exclusive; if you set both, the ControlToCompare property takes precedence.
  • Operator Specifies the comparison operation to perform. The list of feasible operations is defined in the ValidationCompareOperator enumeration. The default operator is Equal. Other operators are NotEqual, LessThan, GreaterThan, GreaterThanEqual, LessThanEqual, and DataTypeCheck. The last operator in particular is useful when you want to make sure certain input data can be converted to a certain type. When the DataTypeCheck operator is specified, both ValueToCompare and ControlToCompare are ignored. In this case, the test is made on the type of the input data and returns true if the specified data can be converted to the expected type. Supported types are expressed through the following keywords: String, Integer, Double, Date, and Currency (decimal).
  • ValueToCompare Indicates the value to compare the user's input against. If the Type property is set, the ValueToCompare attribute must comply with it.

The following code demonstrates the typical markup of the CompareValidator control when the control is called to validate an integer input from a text box representing someone's age:

 

The CustomValidator Control

The CustomValidator control is a generic and totally user-defined validator that uses custom validation logic to accomplish its task. You typically resort to this control when none of the other validators seems appropriate or, more simply, when you need to execute your own code in addition to that of the standard validators.

To set up a custom validator, you need to indicate a client-side function through the ClientValidationFunction property. If client-side validation is disabled or not supported, simply omit this setting. Alternatively, or in addition to client validation, you can define some managed code to execute on the server. You do this by defining a handler for the ServerValidate event. The code will be executed when the page is posted back in response to a click on a button control. The following code snippet shows how to configure a custom validator to check the value of a text box against an array of feasible values.

 

If specified, the client validation function takes a mandatory signature and looks like this:

function CheckMembership(source, arguments) { ... }

The source argument references the HTML tag that represents the validator control—usually, a tag. The arguments parameter references an object with two properties, IsValid and Value. The Value property is the value stored in the input control to be validated. The IsValid property must be set to false or true according to the result of the validation. The CustomValidator control is not associated in all cases with a single input control in the current naming container. For this type of validator, setting the ControlToValidate property is not mandatory. For example, if the control has to validate the contents of multiple input fields, you just don't set the ControlToValidate property and the arguments.Value variable evaluates to the empty string. In this case, you write the validation logic so that any needed values are dynamically retrieved. With client-side script code, this can be done by accessing the members of the document's form, as shown in the following code:

function CheckMembership(source, arguments) { // Retrieve the current value of the element // with the specified ID var membership = document.forms[0]["membership"].value; }

Setting only a client-side validation code opens a security hole because an attacker could work around the validation logic and manage to have invalid or malicious data sent to the server. By defining a server event handler, you have one more chance to validate data before applying changes to the back-end system. To define a server-side handler for a custom validator, use the ServerValidate event.

void ServerValidation(object source, ServerValidateEventArgs e) { }

The ServerValidateEventArgs structure contains two properties—IsValid and Value—with the same meaning and goal as in the client validation function. If the control is not bound to a particular input field, the Value property is empty and you retrieve any needed value using the ASP.NET object model. For example, the following code shows how to check the status of a check box on the server:

void ServerValidation (object source, ServerValidateEventArgs e) { e.IsValid = (CheckBox1.Checked == true); }

Note that the CheckBox control (as well as HtmlInputCheckBox) cannot be validated using the standard validators and the CustomValidator control is the only option.

The RegularExpressionValidator Control

Regular expressions are an effective way to ensure that a predictable and well-known sequence of characters form the user's entry. For example, using regular expressions you can validate the format of zip codes, Social Security numbers, client codes, e-mail addresses, telephone numbers, and so on. When using the RegularExpressionValidator control, you set the ValidationExpression property with the regular expression, which will be used to validate the input. (For more information about regular expressions, see the Visual Studio .NET documentation or the MSDN online documentation.)

The following code snippet shows a regular expression validator that ensures the user's entry is an e-mail address:

 

The regular expression just shown specifies that valid e-mail addresses are formed by two nonzero sequences of letters, digits, dashes, and dots separated by an @ symbol and followed by a dot (.) and an alphabetic string. (This might not be the perfect regular expression for e-mail addresses, but it certainly incorporates the majority of e-mail address formats.)

  Note

The regular expression validation syntax is slightly different on the client than on the server. The RegularExpressionValidator control uses JScript regular expressions on the client and the .NET Framework Regex object on the server. Be aware that the JScript regular expression syntax is a subset of the Regex model. Whenever possible, try to use the regular expression syntax supported by JScript so that the same result is obtained for both the client and server.

The RangeValidator Control

The RangeValidator control lets you verify that a given value falls within a specified range. The type of the values involved in the check is specified dynamically and picked from a short list that includes strings, numbers, and dates. The following code shows how to use a range validator control. The key properties are MinimumValue and MaximumValue, which together clearly denote the lower and upper boundaries of the interval.

 

Note that an exception is thrown if the strings assigned MinimumValue or MaximumValue cannot be converted to the numbers or dates according to the value of the Type property.

If the type is set to Date, but no specific culture is set for the application, you should specify dates using a culture-neutral format, such as yyyy/MM/dd. If you don't do so, the chances are good that the values will not be interpreted correctly. Also bear in mind that the RangeValidator control just extends the capabilities of the more basic CompareValidator control by checking for a value in a fixed interval. In light of this, the RangeValidator control might raise an exception if either MinimumValue or MaximumValue is omitted. Whether the exception is thrown or not depends on the type chosen and its inherent ability to interpret the empty string. For example, an empty string on a Date type causes an exception.

If you want to operate on an unbound interval—whether lower or upper unbound—either you resort to the GreaterThan (or LessThan) operator on the CompareValidator control or simply use a virtually infinite value such as the 9999-12-31 date.

  Note

Properties on the validation controls can be configured programmatically—for example, in the Page_Load event. In particular, if you're going to define the boundaries of a RangeValidator control at run time, be aware that both MinimumValue and MaximumValue are string properties.

The RequiredFieldValidator Control

To catch when a user skips a mandatory field in an input form, you use the RequiredFieldValidator control to show an appropriate error message.

 

As long as you're using an up-level browser and client-side scripting is enabled for each validator, which is the default, invalid input will display error messages without performing a postback. Note that just tabbing through the controls is not a condition that raises an error; the validator gets involved only if you type blanks or if the field is blank when the page is posted back.

The control that requires input does not automatically display an asterisk or other character near the control to emphasize that it's required. Marking the field so that it stands out from the others is a good programming practice, but it is left up to the programmer to make controls that require input to stand out from the others.

How can you determine whether a certain field is really empty? In many cases, the empty string just pays the bill, but this is not a rule. The InitialValue property specifies the initial value of the input control. The validation fails only if the value of the control equals InitialValue upon losing focus. By default, InitialValue is initialized with the empty string.

Setting Up a Data Entry Page

Let's see how to build a form that makes intensive use of validators to ensure that the input is always well-formed. The following page contains a couple of mandatory text fields to specify first and last name. Both are associated with an instance of the RequiredFieldValidator control. Other controls are expected to accept a minimum age and a date. For them, we'll use CompareValidator and RangeValidator. An e- mail address is entered and validated using a RegularExpressionValidator. Finally, a membership level is validated using a CustomValidator.

 

Fill the form out

Name *  
Last Name *  
Age    
Email    
Hire Date    
Membership Level    

By default, if the page runs on an up-level browser such as Internet Explorer 6.0, the validation is automatically enabled on the client as well. As you tab out of each form field, some automatically created Javascript code runs and checks the user input before it is sent to the server.

In the page just listed, each validator control is rendered to the right of the input field so that in case of an error, the error message is displayed to the right of the input field, as shown in Figure 3-5.

Figure 3-5: The input form with error messages signaled by validation controls.

If the client script support is disabled or the browser doesn't provide for it, no validation takes place until the page is posted back. In this case, nothing happens as you tab in and out of input fields, but after a postback the page is served with the proper error messages.

Displaying Error Information

The ErrorMessage property determines the static message that each validation control will display in case of error. Note that if the Text property is also set, it would take precedence over ErrorMessage. Text is designed to display inline where the validation control is located; ErrorMessage is designed to display in the validation summary. (Strategies for using Text and ErrorMessage will be discussed more in the next section, "The ValidationSummary Control.") Because all validation controls are labels, no other support or helper controls are needed to display any message. The message will be displayed in the body of the validation controls and, subsequently, wherever the validation control is actually placed. The error message is displayed as HTML, so it can contain any HTML formatting attribute.

Validators that work in client mode can create the tag for the message either statically or dynamically. You can control this setting by using the Display property. When the display mode is set to Static (the default), the element is given the following style:

style="color:Red;visibility:hidden;"

The CSS visibility style attribute, when set to Hidden, causes the browser not to display the element but reserves space for it. If the Display property contains Dynamic, the style string changes as follows:

style="color:Red;display:none;"

The CSS display attribute, when set to none, simply hides the element, which will take up space on the page only if displayed. The value of the Display property becomes critical when you have multiple validators associated with the same input control. For example, consider the following code excerpted from the previously considered page:

 

The value of the hired text box is first validated to ensure it contains a valid date and then to verify the specified date is later than 1-1-1999. If the Display property is set to Static and the date is outside the specified range, you get a page like the one shown in Figure 3-6.

Figure 3-6: The first error message is not displayed, but it takes up space.

The ValidationSummary Control

The ValidationSummary control is a label that summarizes and displays all the validation error messages found on a Web page. The summary is displayed in a single location formatted in a variety of ways. The DisplayMode property sets the output format, which can be a list, a bulleted list, or a plain text paragraph. By default, it is a bulleted list. The feasible values are grouped in the ValidationSummaryDisplayMode enumeration.

Whatever the format is, the summary can be displayed as text in the page, in a message box, or in both. The Boolean properties ShowSummary and ShowMessageBox let you decide. The output of the ValidationSummary control is not displayed until the page posts back no matter what the value of the EnableClientScript property is. The HeaderText property defines the text that is displayed atop the summary.

 

This code snippet originates the screen shown in Figure 3-7.

Figure 3-7: After the page posts back, the validation summary is updated and a message box pops up to inform the user.

The validation summary is displayed only if there's at least one pending error. Note that, in the default case, the labels near the input controls are updated anyway, along with the summary text. You can control the error information in the following ways:

  • Both in-place and summary information This is the default scenario. Use the ValidationSummary control and accept all default settings on the validator controls. If you want to leverage both places to display information, a recommended approach consists of minimizing the in-place information by using the Text property rather than ErrorMessage. If you set both, Text is displayed in-place while ErrorMessage shows up in the validation summary. For example, you can set Text with a glyph or an asterisk and assign ErrorMessage with more detailed text. (This case is illustrated in Figure 3-8.)

    Figure 3-8: A glyph marks the input data as wrong, and the summary text details the errors.

  • Only in-place information Do not use the ValidationSummary control, and set the ErrorMessage property in each validation control you use.
  • Only summary information Use the ValidationSummary control, and set the ErrorMessage property on individual validation controls. Set the Display property of validators to None so that no in- place error message will ever be displayed.
  • Custom error information You don't use the ValidationSummary control, and you set the Display property of the individual validators to None. In addition, you collect the various error messages through the ErrorMessage property on the validation controls and arrange your own feedback for the user.

Validating for Multiple Conditions

As mentioned earlier, you can associate multiple validators with a single input control. The validation takes place in order, and each validation control generates and displays its own error message. The content of the input control is considered valid if all the validators return true.

If an input control has multiple valid patterns—for example, an ID field can take the form of a Social Security number or a VAT number—you can either validate by using custom code or regular expressions.

Client Side Validation

As mentioned earlier, the verification normally takes place on the server either after the Validate method is called or as the result of a postback event. If the browser supports Dynamic HTML, though, you can also activate the validation process on the client, with a significant gain in responsiveness. To be precise, ASP.NET automatically enables client-side validation if it detects a browser with enough capabilities.

If client-side validation is turned on, the page won't post back until all the input fields contain valid data. To run secure code and prevent malicious and underhanded attacks, you might want to validate data on the server too. Consider also that not all types of validation can be accomplished on the client. In fact, if you need to validate against a database, there's no other option than posting back to the server.

Enabling Client Validation

Client validation can be controlled on a per-validation control basis by using the EnableClientScript Boolean property. By default, the property is set to true, meaning client validation is enabled as long as the browser supports it. If you want to control the client validation at the page level, resort to the ClientTarget attribute on the @Page directive. The following code disables client validation by specifying that any code in the page should target a down-level browser:

 

The ClientTarget attribute—also available as a property on the Page class—overrides the type of browser that ASP.NET should target when generating the page. If the ClientTarget attribute is set, ASP.NET doesn't detect the actual browser's capabilities but loads the capabilities for the specified browser from the machine.config file. Feasible values for the ClientTarget attribute include any value defined in the configuration section. The standard content is as follows:

 

If ClientTarget is not set, the browser's capabilities are detected through Request.Browser property. The BaseValidator class determines whether the browser is up-level or not. Only if the browser is considered up-level, will the client validation be implemented. Browsers and client devices that are considered up-level support at least the following:

  • ECMAScript (including JScript and JavaScript) version 1.2
  • HTML version 4.0
  • The Microsoft Document Object Model
  • Cascading style sheets

For down-level browsers, the only requirement is HTML version 3.2.

Implementing Client Validation

For situations in which validation can be applied on the client, a lot of JavaScript code is silently injected in the page. Let's consider a simple page like the following one:

This page contains a single text box with a required field validator. When viewed through an up-level browser, the HTML output looks like the following code. The code in bold represents specific extensions due to the client validation.

 

language="javascript" onsubmit="ValidatorOnSubmit();">

When the page loads up, the ValidatorOnLoad JavaScript function executes and populates the Page_Validators array with instances of the JavaScript objects that represent the active validators. Another change to notice is the onsubmit client event handler that has been added to the

element. When the HTML form is going to be submitted, a piece of script code runs and checks the validity of all input fields. The onsubmit handler allows the actual post only when all the validators agree to commit.

All the client script functions are imported in the page from a well-known JavaScript file located under the Web server's root:

/aspnet_client/system_web/1_x_xxxx_0/WebUIValidation.js

The path of this file is controlled by the section of the machine.config file.

Another interesting change to observe in the ASP.NET code when client validation is enabled is the insertion of extra attributes in the tag that represents the validator. The preceding code reveals a couple of custom attributes named evaluationfunction and initialvalue. The former refers to the JavaScript function that performs the client-side validation. The function is defined in the WebUIValidation.js file. The other attribute, specific to the required field validator, refers to the value to check against—the empty string in this case. The script validator functions receive one argument, that being the JavaScript object representing the validator. Custom attributes are an effective way to pass external data to script objects based on HTML tags. The following code snippet from WebUIValidation.js shows the script implementation of the required field validator:

function ValidatorTrim(s) { var m = s.match(/^s*(S+(s+S+)*)s*$/); return (m == null) ? "" : m[1]; } function RequiredFieldValidatorEvaluateIsValid(val) { var t = ValidatorTrim(ValidatorGetValue(val.controltovalidate); return (t != ValidatorTrim(val.initialvalue)) }

Internet Explorer WebControls

Although they're not officially part of the .NET Framework and aren't included in the Web controls namespace, other Web controls have been around for some time to address the needs of developers who do a lot of client-side, Internet Explorer–specific Web programming. Unlike controls in the ASP.NET namespace, these controls extensively exploit the Dynamic HTML object model of Internet Explorer 5.x and newer versions. They perform a lot of tasks on the client and make provisions for Web versions of typical desktop controls such as the TreeView or TabStrip. You can download some of these controls from the control gallery at http://www.asp.net. Microsoft has released the following controls:

  • IE TreeView Facilitates rendering of hierarchical data, folder views, and other similar data structures. The control includes support for data binding and rich DHTML behaviors in Internet Explorer 5.5 and newer.

  • IE Toolbar Web counterpart of the toolbar control commonly used in Microsoft Windows desktop applications.

  • IE TabStrip Simplifies the authoring of tabbed menus, and is particularly useful for authoring user-interface elements that navigate site content.
  • IE MultiPage Enables the definition of collections of child page elements. As in a desktop Windows tab control, the control lets you define the content of pages that are navigated.

All Internet Explorer WebControls are tailored for both down-level browsers and up-level browsers and renders their advanced functionalities using client-side behaviors when the browser allows for that. In the same gallery of controls on the http://www.asp.net portal, you'll also find links to similar third-party products.

Data Bound Controls

Web applications are, for the most part, just data-driven applications. For this reason, the ability to bind HTML elements like drop-down lists or tables to structured data represents a key feature for a development platform. Data-bound controls are the ASP.NET answer to the growing demand for automatic binding between data sources and graphical elements. Data binding is the process that retrieves data from a fixed source and dynamically associates this data to properties on server controls. Valid target controls are those that have been specifically designed to support data binding. Data-bound controls are not yet another family of controls. Data-bound controls are simply server controls that feature a few well-known data-related properties, including Text, DataSource, DataTextField, and DataValueField.

The DataSource property, in particular, lets you specify the data source object the control is linked to. Note that this link is logical and does not result in any overhead or underlying operation until you explicitly order to bind the data to the control. Not all properties in the Web control programming interface are data bindable. You activate data binding on a control by calling the DataBind method. When this method executes, the control actually loads data from the associated data source, evaluates the data-bound properties, and redraws its user interface to reflect changes.

Feasible Data Binding Sources

Many .NET classes can be used as data sources—and not just those that have to do with database contents. In general, any object that exposes the ICollection interface is a valid bindable data source. The ICollection interface defines size, enumerators, and synchronization methods for all .NET collections. In particular, you can bind a Web control to the following classes:

  • DataTable, DataView, and DataSet
  • Data readers
  • Dictionaries and arrays

In ASP.NET 1.1, XML documents are not directly bindable unless you load their content in one of the previously mentioned classes. You can do this by loading the XML document into a DataSet and then binding to the DataSet.

To be honest, I should note that the DataSet and DataTable classes don't implement ICollection or any other interface that inherit from it (for example, IList). However, both classes do store collections of data internally. These collections are accessed using the methods of an intermediate interface—IListSource—which performs the trick of making the DataSet and DataTable classes look like they implement a collection. In Chapter 20, we'll discuss in detail the mechanism that makes such ADO.NET objects bindable.

ADO.NET Classes

As we'll see in greater detail in Chapter 5, ADO.NET—and in particular the System.Data namespace—provides a bunch of data container classes that can be filled with any sort of data, including database information. Classes in the System.Data namespace are just in-memory caches of data and work disconnected from any database server. The data reader class, on the other hand, is specific to a managed provider and, as such, is tightly bound to a particular data source such as Oracle or Microsoft SQL Server.

Note that the DataSet class can contain more than one table; however, only one table can be associated with a data-bound control. In this case, you should assign the DataSet object to the DataSource property and the selected DataTable object to another property acting as a selector—the DataMember property.

Collection-Based Classes

At the highest level of abstraction, a collection serves as a container for instances of other classes. All collection classes implement the ICollection interface, which in turn implements the IEnumerable interface. As a result, all collection classes provide a basic set of functionalities.

All collection classes have a Count property to return the number of cached items; they have a CopyTo method to copy their items, in their entirety or in part, to an external array; they have a GetEnumerator method that instantiates an enumerator object to loop through the child items. GetEnumerator is the method behind the curtain whenever you call the foreach statement in C# and the For...Each statement in Visual Basic .NET.

IList and IDictionary are two interfaces that extend ICollection, giving a more precise characterization to the resultant collection class. ICollection provides only basic and minimal functionality for a collection. For example, ICollection does not have any methods to add or remove items. Add and remove functions are exactly what the IList interface provides. In the IList interface, the Add and Insert methods place new items at the bottom of the collection or at the specified index. The Remove and RemoveAt methods remove items, while Clear empties the collection. Finally, Contains verifies whether an item with a given value belongs to the collection, and IndexOf returns the index of the specified item. Commonly used container classes that implement both ICollection and IList are Array, ArrayList, and StringCollection. Previously mentioned ADO.NET classes—such as the DataView class—support data binding via the ICollection interface.

The IDictionary interface defines the API that represents a collection of key/ value pairs. The interface exposes methods similar to IList, but with different signatures. Dictionary classes also feature two extra properties, Keys and Values. They return collections of keys and values, respectively, found in the dictionary. Typical dictionary classes are ListDictionary, Hashtable, and SortedList.

Simple Data Binding

In ASP.NET, there are two types of data binding—simple and complex. A simple binding is a connection between one piece of data and a server control property. It is established through a special expression and is evaluated when the code in the page calls the DataBind method either on the Page object or the control.

A data binding expression is any text wrapped by and prefixed by the symbol #. You can use data-binding expressions to set the value of an attribute in the opening tag of a server control. A data-binding expression is programmatically managed via an instance of the DataBoundLiteralControl class. The following code snippet shows how to set the text of a label with the current time:

 

Within the delimiters, you can invoke user-defined page methods, static methods, and properties and methods of any other page components. The following code demonstrates a label bound to the name of the currently selected element in a drop-down list control:

 

Note that if you're going to use quotes within the expression, you should wrap the expression itself with single quotes. The data-binding expression can accept a minimal set of operators, mostly for concatenating subexpressions. If you need more advanced processing and use external arguments, resort to a user-defined method. The only requirement is that the method must be callable within the page. If the code of the page is not resident in the .aspx page (for example, you're using code- behind), make sure the method is declared public or protected.

Simple Data Binding in Action

In the following example, you'll see how to use simple data binding with text boxes to arrange a form-based record viewer. The user interface of the page supplies three text boxes, one for each of the retrieved fields. The data source is the Employees table of the Northwind database in Microsoft SQL Server 2000. The query that is run against the database selects three fields: employeeid, firstname, and lastname. The binding takes place between the text boxes and the fields. Only one record at a time is displayed, and Previous and Next buttons let you move through the data. You can see what the application looks like in Figure 3-9.

Figure 3-9: The text boxes in the figure are bound to fields in the Employees table from the SQL Server 2000 Northwind sample database.

The binding expression makes use of a user-defined method named GetBoundData.

 

The method takes the name of the field to display and retrieves the position of the current record from the ASP.NET Session object. It then reads the corresponding value and passes it to the ASP.NET runtime for actual rendering.

public string GetBoundData(String fieldName) { DataSet ds = (DataSet) Session["MyData"]; DataTable dt = ds.Tables["EmpTable"]; int nRowPos = (int) Session["CurrentRecord"]; String buf = dt.Rows[nRowPos][fieldName].ToString(); return buf; }

Implementation of Data-Bound Expressions

What really happens when a data-bound expression is found in a Web page? How does the ASP.NET runtime process it? Let's consider the following base code:

While compiling the source code for the page, the ASP.NET runtime writes a handler for the DataBinding event of the control—a Label in this case. The following pseudocode shown illustrates the generation of the label in the underlying class. (See Chapter 2 for more details on the compilation of the page.)

private Control __BuildControltoday() { Label __ctrl = new Label(); this.today = __ctrl; __ctrl.ID = "today"; __ctrl.DataBinding += new EventHandler(this.__DataBindtoday); return __ctrl; }

Basically, the data-binding handler assigns the verbatim expression to the control's property.

public void __DataBindtoday(object sender, EventArgs e) { Label target; target = (Label) sender; target.Text = Convert.ToString(DateTime.Now.ToString()); }

The value returned by the data-binding expression must be convertible to a string. The code in the event handler does not change if the expression points to another control. The ASP.NET runtime assumes the control exists and is instantiated—which is true by design.

Complex Data Binding

Complex data binding occurs when you bind a list control or an iterative control to one or more columns of data. List controls include the DropDownList, CheckBoxList, RadioButtonList, and ListBox. Iterative controls are the Repeater, DataList, and DataGrid controls.

List controls have a more complex and richer user interface than labels and text boxes. They display (or at least need to have in memory) more items at the same time. That's the reason you should associate them explicitly with a collection of data—the data source. Depending on its expected behavior, the control will pick the needed items from memory and properly format and display them.

Iterative controls take a data source, loop through the items, and iteratively apply HTML templates to each row. This basic behavior is common to all three ASP.NET iterators. Beyond that, they differ in terms of layout capabilities and functionality they support. We'll cover iterative controls from various perspectives in Chapter 6 and Chapter 9.

Let's see how complex forms of data binding apply to key list controls. All list controls inherit from the base ListControl class.

The DropDownList Control

The DropDownList control enables users to select one item from a single-selection drop-down list. You can specify the size of the control by setting its height and width in pixels, but you can't control the number of items displayed when the list drops down. The DropDownList control can be filled through data binding. The following code provides an example:

 

You can assign a data binding expression to the DataSource property but not to the DataTextField and DataValueField properties. Their value must match exactly the name of one of the columns in the data source. The properties specific to the DropDownList control are shown in Table 3-12.

Table 3-12: Properties of the DropDownList Control

Property

Description

AutoPostBack

Gets or sets whether the control should automatically post back to the server when the user changes the selection

DataMember

Gets or sets the name of the table in the DataSource to bind

DataSource

Gets or sets the data source that populates the items of the list

DataTextField

Gets or sets the name of the column in the data source that provides the text content of the list items

DataTextFormatString

Gets or sets the formatting string used to control how data bound to the list is displayed

DataValueField

Gets or sets the field of the data source that provides the value of each list item

Items

Gets the collection of items in the list control

SelectedIndex

Gets or sets the index of the selected item in the list

SelectedItem

Gets the selected item in the list

The programming interface of the DropDownList also features three properties to configure the border of the drop-down list—the BorderColor, BorderStyle, and BorderWidth properties. Although the properties are correctly transformed by style properties, most browsers won't use them to change the appearance of the drop-down list.

The DataTextField and DataValueField properties don't accept expressions, only plain column names. To combine two or more fields of the data source, you can use a calculated column. You can either use a column computed by the database or exploit the power of the ADO.NET object model (as explained in Chapter 5) and add an in-memory column. The following SQL query returns a column obtained by concatenating lastname and firstname.

SELECT lastname + ', ' + firstname AS 'EmployeeName' FROM Employees

The same result can also be obtained, more efficiently, without the involvement of the database. Once you've filled a DataTable object with the result of the query, you add a new column to its Columns collection. The content of the column is based on an expression. The following code adds an EmployeeName column to the data source that concatenates the last name and first name:

dataTable.Columns.Add("EmployeeName", typeof(string), "lastname + ', ' + firstname");

An expression-based column does not need to be filled explicitly. The values for all the cells in the column are calculated and cached when the column is added to the table. The table tracks any dependencies and updates the calculated column whenever any of the constituent columns are updated.

The CheckBoxList Control

The CheckBoxList control is a single monolithic control that groups a collection of checkable list items, each of which is rendered through an individual CheckBox control. The properties of the child check boxes are set by reading the associated data source. You insert a check box list in a page as follows:

Table 3-13 lists the specific properties of the CheckBoxList control.

Table 3-13: Properties of the CheckBoxList Control

Property

Description

AutoPostBack

Gets or sets whether the control should automatically post back to the server when the user changes the selection

CellPadding

Gets or sets the pixels between the border and contents of the cell

CellSpacing

Gets or sets the pixels between cells

DataMember

Gets or sets the name of the table in the DataSource to bind

DataSource

Gets or sets the data source that populates the items of the list

DataTextField

Gets or sets the name of the column in the data source that provides the text content of the list items

DataTextFormatString

Gets or sets the formatting string used to control how data bound to the list is displayed

DataValueField

Gets or sets the field of the data source that provides the value of each list item

Items

Gets the collection of items in the list control

RepeatColumns

Gets or sets the number of columns to display in the control

RepeatDirection

Gets or sets a value that indicates whether the control displays vertically or horizontally

RepeatLayout

Gets or sets the layout of the check boxes (table or flow)

SelectedIndex

Gets or sets the index of the selected item in the list

SelectedItem

Gets the selected item in the list

TextAlign

Gets or sets the text alignment for the check boxes

Unlike the DropDownList control, the CheckBoxList does not supply any properties that know which items have been selected. But this aspect is vital for any Web application that utilizes checkable elements. The CheckBoxList can have any number of items selected, but how can you retrieve them?

Any list control has an Items property that contains the collection of the child items. The Items property is implemented through the ListItemCollection class and makes each contained item accessible via a ListItem object. The following code loops through the items stored in a CheckBoxList control and checks the Selected property of each of them:

foreach(ListItem item in chkList.Items) { if (item.Selected) { // this item is selected } }

The RadioButtonList Control

The RadioButtonList control acts as the parent control for a collection of radio buttons. Each of the child items is rendered through a RadioButton control. By design, a RadioButtonList can have zero or one item selected. The SelectedItem property returns the selected element as a ListItem object. Note, though, that there is nothing to guarantee that only one item is selected at any time. For this reason, be extremely careful when you access the SelectedItem of a RadioButtonList control—it could be null.

The contents of the control can be fetched from a data source as follows:

 

The control supports the same set of properties as the CheckBoxList control and, just like it, accepts some layout directives. In particular, you can control the rendering process of the list with the RepeatLayout and RepeatDirection properties. By default, the list items are rendered within a table, which ensures the vertical alignment of the companion text. The property that governs the layout is RepeatLayout. The alternative is displaying the items as free HTML text, using blanks and breaks to guarantee some sort of minimal structure. RepeatDirection is the property that controls the direction in which, with or without a tabular structure, the items flow. Feasible values are Vertical (the default) and Horizontal. RepeatColumns is the property that determines how many columns the list should have. By default the value is 0, which means all the items will be displayed in a single row, vertical or horizontal according to the value of RepeatDirection.

The ListBox Control

The ListBox control represents a vertical sequence of items displayed in a scrollable window. The ListBox control allows single-item or multiple-item selection and exposes its contents through the usual Items collection, as shown in the following code:

 

You can decide the height of the control through the Rows property. The height is measured in number of rows rather than pixels or percentages. When it comes to data binding, the ListBox control behaves like the controls discussed earlier in the chapter. It supports properties such as DataSource and DataMember, and it can be bound to a data source and show its contents.

Two properties make this control slightly different than other list controls—the Rows property, which represents the number of visible rows in the control, and the SelectionMode property, which determines whether one or multiple items can be selected. The following code demonstrates how to write a comma-separated string with the values of the selected items:

public void ShowSelectedItems(object sender, EventArgs e) { StringBuilder sb = new StringBuilder(""); for (int i=0; i < theList.Items.Count; i++) { if (theList.Items[i].Selected) { sb.Append(theList.Items[i].Text); sb.Append(", "); } } Response.Write(sb.ToString()); }

This code is nearly identical to the one you would write to accomplish the same operation on a CheckBoxList control. The programming interface of the list box also contains a SelectedItem property that makes little sense when you work with a multiselection control. In this case, the SelectedItem property returns the selected item with the lowest index.

  Note

All list controls support the SelectedIndexChanged event, which is raised when the selection from the list changes and the page posts back to the server. You can use this event to execute server-side code whenever a control is checked or unchecked.

Conclusion

In ASP.NET pages, server controls are vital components. Server-side controls alone—no matter their capabilities and flavors—constitute a huge difference between ASP and ASP.NET. Server-side controls transform the programming model of ASP.NET from a mere factory of HTML strings to a more modern and effective component-based model.

ASP.NET features a long list of control classes. Looking at the namespaces involved, we should conclude that only two families of controls exist—HTML and Web controls. Controls in the former group simply mirror the set of elements in the HTML syntax. Each constituent control has as many properties as there are attributes in the corresponding HTML tag. Names and behavior have been kept as faithful to the originals as possible. The ultimate goal of the designers of HTML controls is to make the transition from ASP to ASP.NET as seamless as possible—just add runat="server" and refresh the page.

The overall design of Web controls is more abstract and much less tied to HTML. In general Web controls do not provide a strict one-to-one correspondence between controls and HTML tags. However, the capabilities of Web and HTML controls overlap. All ASP.NET server controls render in HTML, but Web controls render to more complex HTML representation than HTML controls.

In the family of Web controls, we can identify interesting and powerful subsets of controls—for example, validators, list controls, and iterative controls. Data- bound controls, including list and iterative controls, represent a key enhancement in the ASP.NET programming model. The ability to bind data sources to controls—especially to disconnected and in-memory sources—adds spice to an already powerful model and significantly increases speed and productivity. Just consider the following example. Do you remember the typical check box and radio button code that countless ASP pages implemented? The code walks its way through all the records in a result set and generates a check box or radio button at each step. With this old model, state maintenance is in the care of the programmer, code has to be written over and over again, and extensibility and reusability is a mere dream. In ASP.NET—thanks to server controls—control list generation is as easy as using ad hoc data- bound list controls.

Resources

  • Internet Explorer WebControls (http://msdn.microsoft.com/workshop/webcontrols/overview/overview.asp)
  • Detect Control Changes (http://www.aspnetpro.com/features/2003/03/asp200303de_f/asp200303de_f.asp)
  • ASP.NET Validation in Depth (http://msdn.microsoft.com/library/en-us/dnaspp/html/aspplusvalid.asp)
  • Using the Internet Explorer WebControls (http://msdn.microsoft.com/msdnmag/issues/03/02/ASPColumn).

Chapter 4 Working with the Page

or a
, ,
tag. The main limitation is that rich and complex tables are not supported. The HtmlTable class does not support HTML elements such as

Категории