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 ControlsThe 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 ControlsASP.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. Table 8.1 shows the ASP.NET server controls for displaying text and images.
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 ControlThis 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. Listing 8.1. Using the Panel Control
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 8.1 shows the example as it appears in Internet Explorer. Figure 8.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 CellsThis 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 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
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 8.2 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. Figure 8.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 ControlsAn 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. Table 8.2 shows the ASP.NET Web Forms controls for creating clickable hyperlinks.
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 ControlThis 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. Listing 8.3. The Declaration of the ImageMap Control and HotSpot Controls
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). Listing 8.4. Displaying the Value of the HotSpot That Was Clicked
Figure 8.3 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. Figure 8.3. Using the ImageMap control to create a clickable image mapYou 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. Listing 8.5. Adding HotSpot Controls to an ImageMap Dynamically
For more details about the ImageMap control, see: http://msdn2.microsoft.com/library/7f9s61xx(en-us,vs.80).aspx. Example: The TreeView ControlA 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. Listing 8.6. The XML Source File for the TreeView Example
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 8.4 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. Figure 8.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. Listing 8.7. The XmlDataSource Control and TreeView Control Declarations
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 8.4. Listing 8.8. Handling the SelectedNodeChanged Event
For more details about the TreeView control, see: http://msdn2.microsoft.com/library/f74eswe6(en-us,vs.80).aspx. Input and Form ControlsASP.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. Table 8.3 summarizes all of these controls.
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 ControlThis 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 8.5), and you just have to provide a button to start the process. Figure 8.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. Listing 8.9. Declaring a FileUpload Control and Button to Start the Process
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. Listing 8.10. Handling an Uploaded File and Displaying Information About It
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 ControlsOne 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 Table 8.3, with the exception of the CustomValidator control. Figure 8.6 shows the example page when you first open it and click the Login button without entering sufficient digits into the first text box. Figure 8.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 8.7). If you enter valid values for the top two controls in the page and click Login, you will see that Page.IsValid returns TRue. Figure 8.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). Listing 8.11. The Controls for the Login Section of the Example Page
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 ControlThe 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" runat="server" HeaderText="The following errors were found:" /> Accessing the Validation Controls in CodeThe 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 8.7), 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. Listing 8.12. The Code to Handle the Events in the Validation Example Page
Figure 8.8 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. Figure 8.8. Displaying a message box on the client to indicate validation errors
For more details on the validation controls, see: CompareValidator: http://msdn2.microsoft.com/library/he3e5wby(en-us,vs.80).aspx CustomValidator: http://msdn2.microsoft.com/library/k40kfxx1(en-us,vs.80).aspx RangeValidator: http://msdn2.microsoft.com/library/afhtcss6(en-us,vs.80).aspx RegularExpressionValidator: http://msdn2.microsoft.com/library/6a1dyf95(en-us,vs.80).aspx RequiredFieldValidator: http://msdn2.microsoft.com/library/ycxs7t4x(en-us,vs.80).aspx ValidationSummary: http://msdn2.microsoft.com/library/2a9k273c(en-us,vs.80).aspx List and Grid ControlsMost 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 Table 8.4. 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.
Example: The BulletedList ControlThis 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 8.9 shows an example of the output generated by four BulletedList controls. Figure 8.9. Examples of the output generated by the BulletedList control
Listing 8.13 shows the declarations of the four controls in Figure 8.10. 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. Listing 8.13. The Declaration of the Four BulletedList Controls
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. Listing 8.14. The Server-Side Code in the BulletedList Example Page
For more details about the BulletedList control, see: http://msdn2.microsoft.com/library/k234932b(en-us,vs.80).aspx7. Example: The ListBox and DropDownList ControlsThis 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 8.11 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. Figure 8.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. Listing 8.15. The Declaration of the ListBox and DropDownList Controls
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. Listing 8.16. Populating the ListBox and DropDownList Controls
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. Listing 8.17. Displaying Information About the List Controls
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 ControlsWhile 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 Table 8.5) are discussed in more depth in Chapter 11. The WebParts controls (not listed here) are discussed in more depth in Chapter 13.
Example: The Calendar ControlThis 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). Listing 8.18. The Declaration of the Calendar Control
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 8.12). Figure 8.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 ControlThe 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. Listing 8.19. Handling User Selection in the Calendar Control
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 8.13 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 8.13 that the code in the example displays the ID and Title properties of the current step. Figure 8.13. An example of using the Wizard controlThe example Wizard has four steps, and the current one is automatically highlighted in the sidebar (although Figure 8.13 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. Listing 8.20. The Declaration of the Wizard Control
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. Listing 8.21. The Code to Handle the Events in the Wizard Example
Finally, clicking the Cancel button runs the WizardCancel routine, which just hides the Wizard control. Container ControlsSome 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. Table 8.6 lists and describes the specialist container controls.
Mobile ControlsThe 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 StylesheetsThe 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 TypeAs 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:
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. |