The ASP.NET Control Set






The ASP.NET Control Set

When building ASP.NET Web Form pages, it is vital to understand the range of controls that are available. You also need to know how the choice of controls affects the way that pages work and the way that you write code to implement the required server-side processes. The evolution of ASP.NET and Web programming in general means that often several different controls are available to implement a specific feature.

Standard HTML Server Controls

The standard HTML server controls generate the basic HTML elements, as reflected by the control names. In particular, this set of controls focuses on the HTML input-type controlsalthough there are many other types of controls in the 30 or so supplied in ASP.NET. This includes the HtmlGenericControl class, which ASP.NET uses if it encounters an HTML element with the runat="server" attribute that does not match any of the other HTML server controls.

The main advantage of the HTML server controls is that they are lightweight compared to the other ASP.NET controls. This might be a consideration if you build very complex pages, although in most cases the difference will only be noticeable when the server is under pressure or short of memory.

The HTML server controls expose properties named exactly as in the HTML declarations of the element. For example, the HtmlInputText control that implements a text box exposes the contents of the text box through the Value property, whereas all the other controls in the System.Web.UI.WebControls namespace use the more intuitive Text property.

All of the standard HTML server controls are in the System. Web.UI.HtmlControls namespace. A full list and a description of each one is available at http://msdn2.microsoft.com/library/tct4wcsd(en-us,vs.80).aspx.


If you build your pages using Visual Studio 2005 or Visual Web Developer, you will find that the designer does not automatically add the runat="server" attribute to these controls when you place them on a page. This means that they are not, at this point, server controlsthey are simply ordinary HTML elements that implement the controls in the browser. You must add the runat="server" attribute to the element yourself if you wish to interact with the control in your server-side code.

However, omitting it where server-side access is not required makes the page less resource-intensive. The browser will recognize and apply the attributes for these controls because they use the standard HTML attribute names. Therefore, the elements do not have to be server controls, and this is why Visual Studio omits the runat="server" attribute by default.

Text and Image Display Controls

ASP.NET provides a set of controls that display content without themselves being interactive. The most commonly used are the Label and Image controls, though there are other controls that you can use to display non-interactive content. Like all of the ASP.NET server controls, other than the HTML server controls described in the preceding section, the property names are consistent, and (in most cases) differ from the attribute names generated when the page renders to the browser. This is a perfect example of how ASP.NET brings Web programming more into line with normal application-style approaches by hiding the "third view" (the HTML) from developers and allowing them to concentrate on building the interface and then writing code.

Bear in mind that you do not have to use a control to display content. You can place text and normal declarative HTML elements in the page, just as Web developers have always done. When using a tool such as Visual Studio 2005, you can format and color this text without having to go into Source view and work directly with the HTML. You can also use the toolbar options to create bulleted and numbered lists, justify the text, and specify the font and text size. Figure shows the ASP.NET server controls for displaying text and images.

Text and Image Display Server Controls

Control

Description

Image

Displays an image specified as the ImageUrl property. This can be a static image file (usually a GIF, PNG, or JPG image), or an animated GIF image.

Label

Displays a static text string specified as the Text property. This string can contain HTML markup, if required. At runtime, the control generates an HTML <span> element to contain the text.

Literal

Displays a static text string specified as the Text property. Unlike the Label control, however, the Literal control adds no HTML or other content of its own. It simply places the value of the Text property into the page at the location of the control. This value can contain HTML and other markup or content. It has a Mode property that specifies how the control translates or modifies the content at runtime. It can also remove unsupported elements depending on the current client type, and HTML-encode the content. A useful application of this control is the ability to show and hide blocks of content by setting the Visible property at runtime.

Panel

Generates either an HTML <div> element or a single-column single-cell HTML <table>, depending on the client type, and inserts the text or content specified as the Text property of the control. Setting the border and background color properties provides a useful technique for generating contrasting areas of content within a page. The GroupingText property allows a caption to appear at the top of the Panel content, and a fixed size Panel can display scrollbars.

Table

Generates an HTML <table> to which you dynamically add TableHeaderRow, TableRow, and TableFooterRow controls, each of which then contains a series of TableHeaderCell or TableCell controls. Use this control when you want to build tables dynamically and/or access the rows and cells in server-side code. In Visual Studio, for tables that do not require these features, use the Table HTML fragment available from the HTML section of the Toolbox, which does not generate the runat="server" attribute on the table, the rows, or the cells.


A list of all the ASP.NET Web Forms controls in the System.Web.UI.WebControls namespace is available at http://msdn2.microsoft.com/library/8bhzsw6t(en-us,vs.80).aspx.


All Web Forms controls (server controls other than the standard HTML controls) are declared in the source of the page as elements with the prefix "asp" and must include the runat="server" attribute within the control declaration element. Visual Studio adds this automatically. Without it, processing of the element within the source of the page to generate the appropriate HTML content does not occur. Instead, the client receives only the element declaration itself, which the browser ignores because it does not recognize the "asp" namespace. If you find that controls are not appearing on a page when you expect them to be, use the View | Source option in your browser to see what the client is actually receiving.

There is not enough space in this chapter to demonstrate all of the ASP.NET controls, though you will see them all used in various ways throughout this book. However, in this chapter you will see how some of the more useful controls, and their specific features, can be used. For example, the next two sections demonstrate the basic ways you can use the Panel and the Table controls.

Example: Using the Panel Control

This example demonstrates how you can use a Panel control to create an area on the page for the display of text or other content. The Panel control generates an HTML <div> element or a single-column single-row table, depending on the browser that accesses the page. Listing 8.1 shows the declarations of the control as they appear in Source view. You can, of course, set the properties of the Panel controls and enter the text content in Design view.

Using the Panel Control

<asp:Panel id="MyPanel1" Width="200" Height="100" ScrollBars="Vertical"
           BorderStyle="Solid" BorderWidth="1" runat="server">
  This is some test text for the Panel control to demonstrate ...
</asp:Panel>

<br /><br />

<asp:Panel id="MyPanel2" Width="200" Height="100"
           BorderStyle="Solid" BorderWidth="1" runat="server"
           Direction="RightToLeft" ScrollBars="Vertical">
  This is some test text for the Panel control to demonstrate ...
</asp:Panel>

<br /><br />

<asp:Panel id="MyPanel3" Wrap="false" Width="200" Height="100"
           BorderStyle="Solid" BorderWidth="1" runat="server"
           ScrollBars="Both">
  Scroll bars are useful when the text cannot<br />be wrapped ...
</asp:Panel>

<br /><br />

<asp:Panel id="MyPanel4" Width="200" runat="server"
           GroupingText="My Panel">
  This is some test text for the Panel control to demonstrate ...
</asp:Panel>

Notice how the Width and Height properties specify the size of the panel, and that you can also specify the addition of scroll bars and the text direction within the panel. The last panel demonstrates the use of the GroupingText property to generate an HTML <fieldset> and <legend> instead of the more usual <div> or HTML table. Figure shows the example as it appears in Internet Explorer.

1. The Panel control example


For more details about the Panel control, see: http://msdn2.microsoft.com/library/58dzaz0a(en-us,vs.80).aspx.


Example: Using the Table Control and Associated Header Cells

This example demonstrates how you can generate HTML tables dynamically using the Table, TableHeaderRow, TableRow, TableHeaderCell, and TableCell controls. Each cell is added to the Cells collection of an appropriate row type, which is then added to the Rows collection of the Table.

The example also illustrates how you can improve the accessibility of your HTML tables using the new AssociatedHeaderCellID property of the ASP.NET TableCell class. The AssociatedHeaderCellID property accepts an array containing the ID of the row and column header cells that apply to the current cell, allowing non-visual user agents and specialized page readers to display the values in these header cells. This makes it much easier for users of these types of devices to assimilate the contents of a table without actually being able to see the layout.

Note

When a browser renders an HTML table, comprehending the information it contains is generally a matter of scanning the rows and columns and mentally relating them with the header descriptions for each row. Often the table is like a spreadsheet in design, where each cell value in the body relates to the description for the column and the row where it resides. For most users, this just involves looking at the header and the left-hand row to locate the desired descriptions, and then scanning down and across to the cell where they meet. However, for users of non-visual browsers and user-agents, this is hard to do. Their browser will usually iterate through the table row by row, and it is easy to lose track of which header description each cell in the row relates to. To assist such users, HTML 4.0 includes the headers attribute for a table cell, which should be set to a list of the header cell ID values for the header and row description that this cell relates to. This way, the browser can extract the header and row descriptions as it iterates through the cells in each row and present them to the user in a suitable manner.


The example page contains just an empty Table control, declared like this:

<asp:Table id="MyTable" GridLines="Both" CellPadding="5"
           runat="server" />

Listing 8.2 shows the code in the Page_Load event handler that creates the table. Each header cell, including the first cell in each row (the header for the row), has an ID that is made up of the text "HDesc" and the column index, or "RDesc" and the row index. To make it easy to see the values of the ID, it is copied into the ToolTip property of these cells as well.

Listing 8.2. Creating the Table in the Page_Load Event Handler

public void Page_Load()
{
  Int32 iRows = 4;
  Int32 iCols = 3;
  TableRow oRow;
  TableCell oCell;

  // create header row, setting ID of each cell
  oRow = new TableHeaderRow();
  for (Int32 iColCount = 0; iColCount <= iCols; iColCount++)
  {
    oCell = new TableHeaderCell();
    oCell.ID = "HDesc" + iColCount.ToString();
    oCell.Text = "Header" + iColCount.ToString();
    oCell.ToolTip = "ID = '" + oCell.ID  + "'";
    oRow.Cells.Add(oCell);
  }
  MyTable.Rows.Add(oRow);

  // create data rows
  for (Int32 iRowCount = 0; iRowCount < iRows; iRowCount++)
  {
    // first cell is a <th> "header" containing description of row
    oRow = new TableHeaderRow();
    oCell = new TableHeaderCell();
    oCell.ID = "RDesc" + iRowCount.ToString();
    oCell.Text = "RowDescription" + iRowCount.ToString();
    oCell.ToolTip = "ID = '" + oCell.ID + "'";
    oRow.Cells.Add(oCell);
    // remaining cells are data <td> elements
    for (Int32 iColCount = 1; iColCount <= iCols; iColCount++)
    {
      oCell = new TableCell();
      oCell.Text = "Row" + iRowCount.ToString() + " Col"
                 + iColCount.ToString();
      // add HTML "headers" attributes to cell
      oCell.AssociatedHeaderCellID = new String[2]
                                  {"HDesc" + iColCount.ToString(),
                                   "RDesc" + iRowCount.ToString()};
      // copy into tooltip so as to make visible in page
      oCell.ToolTip = "AssociatedHeaderCellID = '"
                    + oCell.AssociatedHeaderCellID[0] + " "
                    + oCell.AssociatedHeaderCellID[1] + "'";
      oRow.Cells.Add(oCell);
    }
    MyTable.Rows.Add(oRow);
  }
  // create footer row
  oRow = new TableFooterRow();
  for (Int32 iColCount = 0; iColCount <= iCols; iColCount++)
  {
    oCell = new TableCell();
    oCell.ID = "FDesc" + iColCount.ToString();
    oCell.Text = "Footer" + iColCount.ToString();
    // add HTML "headers" attributes to cell
    oCell.AssociatedHeaderCellID = new String[1]
                               { "HDesc" + iColCount.ToString() };
    // copy into tooltip so as to make visible in page
    oCell.ToolTip = "AssociatedHeaderCellID = '"
                  + oCell.AssociatedHeaderCellID[0] + "'";
    oRow.Cells.Add(oCell);
  }
  MyTable.Rows.Add(oRow);
}

When creating the rows for the body of the table, the code creates a String array containing the column header ID and row header ID that apply to this cell, and then sets these on the cell using the AssociatedHeaderCellID property. Again, this is copied into the ToolTip property to make it easy to see the results when viewing the page. The AssociatedHeaderCellID property is also set for the footer cells, but this time it uses just the ID of the appropriate header cell.

Figure shows the result. To see the way that the AssociatedHeaderCellID property adds attributes to the cells in a table, move your mouse pointer over the header, body, and footer rows to see the cell ID or the value of the AssociatedHeaderCellID property, or view the source for this page in your browser and look for the headers attributes.

2. The dynamically generated Table control with the Headers attributes set on each cell


For more details about the Table control, see: http://msdn2.microsoft.com/library/sdw1fhcy(en-us,vs.80).aspx.


Hyperlink and Navigation Controls

An understanding of the specific behavior of different types of controls is vital. As an example, consider the situation where you need to implement a hyperlink in your page. You can generate a hyperlink using a normal HTML <a> element, an <a> element implemented as an HtmlAnchor server control, an ASP.NET Hyperlink server control, or a more complex control such as a HyperLinkField column in a list control or an ImageMap control. However, other controls such as a LinkButton, a CommandField column in a grid control, and several other rich controls such as the Menu and Wizard can also generate "normal" underlined hyperlinks in the page.

The difference is that the latter set of controls generates a postback to the same page when clicked, where the event-driven architecture of ASP.NET can produce the effect of a normal application form (hence, the name Web Forms). The former controls cause navigation (generally to a different page) rather than a postback, and so the type of control you choose is obviously vitally important. Later in this chapter, you will see more discussion about the postback architecture and the event-driven approach to Web programming in ASP.NET 2.0. Figure shows the ASP.NET Web Forms controls for creating clickable hyperlinks.

Hyperlink and Navigation Server Controls

Control

Description

HyperLink

Generates simple text hyperlink using an HTML <a> element, with the destination URL specified as the NavigateUrl property. You can display a clickable image instead of text by setting the ImageUrl property (the control automatically hides the image border in this case). Note, however, that the embedded image (an <img> element within the <a> element) is not a server control, and so you cannot interact with the <img> element serverside at runtime.

ImageButton

Generates an HTML <input type="image"> element using the image specified as the ImageUrl property, and causes a postback to the server rather than navigation to another page. However, cross-page posting (posting of the form to a different page) is possible by specifying the destination URL as the PostBackUrl property of the control. Another useful feature is that the X and Y coordinates of the mouse-pointer within the image are available in the event handler that handles the Click event of this control.

ImageMap

A common navigation scenario is the use of a clickable image, where each region navigates to a different page. While this is achievable with an ImageButton control, it is not an ideal approach (in terms of its accessibility to all users or in terms of its provision of an intuitive interface) because the result of clicking an area is not determinable by the client. The ImageMap control takes advantage of the client-side capabilities and provides a better solutionone that most specialist browsers can accommodate and display information about in a useful way. A series of hotspot child controls (CircleHotSpot, RectangleHotSpot, and PolygonHotSpot) define the areas of the image and the target URL of each one. By default, the hotspot controls cause navigation to the URL specified as the NavigateUrl property. Alternatively, each hotspot can cause a postback to the URL specified as the PostBackUrl property, depending on the setting of the HotSpotMode property.

LinkButton

Generates a hyperlink <a> element, and so looks just like a normal hyperlink. However, the href attribute is set to a JavaScript function that calls the submit method of the server-side form in the page, causing a postback rather than navigation to another URL. Cross-page posting (posting of the form to a different page) is possible by specifying the destination URL as the PostBackUrl property of the control.

Menu

Generates a complete hierarchical menu, with dynamic drop-down or fly-out submenus, from an XML sitemap file. This includes the client-side code to implement the dynamic behavior, and the hyperlinks that cause navigation to the specified pages. For more details, see Chapter 10.

SiteMapPath

Generates a "breadcrumb trail" that indicates the location of the current page within the hierarchy of the site, as described in the sitemap file. For more details, see Chapter 10.

TReeView

Generates a complete tree view, including all client-side code required to implement dynamic behavior. The tree view can be static, or dynamic with collapsible nodes. Each node can be a hyperlink, a checkbox, or static text.


Bear in mind that many other controls can initiate a postback to the server. These include the various button controls, and the many interactive controls such as lists and checkboxes that have the AutoPostback property set to true. Even the BulletedList control (described in the section on list controls) can display the items in the list as hyperlinks.

Example: The ImageMap Control

This example demonstrates how you can use the ImageMap control to create a clickable image map on the client, based on a series of HotSpot control instances defined within the ImageMap control declaration.

Listing 8.3 shows the declaration of the controls in this example, including several PolygonHotSpot controls and one CircleHotSpot control.

The Declaration of the ImageMap Control and HotSpot Controls

<asp:ImageMap id="UKMap" HotSpotMode="Postback" ImageUrl="UKMap.jpg"
              OnClick="MapClicked" runat="server">
  <asp:PolygonHotSpot PostBackValue="Northern Scotland"
       Coordinates="205,17,328,38,346,99,200,160,270,132,271,
                    130,268,132,270,130,201,159" />
  <asp:PolygonHotSpot PostBackValue="Southern Scotland"
       Coordinates="209,166,225,224,339,200,335,112" />
  ...
  <asp:CircleHotSpot PostBackValue="London"
       x="411" y="452" radius="11" />
  <asp:PolygonHotSpot PostBackValue="The Midlands"
       Coordinates="329,424,307,381,347,348,418,333,412,380,
                    407,429,399,439,358,428" />
  <asp:PolygonHotSpot PostBackValue="South East England"
       Coordinates="391,471,400,468,430,465,464,467,443,
                    494,411,506,394,494" />
  </asp:ImageMap>

When you click a hotspot in this example, a postback occurs and the Click event is raised for the ImageMap control. This causes the routine named MapClicked (as specified in the declaration of the ImageMap control) to execute. It simply shows the PostBackValue property of that HotSpot control (see Listing 8.4).

Displaying the Value of the HotSpot That Was Clicked

public void MapClicked(Object sender, ImageMapEventArgs e)
{
  Message.Text = "You selected " + e.PostBackValue;
}

Figure shows the result of running this example and clicking on the central area of the map. An alternative approach is to specify a URL for the NavigateUrl property of each HotSpot control so that clicking on the map navigates directly to the target page.

3. Using the ImageMap control to create a clickable image map


You can also add HotSpot instances to an ImageMap control dynamically, as shown in Listing 8.5. This code adds five RectangleHotSpot controls to the ImageMap, each being 100 pixels square and arranged in a column at the left-hand side of the image. Each HotSpot will cause navigation to the page name MyPage.aspx, with the index of the HotSpot that was clicked as the area value in the query string. Notice that the code also adds an alt attribute to each HotSpot using the AlternateText property. This will appear on the client as a pop-up tooltip, and is useful in non-visual user agents to assist navigation.

Adding HotSpot Controls to an ImageMap Dynamically

// dynamically create hot spots for ImageMap control
HotSpotCollection hs = MyImageMap.HotSpots;
for (Int32 i = 0; i < 5; i++)
{
  RectangleHotSpot r = new RectangleHotSpot();
  r.Top = (i * 100);
  r.Left = 0;
  r.Bottom = r.Top + 99;
  r.Right = 99;
  r.HotSpotMode = HotSpotMode.Navigate;
  r.NavigateUrl = String.Format("~/MyPage.aspx?area={0}", i);
  r.AlternateText = String.Format("Go to area {0}", i);
  hs.Add(r);
}

For more details about the ImageMap control, see: http://msdn2.microsoft.com/library/7f9s61xx(en-us,vs.80).aspx.


Example: The TreeView Control

A common way to display hierarchical information is with a treeView control. In Visual Studio, this control appears in the Navigation section of the Toobox, but it is useful for all kinds of tasks. This example demonstrates how you can use it to display information from an XML file exposed through an XmlDataSource control. The XML file contains a list of prestige vehicles, with several models and the various (fictional) trim packages for each one. Listing 8.6 shows the XML file with some repeating elements removed for clarity.

The XML Source File for the TreeView Example

<Automobiles>
  <Manufacturer Make="Audi" WebSite="http://www.audi.com/">
    <Car Model="A4" Id="02347">
      <Package Trim="Sport Package"/>
      <Package Trim="Luxury Package"/>
    </Car>
    <Car Model="A6" Id="02932">
      <Package Trim="Sport Package"/>
      <Package Trim="Luxury Package"/>
    </Car>
    <Car Model="A8"  Id="09381">
      <Package Trim="Sport Package"/>
      <Package Trim="Luxury Package"/>
    </Car>
  </Manufacturer>
  ... other manufacturers here ...
</Automobiles>

This is bound to an XmlDataSource control declared in the page, as shown in Listing 8.6. Below this you can see the declaration of the treeView control, which specifies that the data will come from the XmlDataSource control by using the DataSourceID attribute. The ExpandDepth attribute specifies that the list is closed (with only the root node visible) by default, and the ShowLines attribute specifies that dotted lines will appear between each node when expanded. You can also set a wide range of properties that control the style and format of the tree items, and you can replace the default images used for the open and close buttons in the tree with your own if you wish. When the user clicks a node, the treeView control raises the SelectedNodeChanged event and the routine named ShowValue will execute.

Nested inside the treeNode declaration are the binding details for theXML file. By default, the treeView displays the name of each node in the XML file, but you can use the treeNodeBinding elements to specify how the binding to each node takes place. In this example, the first treeNodeBinding element specifies that the treeView should display the value of the Make attribute of the Manufacturer element as a hyperlink that navigates to the value of the WebSite attribute in the same element.

The remaining two treeNodeBinding elements specify that the treeView should just display the value of the Model attribute of the Car element and the value of the TRim attribute of the Package element. Because there is no NavigateUrlField specified, these links cause a postback to the server. Figure shows the example page, and you can see how the nodes in the XML file display as a clickable and expandable tree. You can also see the ToolTip for the Car element, and clicking this will open the appropriate manufacturer's Web site in a new browser window.

4. The TreeView example page showing the results of clicking a Trim node and then hovering over a Car node


Note

If you think of each element as a data row, the attributes are effectively the columns in the row and so it is similar to the techniques for creating BoundField controls in a GridView control when using a SqlDataSource controlas shown in Chapter 2.


The XmlDataSource Control and TreeView Control Declarations

<asp:XmlDataSource ID="XmlDataSource1" runat="server"
                   DataFile="~/ch08/XmlDataSource.xml" />
<asp:TreeView id="TreeView1" runat="server"
              DataSourceID="XmlDataSource1"
              ExpandDepth="0" ShowLines="true"
              OnSelectedNodeChanged="ShowValue">
 <DataBindings>
  <asp:TreeNodeBinding DataMember="Manufacturer" TextField="Make"
                       NavigateUrlField="WebSite" Target="_blank"
                       ToolTip="Visit this manufacturer's Web site" />
  <asp:TreeNodeBinding DataMember="Car" TextField="Model" />
  <asp:TreeNodeBinding DataMember="Package" TextField="Trim" />
 </DataBindings>
</asp:TreeView>

Listing 8.8 shows the code that handles the SelectedNodeChanged event, which runs when you click a node other than a Car node. The value of the clicked node is available directly from the SelectedValue property of the treeView control. However, you can also get a reference to the node itself using the SelectedNode property (this is similar to the way that most other list controls work, as you will see later in this chapter). The properties of the node include the DataPath, which returns the XPath expression the control uses to extract the value for the XML file, and the ValuePath, which is simply the path from the root node to the current node. All these values are visible at the top of Figure.

Handling the SelectedNodeChanged Event

public void ShowValue(Object sender, EventArgs e)
{
  Label1.Text = "You selected:" + TreeView1.SelectedValue + "<br />";
  Label1.Text += "DataPath is:" + TreeView1.SelectedNode.DataPath
              + "<br />";
  Label1.Text += "ValuePath is:" + TreeView1.SelectedNode.ValuePath
              + "<br />";
}

For more details about the TreeView control, see: http://msdn2.microsoft.com/library/f74eswe6(en-us,vs.80).aspx.


Input and Form Controls

ASP.NET 2.0 provides a set of controls that implement the range of interactive controls you see in a desktop application. These have the same names as the controls available in other environments such as VB.NET, and they provide features such as different types of button, various styles of text box, check boxes, and option (radio) buttons. They also all use a similar and standard set of property, method, and event names.

This convergence of control types, combined with the design-led programming environment of tools like Visual Studio 2005 and Visual Web Developer, means that the differences between traditional application development and Web development have considerably narrowed. This is, of course, part of the process of moving toward a common display language that Windows Vista and operating systems even further down the line will use.


In addition, a set of special controls can easily perform client-side and server-side validation of the data submitted by the user. Figure summarizes all of these controls.

Input and Form server controls

Control

Description

Button

Generates a standard "submit" button in the page, with the caption provided by the Text property. Causes a postback, and raises a Click event that you handle in your server-side code. You can use the SubmitBehavior property to specify that a click on the button will cause a postback through the same mechanism as a LinkButton (calling the submit method of the form) instead of the browser's normal submit behavior. Cross-page posting (posting of the form to a different page) is possible by specifying the destination URL as the PostBackUrl property of the control.

CheckBox

Generates an <input type="checkbox"> element in the page, which implements a checkbox in the browser. The Text property sets the caption next to the checkbox, displayed in a <span> element that encloses the complete control. The Checked property indicates whether the checkbox is ticked, and there is no Value property (due to the way that the browser submits the setting of a checkbox control). If the AutoPostBack property is TRue, the browser submits the page when the user changes the setting of the checkbox. The InputAttributes and LabelAttributes properties give access to the collection of attributes on the <input> and <span> elements, respectively, allowing fine control over the appearance and formatting.

FileUpload

Generates an <input type="file"> element in the page, which implements a textbox and button in the browser that enables uploading of files to the server. There is no Text property, and server-side code cannot set the file name. Server-side access to the posted file is through the PostedFile property, and the properties HasFile, FileBytes, FileContent, and FileName provide information about the uploaded file. The file size limit is set in the maxRequestLength section of the server's Machine.Config or Web.Config file.

HiddenField

Creates a hidden control in the page that is useful for storing values sent to or returned from client-side code (such as JavaScript). The browser sends the value back to the server when the user submits the page; it becomes available to server-side code as the Value property.

RadioButton

Generates an <input type="radio"> element in the page, which implements an option button (or "radio" button) in the browser. The Text property sets the caption next to the button, displayed in a <span> element that encloses the complete control. The Checked property indicates whether the option is selected. This is the only control that allows use of the same value for the name attribute in more than one control, accessed through the GroupName property. If the AutoPostBack property is true, the browser submits the page when the user changes the setting of the option button. The InputAttributes and LabelAttributes properties give access to the collection of attributes on the <input> and <span> elements, respectively, allowing fine control over the appearance and formatting.

TextBox

Generates a text entry control in the page. The type depends on the setting of the TextMode property, which is a value from the TextBoxMode enumeration. This can be SingleLine to generate an <input type="text"> element (a normal text box), MultiLine to generate a <textarea> element, or Password to generate an <input type="password"> element (a password entry box that displays dots or asterisks instead of the typed text). The Columns property defines the width in characters. When TextMode is SingleLine or Password, the MaxLength property specifies the maximum input length. When TextMode is MultiLine, the Rows property specifies the number of rows of text to display and the Wrap property controls text wrapping within the text box. If the AutoPostBack property is true, the browser submits the page when the user changes the text and then moves the input focus to another control.

Compare Validator

Attached to an input control on the page, this control compares the value against that in another control, against a specifically declared value, or just checks that the control value is of the specified data type. If validation fails, the browser does not submit the page and an error message can be shown.

Custom Validator

Attached to an input control on the page, this control performs server-side and client-side validation of the value using custom functions that you provide. If validation fails, the browser does not submit the page and an error message can be shown.

Range Validator

Attached to an input control on the page, this control checks if the value of that control falls between two specifically declared values. If validation fails, the browser does not submit the page and an error message can be shown.

Regular Expression Validator

Attached to an input control on the page, this control checks if the value of that control matches a regular expression you specify. If validation fails, the browser does not submit the page and an error message can be shown.

Requiredfield Validator

Attached to an input control on the page, this control checks if that control contains a value. If not, the browser does not submit the page and an error message can be shown.

Validation Summary

Displays a list of the validation errors found in the page, or in the current validation group.


The next two sections demonstrate the FileUpload control, and show how the validation controls can be used to simplify validation of input values in your Web pages.

Example: The FileUpload Control

This example demonstrates use of the FileUpload control to upload files from the client to the server over HTTP. The FileUpload control generates the TextBox and Browse button you see in the example page (see Figure), and you just have to provide a button to start the process.

5. Displaying information about an uploaded file using the FileUpload control


Listing 8.9 shows the declaration of the FileUpload control and a Button control for the user to start the upload process.

Declaring a FileUpload Control and Button to Start the Process

<asp:FileUpload id="MyFile" runat="server" />
<asp:Button id="btnUpload" Text="Go"
     OnClick="GetFile" runat="server" />

Listing 8.10 shows the code that runs when the Go button causes a postback to the server. Some details about the process are available as properties of the FileUpload control, and others are obtained from properties of the PostedFile instance exposed by the FileUpload control once upload is complete.

Handling an Uploaded File and Displaying Information About It

public void GetFile(Object sender, EventArgs e)
{
  if (MyFile.HasFile)
  {
    try
    {
      // get values from control
      lblResult.Text = "Uploading file '" + MyFile.FileName
                     + "'...<br />";
      // get values from PostedFile instance
      MyFile.SaveAs("C:\\temp\\uploaded_" + MyFile.FileName);
      lblResult.Text += "Received file '"
                     + MyFile.PostedFile.FileName + "'<br />"
                     + "Type: '" + MyFile.PostedFile.ContentType
                     + "'<br />Length: "
                     + MyFile.PostedFile.ContentLength.ToString()
                     + " bytes<br />"
                     + "Saved as: 'C:\\temp\\uploaded_"
                     + MyFile.FileName + "'";
    }
    catch (Exception ex)
    {
      lblResult.Text += "Cannot save uploaded file<br />" + ex.Message;
    }
  }
  else
  {
    lblResult.Text += "No file received";
  }
}

Remember that the default setting of the maximum file size to upload is 4096 bytes. You can change this, if necessary, by setting the maximum file (request headers) size you want to allow as the maxRequestLength attribute of the <httpRuntime> section of machine.config or web.config. Bear in mind that this might cause extended request times or open your server to denial-of-service attacks. For more details, see: http://msdn2.microsoft.com/library/w8fdw8xd(en-us,vs.80).aspx.


Example: The Validation Controls

One feature of building Web Form pages that collect data is ensuring that you validate data input by the user before you accept it. It is nice to do this client-side where possible, and avoid postbacks until the user fully completes the form. However, you must always validate (or re-validate) values on the server following a postback to protect your applications from spoofed pages or malformed requests.

The ASP.NET validation controls can perform client-side validation where the browser supports it, and always performs the same validation server-side afterwards. You can turn off client-side validation if you wish. The example we're using here demonstrates all of the validation controls listed in Figure, with the exception of the CustomValidator control. Figure shows the example page when you first open it and click the Login button without entering sufficient digits into the first text box.

6. Client-side validation when an error is encountered


In most modern browsers, the validation takes place client-side without causing a postback to the server. However, if you turn off client-side validation using the drop-down list box at the bottom left of the page and then click Login again, you will see that the page is submitted. This time, a message is shown at the bottom of the screen indicating that the IsValid property of the Page is falsein other words, validation failed for at least one control (see Figure). If you enter valid values for the top two controls in the page and click Login, you will see that Page.IsValid returns TRue.

7. Server-side validation when an error is encountered


The example page contains a great many controls declarationstoo many to list in full here. However, Listing 8.11 shows the controls in the top "Login" section of the page. Both TextBox controls have two validation controls attached. The RequiredFieldValidator checks that the TextBox contains a value, and the RegularExpressionValidator matches the value against a regular expression that signifies a valid value.

Note

With the exception of the RequiredFieldValidator, an empty control is considered as valid (although the CustomValidator will consider empty values as invalid if you set the ValidateEmptyText property of that control).


The Controls for the Login Section of the Example Page

User ID (6 numbers):
<asp:TextBox id="txtLogonUserID"
      TabIndex="1" Columns="10" runat="server"
      ToolTip="Must be 6 numbers, no spaces" />

<asp:RequiredFieldValidator id="valRequLogonUserID" runat="server"
      ValidationGroup="LoginGroup" ControlToValidate="txtLogonUserID"
      Display="Dynamic" ErrorMessage="You must provide a User ID">*
</asp:RequiredFieldValidator>

<asp:RegularExpressionValidator id="valRegexLogonUserID" runat="server"
      ValidationGroup="LoginGroup" ControlToValidate="txtLogonUserID"
      ValidationExpression="\d{6}" Display="Dynamic"
      ErrorMessage="Your User ID must be 6 numbers with no spaces">*
</asp:RegularExpressionValidator>

&nbsp; Password (no spaces):
<asp:TextBox id="txtLogonPWord"
      TabIndex="2" TextMode="Password" Columns="10" runat="server"
      ToolTip="Must be between 4 and 8 characters, no spaces" />

<asp:RequiredFieldValidator id="valRequLogonPWord" runat="server"
      ValidationGroup="LoginGroup" ControlToValidate="txtLogonPWord"
      Display="Dynamic" ErrorMessage="You must provide a password">*
</asp:RequiredFieldValidator>

<asp:RegularExpressionValidator id="valRegexLogonPWord"
runat="server"
      ValidationGroup="LoginGroup" ControlToValidate="txtLogonPWord"
      ValidationExpression="\S{4,8}" Display="Dynamic"
      ErrorMessage="Your password must be between 4 and 8 ...">*
</asp:RegularExpressionValidator>

<asp:Button id="btnLogon" ValidationGroup="LoginGroup"
     Text="Login" OnClick="DoValidate" runat="server" />&nbsp;

<asp:Button id="btnCancel" CausesValidation="false"
     Text="Cancel" runat="server" />

Each validation control is attached to its source control (a TextBox in this example) through the ControlToValidate attribute, and declares an error message to display when validation fails. The "content" (the text between the opening and closing tags) of each validation control is displayed in the page at the point where the validation control is located when validation fails, and the example page uses the common approach of an asterisk. The Display="Dynamic" attribute indicates that this text is removed from the page when the value is valid and so does not take up space. When Display="Static", the content is hidden, and a blank area shows in the page.

The ValidationGroup attribute allows you to have more than one set of validated controls on the same page. In the example, there is a "Login" section and a "Register" section, and the validation controls have a different value for the ValidationGroup attribute in each section. Only the validation controls within the validation group specified by the control that submits the page (a Button control in this example) carry out validation of their attached control values. If you only have one set of validation controls on a page, you can omit the ValidationGroup declaration and all the controls are then part of the default validation group.

Most controls that can submit a page (e.g., cause a postback) have the ValidationGroup property. They also have the CausesValidation property. By default, this is true so that validation takes place automatically on a postback. However, if you set it to false for a control, that control will not cause validation to occuron either the client or the server. This is useful for Cancel buttons, which allow the user to "escape" from the page even when client-side validation is enabled. The example page also uses this attribute on the two drop-down list controls at the bottom of the page so that they can post back to the server without requiring the user to fill in the controls on the page with valid values first.

Each validation control also has properties specific to the type of control that indicate valid values. In the RegularExpressionValidator, this is the ValidationExpression property. For the RangeValidator, you set the MaximumValue, MinimumValue, and Type properties. For example:

MaximumValue="75" MinimumValue="18" Type="Integer"

For the CompareValidator, you can set either the ControlToCompare property to the ID of another control in order to compare the two control values (as in the "Confirm Password" section of the example page) or the ValueToCompare property to specify a fixed value. You also use the Type property to specify the comparison type (Currency, Date, Double, Integer, or String). You can also set the Operator property to DataTypeCheck if you just want to confirm that the control contains a valid value of a specific type.

The ValidationSummary Control

The validation controls are responsible for managing validation of the other controls in the page. The ValidationSummary control links to all the validation controls in the page to display a list of the error messages from each one where validation failed. By default, this list displays in red text at the point where the control is located. The declaration of a ValidationSummary control specifies the validation group that it belongs to (so the example page contains two ValidationSummary controls) and the text to display above the list of error messages:

<asp:ValidationSummary ValidationGroup="LoginGroup"
     id="valSummaryMessage" runat="server"
     HeaderText="The following errors were found:" />

Accessing the Validation Controls in Code

The validation controls do all the work for you, and all you have to do is check the IsValid property of the Page to see if validation succeeded or failed when a postback occurs. The code in the example page displays the value of this property each time the page loads, as shown in the DoValidate routine in Listing 8.12 (which runs when either the Login or Register button causes a postback).

The other two event handlers are attached to the SelectedIndexChanged events of the two drop-down lists at the bottom of the example page. The SetClientValidation routine executes when the user changes the setting for client-side validation (as shown in Figure), and demonstrates how you can iterate through the collection of validation controls on the page using the Validators collection of the Page object. Each validation control inherits from BaseValidator, so this is the ideal choice of type for the for loop.

The second drop-down list allows you to turn on display of a client-side message box for the two ValidationSummary controls. This routine just sets the ShowMessageBox property of these ValidationSummary controls on the page to truethough you can specify this as an attribute in the control declaration if you always want message boxes to be shown.

The Code to Handle the Events in the Validation Example Page

public void DoValidate(Object sender, EventArgs e)
{
  lblRegisterMsg.Text = "Page.IsValid = " + Page.IsValid.ToString()
}

public void SetClientValidation(Object sender, EventArgs e)
{
  Boolean bClientSide = (lstClientValidate.SelectedValue == "Yes");
  foreach (BaseValidator validator in Page.Validators)
  {
    validator.EnableClientScript = bClientSide;
  }
}

public void SetMessageBox(Object sender, EventArgs e)
{
  Boolean bMessageBox = (lstMessageBox.SelectedValue == "Yes");
  valSummaryMessage.ShowMessageBox = bMessageBox;
  valRegisterMessage.ShowMessageBox = bMessageBox;
}

Figure shows the message box that appears when the ShowMessageBox property is TRue and there are invalid values in the controls in the current validation group.

8. Displaying a message box on the client to indicate validation errors



List and Grid Controls

Most Web applications deal with dataand one of the common ways to display data is as a list. It may be a list of products for sale, a list of incoming e-mail messages, a list of orders for a customer, or any other type of list. ASP.NET provides a range of controls specifically aimed at generating lists of items and displaying each item is a specific way. For example, you can display items as a list of bullet points, in a grid or table, in a list box or drop-down list, as a set of checkboxes or option buttons, or in some custom repeating format of your own. The list controls also make it easy to manipulate the contents and get the user's selection(s) when the page is submitted.

Most simple list controls (such as ListBox, DropDownList, CheckBoxList, RadioButtonList, and BulletedList) can be populated using the Items collection, which exposes a collection of ListItem instances that have a Text, Value, Selected, and Enabled property. More complex list controls (such as GridView and DetailsView) can be populated using the Fields collection, which exposes a collection of objects to represent the rows in the control.

However, a fundamental feature of all list controls is support for server-side data binding. This makes it easy to create lists in your pages, using a database, XML document, or a collection of items as the source. More details on the GridView, DetailsView, and FormView controls, server-side data binding, and using the data source controls, is contained in Chapters 3, 4, and 5.

The next two sections describe two of the controls listed in Figure. The first example looks at the BulletedList control, and the second looks at some of the ways you can work with the ListBox and DropDownList controls.

The List and Grid Server Controls

Control

Description

BulletedList

Generates an HTML <ol> ordered list or <ul> unordered list containing one or more <li> list items. Properties such as BulletStyle, BulletImageUrl, and First BulletNumber specify the appearance of the list items. The DisplayMode property specifies how the items provide any user interaction required (the items are displayed as a HyperLink, LinkButton, or plain text). Values are accessible through the Items collection, and the SelectedItem, SelectedValue, and SelectedIndex properties.

CheckBoxList

Generates a list of CheckBox controls, populated through either databinding or explicit addition of ListItem instances. The RepeatColumns, RepeatDirection, and RepeatLayout properties specify whether the checkboxes appear in ordinary "flow" layout, or in the rows of an HTML table containing one or more columns. If the AutoPostBack property is true, the browser submits the page when the user selects a different item in the list. Values are accessible through the Items collection, and the SelectedItem, SelectedValue, and SelectedIndex properties.

DataList

Generates a single-column HTML table, with the data items inserted into each row. Templates can create the structure and content for each row, if required. This control is lighter than the GridView and DataGrid, but still supports selection and editing of rows. Each row is accessible as a DataListItem through the Items collection of the control.

DetailsView

Displays one row from a data source as a single page, with the column names and values laid out verticallyas in a paper form. The Rows collection provides access to the content. It supports automatic row deletes and updates, plus the inserting of new rows. Templates can create the structure and content for each row, if required.

DropDownList

Generates an HTML <select size="1">... </select> element in the page. Each ListItem instance in the source data generates a nested <option> element. If the Auto PostBack property is true, the browser submits the page when the user selects a different item in the list. Values are accessible through the Items collection, and the Selected Item, SelectedValue, and SelectedIndex properties.

FormView

Displays one row from a data source as a single page, but without adding any layout or structure to display the values. Templates must be used to create the structure and content for each row. It supports automatic row deletes and updates, plus the inserting of new rows.

GridView

Displays multiple rows from a data source as a grid of columns and rows within an HTML table. Templates can create the structure and content for each column, if required. The Columns and Rows collections provide access to the content. It supports automatic row deletes and updates, and replaces the DataGrid control from earlier versions of ASP.NET (although this control is still available).

ListBox

Generates an HTML <select>...</select> element in the page with the number of rows visible specified as the Rows property. Each ListItem instance in the source data generates a nested <option> element. If the AutoPost Back property is true, the browser submits the page when the user selects a different item in the list. Values are accessible through the Items collection, and the Selected Item, SelectedValue, and SelectedIndex properties.

RadioButtonList

Generates a list of RadioButton controls, populated through either data binding or explicit addition of ListItem instances. The RepeatColumns, RepeatDirection, and RepeatLayout properties specify whether the radio buttons appear in ordinary "flow" layout, or in the rows of an HTML table containing one or more columns. If the AutoPostBack property is true, the browser submits the page when the user selects a different item in the list. Values are accessible through the Items collection, and the SelectedItem, SelectedValue, and SelectedIndex properties.

Repeater

Generates repeated sections of content from a data source, but provides no structure or layout information. Templates must be used to create the structure and content for each row. The Items collection provides access to the content. This is a very light control, and provides best performance in situations where no data updates occur. Each row is accessible as a DataListItem through the Items collection of the control.


Example: The BulletedList Control

This example demonstrates use of the BulletedList control. This control renders the contents of the source data as a series of bullets that can contain text or hyperlinks. Figure shows an example of the output generated by four BulletedList controls.

9. Examples of the output generated by the BulletedList control


Listing 8.13 shows the declarations of the four controls in Figure. The top-left list (the first one in Listing 8.13) uses all the default values for the properties of the list. The Text to display for each item in the list is specified within the opening and closing tags of the ListItem controls declared within the BulletedList control.

The bottom-left list (the second one in Listing 8.13) specifies a numeric format (BulletStyle="Numbered") and starts the list from the number 5 instead of the default of 1 (FirstBulletNumber="5"). It also uses serverside data binding to populate the list, by setting the DataSource property to a String array and calling the DataBind method. Alternatively, you can set the DataSourceID to the ID of a data source control to populate the list.

The top-right list (the third one in Listing 8.13) uses square bullets (BulletStyle="Square") and displays the ListItem instances as hyperlinks (DisplayMode="Hyperlink"). The ListItem controls in this list also specify both a Text and a Value property for each item, and the Value property provides the URL to navigate to when the item is clicked.

The bottom-right list (the last one in Listing 8.13) displays each link using a LinkButton (DisplayMode="LinkButton") and a custom image (BulletStyle="CustomImage" and BulletImageUrl="bullet.gif"). Clicking on an item in this list initiates a postback to the server and runs the routine named ShowItem because the BulletedList control declaration includes OnClick="ShowItem". The Value property of the selected ListItem is available in the event handler.

The Declaration of the Four BulletedList Controls

Basic list:
<asp:BulletedList id="List1" runat="server">
  <asp:listitem>Item 1</asp:listitem>
  <asp:listitem>Item 2</asp:listitem>
  <asp:listitem>Item 3</asp:listitem>
</asp:BulletedList>

Databound list:
<asp:BulletedList id="List2" DisplayMode="Text"
     BulletStyle="Numbered" FirstBulletNumber="5" runat="server" />

Hyperlink list:
<asp:BulletedList id="List3" DisplayMode="Hyperlink"
     BulletStyle="Square" Target="_blank" runat="server">
<asp:ListItem Text="DaveAndAl" Value="http://www.daveandal.net" />
<asp:ListItem Text="ASP.NET" Value="http://www.asp.net" />
<asp:ListItem Text="http://localhost" />
</asp:BulletedList>

LinkButton list:
<asp:BulletedList id="List4" DisplayMode="LinkButton"
     BulletStyle="CustomImage" BulletImageUrl="bullet.gif"
     OnClick="ShowItem" runat="server">
<asp:ListItem Text="Value 1" />
<asp:ListItem Text="Value 2" />
<asp:ListItem Text="Value 3" />
</asp:BulletedList>

Listing 8.14 shows how the code in the page populates the second (data-bound) list, and how it reacts to a click on the fourth (LinkButton) list. In the Page_Load event handler, the code calls a routine named GetListArray that generates a simple single-dimension array of three String values and then binds this array to the BulletedList control. The ShowItem routine runs when a LinkButton in the fourth list is clicked, and simply retrieves the SelectedIndex of that item within the list from the BulletedListEventArgs instance passed to this routine.

The Server-Side Code in the BulletedList Example Page

public void Page_Load()
{
  if (!Page.IsPostBack)
  {
    List2.DataSource = GetListArray();
    Page.DataBind();
  }
}

public String[] GetListArray()
{
  String[] aList = new String[3];
  for (Int32 iLoop = 1; iLoop <= 3; iLoop++)
  {
    aList[iLoop - 1] = "Bound item " + iLoop.ToString();
  }
  return aList;

}
public void ShowItem(Object sender, BulletedListEventArgs e)
{
  lblResult.Text = "Selected item index is: " + e.Index;
}

For more details about the BulletedList control, see: http://msdn2.microsoft.com/library/k234932b(en-us,vs.80).aspx7.


Example: The ListBox and DropDownList Controls

This example demonstrates some of the features of the ListBox, DropDownList, and ListItem controls. The ListBox and DropDownList controls are populated dynamically at runtime when the page first loads (in the Page_Load event handler) using some different approaches. The DropDownList then allows you to select and disable an entry in the ListBox control at the top of the page by setting the Enabled property of the appropriate ListItem to false. The properties of each ListItem, including the one that is disabled and therefore not visible (but still exists in the Items collection), are displayed below the DropDownList after you make a selection.

The values of the SelectedIndex and SelectedValue properties of the ListBox are also displayed, and you will see from experimentation that the disabled ListItem is still shown as selected, even if you disable it after selecting it. Figure shows the example page after selecting Item4 in the dropdown list. The techniques you see here are the same for all controls that contain a series of ListItem instances (a ListItemCollection), including CheckBoxList, RadioButtonList, BulletedList, ListBox, and DropDownList.

11. Working with the ListBox and DropDownList controls


Listing 8.15 shows the declaration of the two list controls. There are no <asp:ListItem> elements in the declaration, because the lists are populated dynamically at runtime. However, the DropDownList uses the AutoPostBack property to specify that the page is submitted as soon as the user changes the selection and that the routine named ShowValues will execute when this postback occurs.

The Declaration of the ListBox and DropDownList Controls

<asp:ListBox id="MyList" Rows="6" runat="server" />
<p />
Disable this item:
<asp:DropDownList id="MyDropDown" runat="server"
     AutoPostback="true" OnSelectedIndexChanged="ShowValues" />

Listing 8.16 shows the Page_Load event handler. This demonstrates several ways that you can populate list controls (besides server-side data binding). A for statement adds new ListItem instances to the lists, with each one specified as a new ListItem instance. This allows you to set the Text and Value properties. If you only want to set the Text property, you can use MyList.Items.Add("My Text Value") instead. You can also use the Insert method to add either a new ListItem or a text value, and access the items in the ListItems collection by index. You can see both of these techniques used in populating the DropDownList control in Listing 8.16.

Populating the ListBox and DropDownList Controls

public void Page_Load()
{
  if (!Page.IsPostBack)
  {
    // fill first ListBox
    // set the Text and Value properties of each ListItem
    for (Int32 i = 1; i <= 5; i++)
    {
      MyList.Items.Add(new ListItem("This is Item "
                                    + i.ToString(), i.ToString()));
    }

    // fill DropDownList setting just text of each ListItem
    // start at second item then insert first item and set value
    // shows different ways to populate the Items collection
    // notice that Value must correspond to the index (and not the
    // Value property) of the items in the ListBox above
    for (Int32 i = 2; i <= 5; i++)
    {
      MyDropDown.Items.Add(new ListItem("Item "
                         + i.ToString(), (i - 1).ToString()));
    }
    MyDropDown.Items.Insert(0, "Item 1");
    MyDropDown.Items[0].Value = "0";
  }
}

Listing 8.17 shows how you can access the values in a list control, in this case following a postback, to display the user's selection and other information about the list (these are generic techniques for all simple list controls). The code first iterates through the ListItems collection for the ListBox enabling all the ListItem instances in the list, and then disables the item in the ListBox that is selected in the DropDownList. Next, the code iterates through the list again, displaying the four properties of each ListItem. Finally, it displays the value of the SelectedIndex and SelectedValue properties for the ListBox control.

Note that if a list control allows multiple selections to be made (usually a ListBox is used in this case with the SelectionMode="Multiple" attribute), the SelectedIndex and SelectedValue properties return the text and value of the first item in the list that is selected. Iterating the list is the only way that you can determine which items are selected when multiple selections are permitted.

Displaying Information About the List Controls

public void ShowValues(Object sender, EventArgs e)
{
  // start by making all items visible (i.e. enabled)
  foreach (ListItem item in MyList.Items)
  {
    item.Enabled = true;
  }

  // disable entry in first list that is specified in second list
  MyList.Items[Int32.Parse(MyDropDown.SelectedValue)].Enabled = false;

  // display details of Items collection
  lblList.Text = "<b>Items in ListItemCollection:</b><br />";
  foreach (ListItem item in MyList.Items)
  {
    lblList.Text += "Text = '" + item.Text
                 + "',&nbsp; Value = '" + item.Value
                 + "'&nbsp; Enabled = " + item.Enabled.ToString()
                 + "&nbsp; Selected = " + item.Selected.ToString()
                 + "br />";
  }

  // display other properties of the first ListBox control
  lblList.Text += "<br />SelectedIndex property = "
               + MyList.SelectedIndex.ToString();
  lblList.Text += "<br />SelectedValue property = '"
               + MyList.SelectedValue + "'br />";
}

For more details about the ListBox control, see: http://msdn2.microsoft.com/library/fe97eda3(en-us,vs.80).aspx.

For more details about the DropDownList control, see: http://msdn2.microsoft.com/library/7wfh8284(en-us,vs.80).aspx.

For more details about the ListItem control, see: http://msdn2.microsoft.com/library/6bf5ha6h(en-us,vs.80).aspx.


Rich Controls

While there is no real definition of what makes up a rich control, there are many controls in ASP.NET that do not directly relate to a specific type of form element or control. Examples are the Wizard control that provides a base for building multistep Wizards, or the Calendar control that implements a complete clickable calendar within a single control. Rich controls generally consist of a collection of other basic controls, and they can save a great deal of time and effort when constructing your Web pages.

Some rich controls also interface directly and automatically with the underlying ASP.NET system. For example, the Login control links to the membership and role management system automatically implemented by ASP.NET 2.0. Likewise, the WebParts controls that you can use to build portal-style pages integrate with the personalization system in ASP.NET 2.0. The Login controls (listed in Figure) are discussed in more depth in Chapter 11. The WebParts controls (not listed here) are discussed in more depth in Chapter 13.

The Rich Controls and Login Controls

Control

Description

AdRotator

Generates an area on the page that contains a banner image. The banner is chosen in a semicontrollable random sequence from the banner details stored in an XML file specified for the AdvertisementFile property, or provided through server-side data binding. Values in the source data for each banner specify the navigation details and the relative weightings used to select the advertisement at runtime.

Calendar

Generates an interactive calendar that displays one month, and allows navigation between months and years. Dates are hyperlinks that cause a postback to the server, where the selected date, week, or month is available as the SelectedDate and SelectedDates properties.

MultiView

Provides a way to display one of a series of pages or views, each containing a selection of other controls. Each page or view is a View control instance, and navigation between the views is possible through Button controls that have specific CommandName values. The Views collection provides access to the collection of View instances, and the one currently displayed is set or read from the ActiveViewIndex property.

Wizard

This control also provides a series of pages or views, in a similar but more complex way than the MultiView control. It automatically provides the navigation features as links or buttons and a sidebar containing a list of steps, and accepts templates for defining the content and style of sections of the control. Each step or page in the Wizard is a WizardStep instance, exposed through a collection as the WizardSteps property. The currently displayed step is set or read through the ActiveStep property.

Xml

Copies the contents of an XML file or a dynamic XML source specified through the Document-Content or DocumentSource properties into the page at the location of the control. An XSLT transformation can be applied to the XML first using a stylesheet specified as the TRansform or TRansformSource property.

Login

Generates the text boxes and button required to implement a login page, and optionally a checkbox to specify persistence for the login when Forms authentication is used.

LoginName

Generates output indicating the login name of the current user, or nothing if the user is anonymous (not logged in).

LoginStatus

Generates a hyperlink with the text "Login" when the current user is anonymous (not logged in), and "Logout" when the current user has been authenticated (is logged in).

LoginView

Provides three templates used to display data about the currently logged in user, or a message if there is no logged-in user.

ChangePassword

Provides the controls required for a page that allows users to change their password, as stored in the ASP.NET personalization system.

CreateUserWizard

Provides the controls required by users when they create a new account, as stored in the ASP.NET personalization system.

PasswordRecovery

Provides the controls required for users to specify the reminder details to have a lost or forgotten password e-mailed to them.


Example: The Calendar Control

This example demonstrates use of the Calendar control with the default appearance and formatting. The calendar rendered in the browser allows selection of single dates, whole weeks, and whole months because the declaration sets the SelectionMode to "DayWeekMonth" (see Listing 8.18).

The Declaration of the Calendar Control

<asp:Calendar id="MyCal" runat="server"
     SelectionMode="DayWeekMonth"
     OnVisibleMonthChanged="MyCal_VisibleMonthChanged"
     OnSelectionChanged="MyCal_SelectionChanged" /><p />

The Calendar control declaration also specifies that code in the page should handle the VisibleMonthChanged and SelectionChanged events to display the date(s) selected, or the current and the previously selected months when the user navigates from one month to another (see Figure).

12. The Calendar control with a full week selected


Listing 8.19 shows the code of the event handlers for the VisibleMonthChanged and SelectionChanged events. It is easy to extract the values of the previous and current months in the VisibleMonthChanged event, because they are properties of the MonthChangedEventArgs instance passed to the event handler. The code formats these to display just the month name.

The code that handles the SelectionChanged event is a little more complicated. It queries the SelectedDates property to see if more than one date was selected. If so, it uses the SelectedDatesCollection that is available from the SelectedDates property to display a list of these. If only one date is selected, the code queries the SelectedDate property instead.

For more details about the Calendar control, see: http://msdn2.microsoft.com/library/yzb6d7wx(en-us,vs.80).aspx9.


Example: The Wizard Control

The final example in this chapter is the Wizard control. This control enables easy construction of multistep task-based data collection routines, just like the Wizards you are used to seeing in other types of applications and operating systems. The Wizard control looks after all the plumbing required to implement navigation between the individual Wizard steps, displaying the appropriate Previous, Next, Finish, and Cancel buttons, and optionally showing a list of steps in a "sidebar" next to the main Wizard area.

Handling User Selection in the Calendar Control

public void MyCal_VisibleMonthChanged(Object sender,
MonthChangedEventArgs e)
{
  // show the previous and current month names
  Label1.Text += "You changed the month from <b>"
              + e.PreviousDate.ToString("MMMM")
              + "</b> to <b>"
              + e.NewDate.ToString("MMMM") + "</b>";
}

public void MyCal_SelectionChanged(Object sender, EventArgs e)
{
  // get a collection of selected dates (if any)
  SelectedDatesCollection dates = MyCal.SelectedDates;
  if (dates.Count > 1)
  {
    // get a list of all dates in the selection
    Label1.Text += "<b>You selected</b>:<br />";
    foreach (DateTime dt in dates)
    {
      Label1.Text += dt.ToShortDateString() + "&nbsp;&nbsp; ";
    }
  }
  else
  {
    // just get and display the selected date
    Label1.Text += "<b>You selected</b>: "
                + MyCal.SelectedDate.ToShortDateString();
  }
}

The Wizard control is almost infinitely configurableyou can show or hide various sections, such as the navigation button area, the sidebar, and the header. You can populate it using templates, replace the interface elements with your own images, and specify style information for all the items. The Visual Studio designer also shows each step individually using a drop-down menu, so that you can build your Wizard in Design view.

The Wizard is a container control that holds individual WizardStep controls. You can declare these in your page, or generate them dynamically at runtime and add them to the WizardSteps collection of the Wizard control. Likewise, you can access the existing steps in code though this collection. Figure shows a simple Wizard. As you move from one step to another, the ActiveViewChanged event occurs, and you can access the current WizardStep instance from the ActiveStep property to display details. You can see in Figure that the code in the example displays the ID and Title properties of the current step.

13. An example of using the Wizard control


The example Wizard has four steps, and the current one is automatically highlighted in the sidebar (although Figure only shows three of these steps). Clicking the Finish button in step four hides the Wizard and displays the step history (in reverse order starting from the most recent step viewed) and the values of the controls in all of the steps. As you can see, this makes it easy to use the full set of values once the user completes the Wizard, rather than having to concern yourself with how you will store them between pages when you build your own Wizard equivalents.

Listing 8.20 shows the declaration of the Wizard control in the example page, with some of the WizardStep elements removed for clarity. Notice how the attributes of the Wizard element wire up the events to the event handlersthe example page handles the CancelButtonClick, FinishButtonClick, and ActiveStepChanged events. After the style declarations for the sidebar and navigation sections comes the WizardSteps element that contains the individual WizardStep elements.

The Declaration of the Wizard Control

<asp:Wizard id="MyWizard" runat="server"
     DisplaySideBar="true" DisplayCancelButton="true"
     OnCancelButtonClick="WizardCancel"
     OnFinishButtonClick="WizardFinish"
     OnActiveStepChanged="StepChanged"
     Backcolor="White" CellPadding="10" BorderColor="Black"
     BorderStyle="Ridge" BorderWidth="3" ActiveStepIndex="0">

  <SideBarStyle BackColor="#FFFFC0" VerticalAlign="Top" />
  <NavigationStyle BackColor="LightBlue" BorderStyle="None" />

  <WizardSteps>

    <asp:WizardStep id="Step1" Title="First Step" runat="server">
      <asp:Image runat="server" id="Image1"
                 Width="110px" Height="110px" AlternateText="Step 1"
                 ImageUrl="~/ch08/step1.gif" ImageAlign="Left"
                 style="margin-right: 20px; padding-bottom: 10px;" />
      This is step 1<br />
      <asp:TextBox id="txtStep1" Text="Step One Text" runat="server" />
    </asp:WizardStep>

    ... more WizardStep declarations here ...

    <asp:WizardStep StepType="Finish" id="Step4" Title="Final Step"
                    runat="server">
      <asp:Image runat="server" id="Image4"
                 Width="110px" Height="110px" AlternateText="Step 4"
                 ImageUrl="~/ch08/step4.gif" ImageAlign="Left"
                 style="margin-right: 20px; padding-bottom: 10px;" />
      This is step 4<br />
      <asp:TextBox id="txtStep4" Text="Step Four Text" runat="server" />
    </asp:WizardStep>

  </WizardSteps>

</asp:Wizard>

Each step in the example Wizard contains an image, the step number, and a text box containing some default text. The final step is declared as a "Finish" step (and so will contain the Finish button) by virtue of the StepType= "Finish" attribute. The equivalent StepType="Start" attribute could be included in the first WizardStep declaration, to ensure that it does not contain a Previous button. However, if these attributes are omitted, the Wizard control assumes that the first and last ones within the WizardSteps element are, respectively, StepType="Start" and StepType="Finish".

Listing 8.21 shows the code in the example page that handles the three events. The StepChanged routine runs when the active step changes and simply outputs the ID and Title properties of the current step. The ActiveStep property returns a WizardStepBase instance (from which the WizardStep type inherits).

Clicking the Finish button runs the WizardFinish routine, which extracts the step history as an ArrayList from the Wizard control using the GetHistory method, and iterates through. It then accesses the TextBox controls to extract the values from each step, and hides the Wizard control.

The Code to Handle the Events in the Wizard Example

public void StepChanged(Object sender, EventArgs e)
{
  // display details of current step
  WizardStep wstep = (WizardStep)MyWizard.ActiveStep;
  lblMessage.Text = "ActiveViewChanged event. ActiveStep is '"
                  + wstep.ID + "' - Title is '" + wstep.Title + "'";
}

public void WizardFinish(Object sender, WizardNavigationEventArgs e)
{
  // display history of steps (stored in reverse order)
  lblMessage.Text = "Step history:</b><br />";
  ArrayList steps = (ArrayList)MyWizard.GetHistory();
  foreach (WizardStep wstep in steps)
  {
    lblMessage.Text += wstep.ID + " Title: '" + wstep.Title + "'br />";
  }

  // display values in text boxes
  lblMessage.Text += "Control values:</b><br />'"
                  + txtStep1.Text + "'br />'"
                  + txtStep2.Text + "'br />'"
                  + txtStep3.Text + "'br />'"
                  + txtStep4.Text + "'br />";

  // hide the Wizard
  MyWizard.Visible = false;
}

public void WizardCancel(Object sender, EventArgs e)
{
  // display message and hide Wizard
  lblMessage.Text = "Canceled";
  MyWizard.Visible = false;
}

Finally, clicking the Cancel button runs the WizardCancel routine, which just hides the Wizard control.

Container Controls

Some controls in ASP.NET do not generate any user interface or content within the rendered page. These include the PlaceHolder control that is useful when you want to allocate a place on the page for sets of controls that you generate dynamically within your server-side code. There are also two controls, the ContentPlaceHolder and Content controls, used when you take advantage of the Master Page feature built into ASP.NET 2.0. Master Pages are discussed in more detail in Chapter 9.

However, bear in mind that many ASP.NET controls can also act as containers. Programmatically, most controls expose a collection named Controls, which contains references to all the ("child") controls that are contained within that control. You can use this collection, as you will see in examples throughout the book, to work with these child controls. The most common scenario is use of the Find method of the Controls collection, which returns a reference to a control you specify using its ID value. Figure lists and describes the specialist container controls.

Specialist Container Controls in ASP.NET

Control

Description

Content

Defines an area on a page whose content (text, HTML, controls, etc.) is inserted into a ContentPlaceHolder control on a Master Page at runtime. A page can contain more than one Content control, each specifying the ID of the target ContentPlaceHolder control. The Master Page file is defined in the Page directive, and the page can contain no other content.

ContentPlaceHolder

Defines an area on a Master Page where the content from a Content control will appear. Any existing content within the ContentPlaceHolder control is replaced by the Content control's content. If no Content control matches this ContentPlaceHolder, any existing content within the ContentPlaceHolder control is displayed.

PlaceHolder

Generates no output, and simply reserves a place on the page where code can dynamically add content at runtime by inserting child controls (of any type) into the Controls collection of the PlaceHolder control.

Substitution

Defines an area on the page that is never cached when output caching is defined for that page. ASP.NET always regenerates the content of the Substitution control, even if the remainder of the page is served from the output cache.


Mobile Controls

The final group of controls has a specific purpose outside building Web pages aimed at normal desktop Web browsers such as Internet Explorer and Mozilla Firefox. Increasingly, people use small-screen devices such as PocketPCs, Personal Digital Assistants (PDAs), and mobile cell phones to access the Internet. These devices may not support the full feature set of HTML, andin factmay not support HTML at all. Many cell phones only understand languages such as Wireless Markup Language (WML).

The Mobile Controls, originally added to ASP.NET version 1.0 as the Mobile Internet Toolkit, is a set of controls specially tailored to provide output that works on all kinds of devices and user agents. A full list of these controls, which reside in the System.Web.UI.MobileControls namespace, is available at http://msdn2.microsoft.com/library/361h4hy6(en-us,vs.80).aspx. You will see that there are some familiar controls such as TextBox, Label, and Panel as well as the validation controls. Most of the other controls are specialized for cell phones or designed to generate output that works well on small-screen devices.

Like the standard ASP.NET controls, the Mobile Controls use a series of device descriptions stored in configuration files within the Browsers subfolder of the usual .NET Framework folder (at %windir%/Microsoft. NET/Framework/[version]/CONFIG/Browsers/). These descriptions include a great deal of detail about each device, including things like the markup languages it supports, the screen resolution, and the font styles as well as whether support is available for cookies, images, or tables.

However, the Mobile Controls make much more use of these feature lists, by changing almost every aspect of the output they generateright down to the markup language itself. This means that you can build your site to give the appearance and include the content you want, and then leave it to the controls to generate automatically the appropriate output for each device that visits.

You may now have decided just to use the Mobile Controls for all of your pages, so that the site is compatible with all types of visiting devices. However, this is not generally practical. The range of controls in the Mobile Controls set is limited, and many do not provide the interactivity of the standard controls or the same opportunities for changing the appearance. They are also more processing-intensive because of the detection and format translation they must perform.

However, the main reason that a single page containing the Mobile Controls is not practical for all of your visitors is that you really do have to design your pages to suit either a large desktop screen or a small screen. It is very difficultif not impossibleto get optimum results in both using the same selection of controls and content. Instead, you should consider building two sets of pages. The good news is that the Mobile Controls expose similar interfaces to the standard controls, using the same property names where this is possible, and so you can use most of your existing server-side code, components, and business logic for both sets of pages.

Chapter 14 looks in more detail at the issues of building pages that work on multiple devices, that can be read by different types of specialist user agents, and that are localized for different cultures and languages.

Layout ApproachesTables and Stylesheets

The traditional technique for laying out items on a Web page, other than the default "flow layout" where each item just follows the preceding one, is the use of HTML tables. These have some advantages, being easy to construct and automatically adapting themselves to the browser window size. However, their use today is regularly discouraged in favor of Cascading Style Sheets (CSS). These allow separation of content from display and layout information, and allow specialized user agents (such as page readers for visually impaired users) to disregard the style and layout information in order to better present the content to the user.

ASP.NET provides support for both approaches, andin some casesmakes its own choice on whether tables or CSS are used to render content. Controls such as the GridView, DataList, Panel, and Login always generate HTML tables. However, all controls expose properties that allow you to specify styling information. You can set the Style property of a control using the appropriate set of CSS selectors (style values), or you can set the CssClass property to the name of a style defined in your CSS stylesheets. Visual Studio 2005 and Visual Web developer also provide excellent support for generating stylesheets and control-level style information through a stylesheet editor and Style property dialogs.

Choosing the Appropriate Control Type

As you can see from the preceding sections, there are a great many different controls you can choose from when building Web pages. Deciding which one to use involves some knowledge of their capabilities and specific features, which you will accumulate over time. However, there are some general rules that are useful:

  • When you will not access the element or control in the page from within your server-side code, you should consider using a standard HTML element without the runat="server" attribute. This avoids ASP.NET creating an instance of the control within the control tree and allows it simply to render the HTML in the source of the page direct to the client.

  • If you are accessing the properties, methods, or events of a control in client-side script only (for example in JavaScript, DHTML/CSS, or for interaction with an ActiveX control or Java file upload applet) you do not need to create them as server controls. Again, they can be standard HTML elements without the runat="server" attribute.

  • If the element is a hyperlink opening the same or (more likely) a different page or URL, and you do not need to pre-process the element attributes (for example, you do not need to dynamically set the URL), you can use standard HTML elements without the runat="server" attribute.

  • If all your server-side code is in the Page_Load event handler and you have no event handlers for other controls, you can use a standard HTML <input type="submit"> element or an <input type="image"> element without the runat="server" attribute to submit the page to the server.

In most other cases, you will require server controls that contain the runat="server" attribute. However, bear in mind that sometimes it is useful simply to add this attribute to the HTML element to convert it to a server control, rather than using the ASP.NET Web Forms controls (the controls with the "asp" prefix). This can produce a lighter-weight page with less processing requirements in situations where you have many controls on the page.



 Python   SQL   Java   php   Perl 
 game development   web development   internet   *nix   graphics   hardware 
 telecommunications   C++ 
 Flash   Active Directory   Windows