Working with Data Source Controls and Data-Bound Controls in ASP.NET

  • 12/10/2010

Lesson 2: Working with Data-Bound Web Server Controls

Lesson 1 showed you how to connect to various data sources by using the data source controls. After it has been accessed, the data needs to be displayed to users so that they can interact with it. ASP.NET provides a large set of controls for doing so. These controls are referred to as data-bound controls. Data-bound controls are controls that provide web-based UI output (HTML and JavaScript) and also bind to data on the server.

This lesson presents an overview of data binding in ASP.NET. It then presents the many data-bound controls found inside ASP.NET.

Introducing Data-Bound Controls

The data-bound controls in ASP.NET can be classified as simple, composite, hierarchical, or visualization controls. Simple data-bound controls are the controls that inherit from ListControl. Composite data-bound controls are classes that inherit from CompositeDataBoundControl, such as GridView, DetailsView, FormView, and similar controls. Hierarchical data-bound controls are the Menu and TreeView controls. Finally, the Chart control is a data visualization control that inherits directly from DataBoundControl.

The Microsoft .NET Framework provides several base classes that are used to provide common properties and behavior for the concrete data-bound controls. These classes form the basis of many of the data-bound controls. In this way, all of the data-bound controls work in a similar manner. Figure 12-8 shows the hierarchy of the base classes used for data-bound controls in ASP.NET.

Figure 12-8

Figure 12-8 The base data-bound class hierarchy.

The BaseDataBoundControl is the first control in the hierarchy (inheriting from WebControl). This class contains the DataSource and DataSourceID properties used in data binding. The DataSource property gets or sets the object that the data-bound control uses to retrieve its data items. This property is most often used when binding to data in code, and it was the default binding property in early versions of ASP.NET. However, the DataSourceID property was introduced later to provide a declarative means of binding to data. You use the DataSourceID property to get or set the ID of a data source control that contains the source of the data, such as the data source controls discussed in Lesson 1. You typically set either the DataSource or the DataSourceID property (not both). If both properties are set, the DataSourceID takes precedence.

You can bind a data-bound web control to any data that implements IEnumerable, IListSource, IDataSource, or IHierarchicalDatasource. The data-bound control will automatically connect to the data source at run time by calling the DataBind method (which also raises the DataBound event). You can also call this method yourself in code to force a rebinding of data to the control.

The next control in Figure 12-8, HierarchicalDataBoundControl, inherits from the BaseDataBoundControl. It is the parent class for controls that display hierarchical data such as the Menu and TreeView controls.

The DataBoundControl inherits from the BaseDataBoundControl and is the parent class to the CompositeDataBoundControl, ListControl, and Chart. These classes are the parent classes to controls that display tabular data such as the GridView and DropDownList controls. The DataBoundControl control’s DataMember property is a string data type that is used when the DataSource contains more than one tabular result set. In this scenario, the DataMember property is set to the name of the tabular result set that is to be displayed.

Mapping Fields to Templates

Templated binding can be used on controls that support templates. A template control is a control that has no default UI. The control simply provides the mechanism for binding to data. The developer supplies the UI in the form of inline templates. The template can contain declarative elements such as HTML and Dynamic Hypertext Markup Language (DHTML). The template can also contain ASP.NET data-binding syntax to insert data from the data source. Controls that support templates include GridView, DetailsView, and FormView, among others. A typical control might allow the following templates to be programmed:

  • HeaderTemplate This is an optional header, which is rendered at the top of the control.

  • FooterTemplate This is an optional footer, which is rendered at the bottom of the control.

  • ItemTemplate The item template is rendered for each row in the data source.

  • AlternatingItemTemplate This is an optional template; if it is implemented, every other row is rendered with this template.

  • SelectedItemTemplate This is an optional template; if implemented, the template is used to render a row that has been selected.

  • SeparatorTemplate This is an optional template that defines the markup used to indicate the separation of items from alternate items.

  • EditItemTemplate This is an optional template that is used to render a row that is in edit mode. This usually involves displaying the data in a TextBox instead of a Label control.

Some of the upcoming examples look at defining these templates for specific controls. For the most part, this process is similar regardless of the control with which you are working.

Using the DataBinder Class

In addition to automatically binding data with data-bound controls, you sometimes will need to have more granular control over which fields get bound to which controls on your page. For this, ASP.NET provides the DataBinder class. This class can be used to define code inside your script that controls how a data source is bound.

The DataBinder class provides the static Eval method to help bind data in this manner. The Eval method uses reflection to perform a lookup of a DataItem property’s underlying type by looking at the type metadata that is stored in the type’s assembly. After the metadata is retrieved, the Eval method determines how to connect to the field. This makes writing data binding syntax on your page an easy task. For example, the following shows binding to the Vin property of a Car object:

<%# Eval("Vin") %>

The Eval method also provides an overloaded method that allows a format string to be assigned as part of the data binding. As an example, if you were to bind to a field called Price, you can modify the display of this field by providing currency formatting, as shown here.

<%# Eval("Price", "{0:C}") %>

The Eval method is great for one-way (or read-only) data binding. However, it does not support read-write data binding and thus cannot be used for insert and edit scenarios. The Bind method of the DataBinder class, however, can be used for two-way data binding. This makes Bind preferable when you need to edit or insert records.

Just like the Eval method, the Bind method has two overloads: one without a format and one with the format parameter. The code for the Bind method looks the same as that for the Eval method. However, the Bind method does not work with all bound controls. It only works with controls that support read, insert, update, and delete scenarios, such as GridView, DetailsView, and FormView.

Simple Data-Bound Controls

Several controls in ASP.NET provide basic, list-based data binding. These controls are not meant to work with pages of data or provide elaborate editing scenarios. Instead, they allow you to provide a list of data items with which a user can operate. Figure 12-9 shows these simple data-bound controls, including their common base class, ListControl.

Figure 12-9

Figure 12-9 The ListControl class hierarchy.

The ListControl class is an abstract base class that provides common functionality for the classes that derive from it. This functionality includes an Items collection, which is a collection of ListItem data objects. Each ListItem object contains a Text property that is displayed to the user and a Value property that is posted back to the web server.

You can add items to the ListItems collection in code or declaratively in markup. You can also bind data to the controls that inherit from ListControl by setting the DataSource property (or the DataMember property if the source data has more than one table). You can also declaratively data-bind a ListControl-derived object by setting the DataSourceID property to the ID of a valid data source control on your page.

You can also choose the fields in your results that you will bind to the ListItem.Text and ListItem.Value properties. You can do so in code or through declarative markup by using the DataTextField and DataValueField properties, respectively. The text displayed for each item in the list control can also be formatted by setting the DataTextFormatString property. As an example, the following shows the declarative syntax for a ListBox bound to a SqlDataSource that provides the Northwind shipper table data.

<asp:ListBox
    ID="ListBox1"
    runat="server"
    DataSourceID="SqlDataSource1"
    DataTextField="CompanyName"
    DataValueField="ShipperID">
</asp:ListBox>

The SelectedIndex property lets you get or set the index of the selected item in the ListControl. By using the SelectedItem property, you can access the selected ListItem object’s properties. If you only need to access the value of the selected ListItem, use the SelectedValue property.

The ListControl also contains the property called AppendDataBoundItems, which can be set to true to keep all items that are currently in the ListControl, in addition to appending the items from the data binding. Setting this property to false clears the Items property prior to binding the data.

The ListControl also provides the SelectedIndexChanged event, which is raised when the selection in the list control changes between posts to the server. Recall that you need to set a control’s AutoPostback property to true if you intend it to post back to the server for this type of event.

The DropDownList Control

The DropDownList control is used to display a list of items to users to allow them to make a single selection. The Items collection contains the child ListItem objects that are displayed in the DropDownList control. To determine the item that the user has selected, you can retrieve the SelectedValue, SelectedItem, or SelectedIndex property.

In the following example, a DropDownList control is bound to a SqlDataSource control that returns data from the Territories database table in the Northwind database. Notice that the DataTextField and DataValueField attributes are set to fields in the database table.

<asp:DropDownList runat="server" Width="250px"
    ID="DropDownList1"
    DataSourceID="SqlDataSource1"
    DataTextField="TerritoryDescription"
    DataValueField="TerritoryID" >
</asp:DropDownList>

Suppose that this page also contains a button with an event that captures the selected item from the DropDownList and displays it on a label. This button control’s event code might look as follows.

Sample of Visual Basic Code

Label1.Text = "You selected TerritoryID: " & DropDownList1.SelectedValue

Sample of C# Code

Label1.Text = "You selected TerritoryID: " + DropDownList1.SelectedValue;

When the page is run and the user makes a selection in the DropDownList control and then clicks the button, the results are displayed in the label.

The ListBox Control

The ListBox control is used to select and display items from a longer list rather than one at a time as done in the DropDownList. With the ListBox control, users can see more data at once. You can also configure the control to allow the selection of a single item or multiple items. To do so, you set the SelectionMode property. The ListBox control also has the Rows property, which is used to specify the number of items displayed on the screen. The following shows an example of a ListBox that is set to allow multiple selections and show up to 13 rows.

<asp:ListBox runat="server" Height="225px" Width="275px"
    ID="ListBox1"
    Rows="13"
    DataSourceID="SqlDataSource1"
    DataTextField="TerritoryDescription"
    DataValueField="TerritoryID"
    SelectionMode="Multiple">
</asp:ListBox>

The Items collection contains the collection of ListItem objects in the ListBox control. To determine which items the user has selected, you can enumerate the ListItem objects in the Items collection by examining the Selected value for each ListItem element. The following code shows an example of processing the selected items and displaying them inside a Label control.

Sample of Visual Basic Code

For Each i As ListItem In ListBox1.Items
    If i.Selected Then
        Label1.Text = Label1.Text & "You selected TerritoryID: " & i.Value & "<br />"
    End If
Next

Sample of C# Code

foreach (ListItem i in ListBox1.Items)
{
    if(i.Selected)
        Label1.Text = Label1.Text + "You selected TerritoryID: " + i.Value + "<br />";
}

The CheckBoxList and RadioButtonList Controls

The CheckBoxList and RadioButtonList controls are very similar. Both are used to display lists of items to users to allow them to make selections but use a check box or button to make the selection. The RadioButtonList control is used to make a single selection. The CheckBoxList control allows users to make multiple selections.

These controls contain a RepeatColumns property that is used to indicate the number of columns to be displayed horizontally. In addition, the RepeatDirection can be set to Horizontal or Vertical (the default) to indicate whether the data should be rendered across by rows or down by columns.

The following shows a CheckBoxList control configured to work with the Territory data and show data across five columns.

<asp:CheckBoxList runat="server"
    ID="CheckBoxList1"
    DataSourceID="SqlDataSource1"
    DataTextField="TerritoryDescription"
    DataValueField="TerritoryID" RepeatColumns="5">
</asp:CheckBoxList>

The Items collection contains the ListItem objects that are inside the CheckBoxList and the RadioButtonList controls. Use the SelectedValue property to determine the item that has been selected for the RadioButtonList. To find the selected CheckBoxList item or items, you can enumerate the ListItem objects in the Items collection by examining the value of the Selected property for each ListItem element.

The BulletedList Control

The BulletedList control displays an unordered or ordered list of items that renders as HTML <ul> or <ol> elements, respectively. The BulletedList control inherits from the ListControl control. This control renders as either bulleted or numbered, depending on the BulletStyle property.

If the control is set to render as bulleted, you can select the bullet style to Disc, Circle, or Square. Note that the BulletStyle settings are not compatible with all browsers. A custom image can also be displayed instead of the bullet.

If the BulletedList control is set to render numbered, you can set the BulletStyle to LowerAlpha, UpperAlpha, LowerRoman, and UpperRoman fields. You can also set the FirstBulletNumber property to specify the starting number for the sequence.

The DisplayMode property can be set to Text, LinkButton, or HyperLink. If set to LinkButton or HyperLink, the control performs a postback when a user clicks an item to raise the Click event.

The following example shows a data-bound BulletedList control. The control is bound to a data source control that selects the Shippers table data from the Northwind database.

<asp:BulletedList runat="server"
    ID="BulletedList1"
    DataSourceID="SqlDataSource1"
    DataTextField="CompanyName"
    DataValueField="ShipperID" BulletStyle="Circle">
</asp:BulletedList>

Composite Data-Bound Controls

There are several data-bound controls that use other ASP.NET controls to display bound data to the user. For this reason, these controls are referred to as composite data-bound controls. These controls inherit from the CompositeDataBoundControl base class. This class implements the INamingContainer interface, which means that an inheritor of this class is a naming container for child controls.

The classes that inherit from CompositeDataBoundControl directly are FormView, DetailsView, and GridView, as shown in Figure 12-10. These controls are covered in this section, along with the related ListView, DataPager, Repeater, Chart, and DataList data-bound controls.

Figure 12-10

Figure 12-10 The CompositeDataBoundControl classes (and related controls).

The GridView Control

The GridView control is used to display data in a tabular format (rows and columns). The control renders in the browser as an HTML table. The GridView control makes it easy to configure features such as paging, sorting, and editing data without having to write much code.

The basic structure of the GridView is shown in Figure 12-11. The GridView control consists of a collection of GridViewRow (row) objects and a collection of DataControlField (column) objects. The GridViewRow object inherits from the TableRow object, which contains the Cells property. This property is a collection of DataControlFieldCell objects.

Figure 12-11

Figure 12-11 The basic GridView control structure.

Although the GridViewRow object holds the collection of cells, each DataControlField (column) object provides the behavior to initialize cells of a specific type in the DataControlField object’s InitializeCell method. The column classes that inherit from DataControlField override the InitializeCell method. The GridView control has an InitializeRow method that is responsible for creating a new GridViewRow and the row’s cells by making calls to the overridden InitializeCell method when the row is being created.

The DataControlField class hierarchy is shown in Figure 12-12. The derived classes are used to create a DataControlFieldCell with the proper contents. Remember that you don’t define cell types for your GridView control; you define column types and your column object supplies a cell object to the row by using the InitializeCell method. The DataControlField class hierarchy shows the different column types that are available in a GridView control.

Figure 12-12

Figure 12-12 The DataControlField class hierarchy.

Using Styles to Format the GridView Control

You use styles to format the GridView. There are several styles available for you to manage, including an overall GridViewStyle and a HeaderStyle, FooterStyle, RowStyle, AlternatingRowStyle, SelectedRowStyle, EditRowStyle, and more. You can set these styles declaratively at design time. In addition, the RowCreated and RowDataBound events can also be used to control the style programmatically. In these event handlers, the Cells collection on the newly created row can be used to apply a style to a single cell in the row. The difference between the two events is that the RowCreated event takes place first, before the data is available. You can use the RowDataBound event when you need to apply a different style to a cell based on the data in the cell. These events fire after the styles are applied, which means that you can override any existing styles. Applying a different style to a cell based on the data in the cell allows you to apply business rules to determine whether a cell should stand out from other cells (such as making negative “quantity on hand” numbers red, but only when an item is shipped more than once per month).

As an example, consider a page that contains a SqlDataSource control bound to the Products table in the Northwind database. Suppose that this data source control provides SQL statements for selecting, updating, inserting, and deleting data. You can use this data source control to configure a GridView control that allows for this editing. The following markup shows an example of how the GridView would look in Source view.

<asp:GridView ID="GridView1" runat="server"
    AllowPaging="True"
    AllowSorting="True"
    AutoGenerateColumns="False"
    DataKeyNames="ProductID"
    DataSourceID="SqlDataSource1">
    <Columns>
        <asp:CommandField ShowDeleteButton="True" ShowEditButton="True"
            ShowSelectButton="True" />
        <asp:BoundField DataField="ProductID" HeaderText="ProductID"
            InsertVisible="False" ReadOnly="True" SortExpression="ProductID" />
        <asp:BoundField DataField="ProductName" HeaderText="ProductName"
            SortExpression="ProductName" />
        <asp:BoundField DataField="SupplierID" HeaderText="SupplierID"
            SortExpression="SupplierID" />
        <asp:BoundField DataField="CategoryID" HeaderText="CategoryID"
            SortExpression="CategoryID" />
        <asp:BoundField DataField="QuantityPerUnit" HeaderText="QuantityPerUnit"
            SortExpression="QuantityPerUnit" />
        <asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice"
            SortExpression="UnitPrice" />
        <asp:BoundField DataField="UnitsInStock" HeaderText="UnitsInStock"
            SortExpression="UnitsInStock" />
        <asp:BoundField DataField="UnitsOnOrder" HeaderText="UnitsOnOrder"
            SortExpression="UnitsOnOrder" />
        <asp:BoundField DataField="ReorderLevel" HeaderText="ReorderLevel"
            SortExpression="ReorderLevel" />
        <asp:CheckBoxField DataField="Discontinued" HeaderText="Discontinued"
            SortExpression="Discontinued" />
    </Columns>
</asp:GridView>

Notice the Columns collection in the markup. Each column is defined along with the DataField and the text to be displayed as the column header (HeaderText). When this webpage is executed and displayed, each row is shown to the user along with action buttons for editing, deleting, and selecting the row. A user can click the Edit link on one of the rows to place the row into edit mode. Figure 12-13 shows an example.

Figure 12-13

Figure 12-13 The GridView control showing a row in edit mode.

The DetailsView Control

The DetailsView control is used to display the values of one record at a time from a data source in an HTML table. The DetailsView control allows you to edit, delete, and insert records. If the AllowPaging property is set to true, the DetailsView can be used by itself to navigate the data source. However, the DetailsView can also be used in combination with other controls such as the GridView, ListBox, or DropDownList, for scenarios in which you want to display a master-detail form.

The DetailsView control does not directly support sorting, whereas the GridView control does. However, you can use the DataSource control, as discussed in Lesson 1, to manage data sorting. You should also note that the GridView does not automatically support inserting new records, whereas the DetailsView does support this feature.

The DetailsView supports the same formatting options that are available with the GridView control. You can format the DetailsView control by using the HeaderStyle, RowStyle, AlternatingRowStyle, CommandRowStyle, FooterStyle, PagerStyle, and EmptyDataRowStyle properties.

As an example, again consider a page that has a SqlDataSource control used for defining selection, insertion, updates, and deletion of product data in the Northwind database. You can configure a DetailsView to show this product data as pages and allow users to edit this data, insert new records, and delete existing ones. The following markup shows an example.

<asp:DetailsView runat="server" Width="300px"
    ID="DetailsView1"
    AllowPaging="True"
    AutoGenerateRows="False"
    DataKeyNames="ProductID"
    DataSourceID="SqlDataSource1">
    <Fields>
        <asp:BoundField DataField="ProductID" HeaderText="ProductID"
            InsertVisible="False" ReadOnly="True" SortExpression="ProductID" />
        <asp:BoundField DataField="ProductName" HeaderText="ProductName"
            SortExpression="ProductName" />
        <asp:BoundField DataField="SupplierID" HeaderText="SupplierID"
            SortExpression="SupplierID" />
        <asp:BoundField DataField="CategoryID" HeaderText="CategoryID"
            SortExpression="CategoryID" />
        <asp:BoundField DataField="QuantityPerUnit" HeaderText="QuantityPerUnit"
            SortExpression="QuantityPerUnit" />
        <asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice"
            SortExpression="UnitPrice" />
        <asp:BoundField DataField="UnitsInStock" HeaderText="UnitsInStock"
            SortExpression="UnitsInStock" />
        <asp:BoundField DataField="UnitsOnOrder" HeaderText="UnitsOnOrder"
            SortExpression="UnitsOnOrder" />
        <asp:BoundField DataField="ReorderLevel" HeaderText="ReorderLevel"
            SortExpression="ReorderLevel" />
        <asp:CheckBoxField DataField="Discontinued" HeaderText="Discontinued"
            SortExpression="Discontinued" />
        <asp:CommandField ShowDeleteButton="True" ShowEditButton="True"
            ShowInsertButton="True" />
    </Fields>
</asp:DetailsView>

Notice that each column in the data table is set inside the Fields collection. The DataField attribute maps to the name of the column in the data source. The HeaderText property is used as the label that describes the data field. When the page is executed and displayed, the DetailsView shows Edit, Delete, and New buttons. When users click the Edit button, they are taken to edit mode for the selected record, as shown in Figure 12-14.

Figure 12-14

Figure 12-14 The DetailsView control in edit mode after the user has clicked the Edit button.

The FormView Control

Like DetailsView, the FormView control is used to display a single record from a data source. However, the FormView control does not automatically display the data in a predefined HTML table. Instead, it allows developers to create templates that define how the data should be displayed. You can define different templates for viewing, editing, and updating records. Creating your own templates gives you the greatest flexibility in controlling how data is displayed.

The FormView contains the following template definitions: ItemTemplate, EditItemTemplate, InsertItemTemplate, EmptyDataTemplate, FooterTemplate, HeaderTemplate, and PagerTemplate. You define a template by placing markup inside it and adding binding code within this markup. You then set the appropriate mode of the FormView control to switch to the specified template.

As an example, consider a page that defines a data source control for selecting the shipper data from the Northwind database. You can configure a FormView control to work with this data. For display, you can define the ItemTemplate. Here you set the controls and HTML used to lay out this data. You use the binding syntax (Eval and Bind) to connect data from the SqlDataSource to the FormView. The markup on the next page shows an example.

<asp:FormView runat="server"
    ID="FormView1"
    AllowPaging="True"
    DataSourceID="SqlDataSource1">
    <ItemTemplate>
        Shipper Identification:
        <asp:Label runat="server" Font-Bold="True"
            ID="Label1"
            Text='<%# Eval("ShipperID") %>'>
        </asp:Label>
        <br />
        <br />
        Company Name<br />
        <asp:TextBox runat="server" Width="250px"
            ID="TextBox1"
            Text='<%# Bind("CompanyName") %>'>
        </asp:TextBox>
        <br />
        Phone Number<br />
        <asp:TextBox runat="server" Width="250px"
            ID="TextBox2"
            Text='<%# Bind("Phone") %>'>
        </asp:TextBox>
    </ItemTemplate>
</asp:FormView>

When you run the page, the custom template is used with the FormView to display data as defined. Figure 12-15 shows the results in a browser window.

Figure 12-15

Figure 12-15 The FormView control showing the ItemTemplate in a browser.

The Repeater Control

The Repeater control also uses templates to define custom binding. However, it does not show data as individual records. Instead, it repeats the data rows as you specify in your template. This allows you to create a single row of data and have it repeat across your page.

The Repeater control is a read-only template. That is, it supports only the ItemTemplate. It does not implicitly support editing, insertion, and deletion. You should consider one of the other controls if you need this functionality, otherwise you will have to code this yourself for the Repeater control.

The following markup is similar to that for the FormView control example. It displays shipper data from the Northwind database as bound to a Label and two TextBox controls.

<asp:Repeater runat="server"
    ID="Repeater1"
    DataSourceID="SqlDataSource1">
    <ItemTemplate>
        <br /><br />
        Shipper Identification:
        <asp:Label runat="server" Font-Bold="True"
            ID="Label1"
            Text='<%# Eval("ShipperID") %>'>
        </asp:Label>
        <br />
        <br />
        Company Name<br />
        <asp:TextBox runat="server" Width="250px"
            ID="TextBox1"
            Text='<%# Bind("CompanyName") %>'>
        </asp:TextBox>
        <br />
        Phone Number<br />
        <asp:TextBox runat="server" Width="250px"
            ID="TextBox2"
            Text='<%# Bind("Phone") %>'>
        </asp:TextBox>
    </ItemTemplate>
</asp:Repeater>

When this data is displayed, however, it is repeated down the page. Figure 12-16 shows the results in a browser window.

Figure 12-16

Figure 12-16 The Repeater control showing the ItemTemplate in a browser.

The ListView Control

The ListView control also uses templates for the display of data. However, it supports many additional templates that allow for more scenarios when working with your data. These templates include the LayoutTemplate, which allows you to indicate an overall layout inside of which rows of your data will be displayed. The rows themselves are defined with the ItemTemplate. At run time, rows are placed within the LayoutTemplate placeholder identified by a control that has its ID attribute set to itemPlaceholder.

Another template is the GroupTemplate, which allows you to define groups of data. You can then set the GroupItemCount value to indicate the number of items in a group, and you can set the control to lay out groups of data and allow users to page through them.

The ItemSeparatorTemplate allows you to define content that should be placed between rows of items. This allows you to put graphic separators or other data between rows.

The ListView control (unlike DataList and Repeater) also implicitly supports the ability to edit, insert, and delete data by using a data source control. You can define individual templates for each of these scenarios. You can then change the mode of the ListView control through a server-side call and thus invoke the template for the user.

As an example, consider a page that includes a data source control that exposes the Product table from the Northwind database. You can create a ListView control to work with this data. The following markup shows such an example. In this example, a LayoutTemplate defines a <div> tag that includes the itemPlaceholder setting. The ItemTemplate is then defined by a <div> tag. At run time, each row will be added as a <div> tag in the placeholder.

<asp:ListView runat="server"
    ID="ListView1"
    DataKeyNames="ProductID"
    DataSourceID="SqlDataSource1">
    <LayoutTemplate>
        <div id="itemPlaceholder" runat="server"></div>
        <br />
        <div style="text-align: center">
            <asp:DataPager ID="DataPager1" runat="server" PageSize="4">
                <Fields>
                    <asp:NextPreviousPagerField
                        ButtonType="Button"
                        ShowFirstPageButton="True"
                        ShowLastPageButton="True" />
                </Fields>
            </asp:DataPager>
        </div>
    </LayoutTemplate>
    <ItemTemplate>
        <div style="text-align: center">
            <b>ProductName:</b>
            <asp:Label ID="ProductNameLabel" runat="server"
                Text='<%# Eval("ProductName") %>' />
            <br />
            <b>QuantityPerUnit:</b>
            <asp:Label ID="QuantityPerUnitLabel" runat="server"
                Text='<%# Eval("QuantityPerUnit") %>' />
            <br />
            <b>UnitPrice:</b>
            <asp:Label ID="UnitPriceLabel" runat="server"
                Text='<%# Eval("UnitPrice") %>' />
            <br />
        </div>
    </ItemTemplate>
    <ItemSeparatorTemplate>
        <hr />
    </ItemSeparatorTemplate>
</asp:ListView>

Notice also that the ListView control uses the ASP.NET DataPager control. This control allows you to provide custom data pagers for your data lists. Here the control is embedded at the end of the LayoutTemplate. The ListView control automatically uses the DataPager to move the user through data.

Finally, notice the use of the ItemSeparatorTemplate. This is used to put a horizontal rule between data rows. Figure 12-17 shows the results in a browser window.

Figure 12-17

Figure 12-17 The ListView control rendered in the browser.

The Chart Control

The Chart control allows you to display data by using chart visualization. You bind a data source to this control much like you do for the other data-bound controls. The big difference is that you then indicate fields from the data source that should be bound to an axis or data series in a chart.

There are more than 25 different chart types for displaying data. When the chart control runs on the server, it generate a graphic file (which is a PNG file by default, but you can change this setting) and then sends this to the browser as part of the response.

There are hundreds of properties you can set to define your chart and how it displays data. The chart definition typically includes the Series and ChartAreas elements. A Series represents a group of data to be shown on a chart. A Series element has a ChartType that defines the visualization of the data (choices are Bar, Area, Bubble, Line, Column, Pie, Radar, Range, and many more). A ChartArea element is used to indicate specifics about areas on your chart, such as an x and y axis. Here you can set intervals, formatting, and related visual items.

As an example, suppose you have the following SqlDataSource control that exposes sales by region.

<asp:SqlDataSource ID="SqlDataSource1" runat="server"
    ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>"
    SelectCommand="SELECT SUM([Order Details].UnitPrice * [Order Details].Quantity) AS
Total, Orders.ShipCountry FROM Orders INNER JOIN [Order Details] ON Orders.OrderID =
[Order Details].OrderID GROUP BY Orders.ShipCountry Order By Total"></asp:SqlDataSource>

You could then bind this to a Chart control to display each country and the total sales for that country. The following markup shows an example.

<asp:Chart ID="Chart1" runat="server"
    DataSourceID="SqlDataSource1"
    Width="702px" Height="581px">
    <Series>
        <asp:Series Name="Series1"
            XValueMember="ShipCountry"
            YValueMembers="Total"
            ChartType="Bar"
            XValueType="String"
            IsValueShownAsLabel="True"
            LabelBackColor="White"
            LabelFormat="{c}">
            <SmartLabelStyle CalloutBackColor="White" />
        </asp:Series>
    </Series>
    <ChartAreas>
        <asp:ChartArea Name="ChartArea1">
            <AxisY>
                <LabelStyle Format="{c}" />
            </AxisY>
            <AxisX Interval="1">
            </AxisX>
        </asp:ChartArea>
    </ChartAreas>
</asp:Chart>

Running this page will produce results similar to those shown in Figure 12-18.

Figure 12-18

Figure 12-18 The Chart control rendered in the browser.

The DataList Control

The DataList control works like the Repeater control. It repeats data for each row in your data set, and it displays this data according to your defined template. However, it lays out the data defined in the template within various HTML structures. This includes options for horizontal or vertical layout, and it also allows you to set how the data should be repeated, as flow or table layout.

The DataList control does not automatically use a data source control to edit data. Instead, it provides command events in which you can write your own code for these scenarios. To enable these events, you add a Button control to one of the templates and set the button’s CommandName property to the edit, delete, update, or cancel keyword. The appropriate event is then raised by the DataList control.

The following markup shows an example of a DataList control configured to show product data from the Northwind database. This control’s RepeatDirection is set to show data vertically by using a RepeatLayout of flow. The product data is bound to the DataList control inside the ItemTemplate code.

<asp:DataList runat="server"
    DataSourceID="SqlDataSource1"
    RepeatDirection="Vertical"
    ID="DataList1"
    RepeatLayout="flow">
    <ItemTemplate>
        <asp:Label ID="Label1" runat="server"
            Text='<%# Eval("ProductName") %>'
            Font-Bold="True">
        </asp:Label>
        <asp:Label ID="Label2" runat="server"
            Text='<%# Eval("UnitPrice", "{0:C}") %>'>
        </asp:Label>
        <br />
    </ItemTemplate>
</asp:DataList>

Hierarchical Data-Bound Controls

The HierarchicalDataBoundControl control serves as a base class for controls that render data in a hierarchical fashion. The classes that inherit from HierarchicalDataBoundControl are TreeView and Menu, as shown in Figure 12-19.

Figure 12-19

Figure 12-19 The HierarchicalDataBoundControl class hierarchy.

The TreeView Control

The TreeView control is a data-bound control that is used to display hierarchical data, such as a listing of files and folders, or a table of contents in a tree structure. Each entry in the tree is called a node. The nodes of this control can be bound to XML, tabular, or relational data. This control can also provide site navigation when used with the SiteMapDataSource control.

You can programmatically access and control the properties of the TreeView control. The TreeView can also be populated via client-side script by using modern browsers. In addition, nodes can be displayed as either plaintext or hyperlinks, and you can opt to display a check box next to each node.

Each node is represented by a TreeNode object. A node that contains other nodes is called a parent node. A node that is contained by another node is called a child node. A node can be both a parent node and a child node. A node that has no children is called a leaf node. A node that is not contained by any other node but is the ancestor to all the other nodes is the root node.

The typical TreeView tree structure has only one root node, but you can add multiple root nodes to the tree structure. This means that you can display a tree hierarchy without being forced to have a single root node.

The TreeNode has a Text property that is populated with the data that is to be displayed. The TreeNode also has a Value property that is used to store the data that is posted back to the web server.

You can configure a node to be a selection node or a navigation node by setting the NavigateUrl property. If the NavigateUrl property is set to an empty string (string.Empty), it is a selection node, and clicking the node simply selects it. If the NavigateUrl property is not set to an empty string, the node is a navigation node, and clicking it navigates to the location specified by the NavigateUrl property.

Populating the TreeView Control

The TreeView control can be populated by using static data or by using data binding. To populate the TreeView control with static data, you can use declarative syntax by placing opening and closing <Nodes> tags in the TreeView element and then creating a structure of nested <TreeNode> elements within the <Nodes> element. Each <TreeNode> has properties that you can set by adding attributes to the <TreeNode> element.

To use data binding to populate the TreeView control, you can use any data source that implements the IHierarchicalDataSource interface, such as an XmlDataSource control or a SiteMapDataSource control. Simply set the DataSourceID property of the TreeView control to the ID value of the data source control, and the TreeView control automatically binds to the specified data source control.

You can also bind to an XmlDocument object or a DataSet object that contains DataRelation objects by setting the DataSource property of the TreeView control to the data source and then calling the DataBind method.

The TreeView control contains a DataBindings property that is a collection of TreeNodeBinding objects that define the binding between a data item and the TreeNode. You can specify the binding criteria and the data item property to display in the node. This is useful when binding to XML elements when you are interested in binding to an attribute of the element.

Assume that you want to use a TreeView control to display customer data from a file called Customers.xml, which contains a list of customers, their orders and invoices, and the items for each order. This data is stored in a hierarchical format in the XML file. The Customers.xml file looks like the following.

<?xml version="1.0" encoding="utf-8" ?>
<Customers>
    <Customer CustomerId="1" Name="Northwind Traders">
        <Orders>
            <Order OrderId="1" ShipDate="06-22-2006">
                <OrderItems>
                    <OrderItem OrderItemId="1" PartNumber="123"
                         PartDescription="Large Widget" Quantity="5"
                         Price="22.00" />
                    <OrderItem OrderItemId="2" PartNumber="234"
                         PartDescription="Medium Widget" Quantity="2"
                         Price="12.50" />
                </OrderItems>
            </Order>
            <Order OrderId="2" ShipDate="06-25-2006">
                <OrderItems>
                    <OrderItem OrderItemId="5" PartNumber="432"
                         PartDescription="Small Widget" Quantity="30"
                         Price="8.99" />
                    <OrderItem OrderItemId="4" PartNumber="234"
                         PartDescription="Medium Widget" Quantity="2"
                         Price="12.50" />
                </OrderItems>
            </Order>
        </Orders>
        <Invoices>
            <Invoice InvoiceId="6" Amount="99.37" />
            <Invoice InvoiceId="7" Amount="147.50" />
        </Invoices>
    </Customer>
    <Customer CustomerId="2" Name="Tailspin Toys">
        <Orders>
            <Order OrderId="8" ShipDate="07-11-2006">
                <OrderItems>
                    <OrderItem OrderItemId="9" PartNumber="987"
                         PartDescription="Combo Widget" Quantity="2"
                         Price="87.25" />
                    <OrderItem OrderItemId="10" PartNumber="654"
                         PartDescription="Ugly Widget" Quantity="1"
                         Price="2.00" />
                </OrderItems>
            </Order>
            <Order OrderId="11" ShipDate="08-21-2006">
                <OrderItems>
                    <OrderItem OrderItemId="12" PartNumber="999"
                         PartDescription="Pretty Widget" Quantity="50"
                         Price="78.99" />
                    <OrderItem OrderItemId="14" PartNumber="575"
                         PartDescription="Tiny Widget" Quantity="100"
                         Price="1.20" />
                </OrderItems>
            </Order>
        </Orders>
        <Invoices>
            <Invoice InvoiceId="26" Amount="46.58" />
            <Invoice InvoiceId="27" Amount="279.15" />
        </Invoices>
    </Customer>
</Customers>

An XmlDataSource and a TreeView control are added to the webpage and configured. The following shows the markup for the TreeView control.

<asp:TreeView ID="TreeView1" runat="server"
     DataSourceID="XmlDataSource1"
     ShowLines="True" ExpandDepth="0">
     <DataBindings>
         <asp:TreeNodeBinding DataMember="Customer"
            TextField="Name" ValueField="CustomerId" />
         <asp:TreeNodeBinding DataMember="Order"
            TextField="ShipDate" ValueField="OrderId" />
         <asp:TreeNodeBinding DataMember="OrderItem"
            TextField="PartDescription" ValueField="OrderItemId" />
         <asp:TreeNodeBinding DataMember="Invoice"
            TextField="Amount" ValueField="InvoiceId"
            FormatString="{0:C}" />
     </DataBindings>
</asp:TreeView>

In this example, the configuration is kept to a minimum, but configuration is required to display information that is more important than the XML element name, such as the customer’s name instead of the XML element name (Customer). The following code is added to the code-behind page to simply display the value of the selected node.

Sample of Visual Basic Code

Partial Class TreeView_Control
    Inherits System.Web.UI.Page

    Protected Sub TreeView1_SelectedNodeChanged(ByVal sender As Object, _
        ByVal e As System.EventArgs) Handles TreeView1.SelectedNodeChanged
            Response.Write("Value:" + TreeView1.SelectedNode.Value)
    End Sub

End Class

Sample of C# Code

public partial class TreeView_Control : System.Web.UI.Page
{
    protected void TreeView1_SelectedNodeChanged(object sender, EventArgs e)
    {
        Response.Write("Value:" + TreeView1.SelectedNode.Value);
    }
}

When the webpage is displayed, the Customers node is visible. You can also click the plus (+) sign to expand the nodes, as shown in Figure 12-20.

Figure 12-20

Figure 12-20 The TreeView displays the nodes as configured.

The Menu Control

The Menu control is a data-bound control that is used to display hierarchical data in the form of a menu system. The Menu control is often used in combination with a SiteMapDataSource control for navigating a website.

The Menu control can be populated by using static data or by using data binding. To populate the Menu control with static data, you can use declarative syntax by placing opening and closing <Items> tags in the Menu element, and then you can create a structure of nested <MenuItem> elements within the <Items> element. Each <MenuItem> has properties that you can set by adding attributes to the <asp:MenuItem> element.

To use data binding to populate the Menu control, you can use any data source that implements the IHierarchicalDataSource interface, such as an XmlDataSource control or a SiteMapDataSource control. Simply set the DataSourceID property of the Menu control to the ID value of the data source control, and the Menu control automatically binds to the specified data source control.

You can also bind to an XmlDocument object or a DataSet object that contains DataRelation objects by setting the DataSource property of the Menu control to the data source, and then calling the DataBind method.

The Menu control contains a DataBindings property that is a collection of MenuItemBinding objects that define the binding between a data item and the menu item it is binding to in a Menu control. You can specify the binding criteria and the data item properties to display in the items. This is useful when binding to XML elements when you are interested in binding to an attribute of the element.

Assume that you want to use a Menu control to display menu data from a file called MenuItems.xml, which contains a list of the menu items to be displayed. The data is stored in a hierarchical format in the XML file. The MenuItems.xml file looks like the following.

<?xml version="1.0" encoding="utf-8" ?>
<MenuItems>
    <Home display="Home"  url="~/" />
    <Products display="Products" url="~/products/">
        <SmallWidgets display="Small Widgets"
            url="~/products/smallwidgets.aspx" />
        <MediumWidgets display="Medium Widgets"
            url="~/products/mediumwidgets.aspx" />
        <BigWidgets display="Big Widgets"
            url="~/products/bigwidgets.aspx" />
    </Products>
    <Support display="Support"  url="~/Support/">
        <Downloads display="Downloads"
            url="~/support/downloads.aspx" />
        <FAQs display="FAQs"
            url="~/support/faqs.aspx" />
    </Support>
    <AboutUs display="About Us" url="~/aboutus/">
        <Company display="Company"
            url="~/aboutus/company.aspx" />
        <Locations display="Location"
            url="~/aboutus/locations.aspx" />
    </AboutUs>
</MenuItems>

An XmlDataSource, a Menu, and a Label control are added to the webpage. The XmlDataSource is configured to use the XML file. The Menu control is configured to use the XmlDataSource. The following is the webpage markup.

<asp:Menu runat="server"
    ID="Menu1"
    DataSourceID="XmlDataSource1"
    OnMenuItemClick="Menu1_MenuItemClick">
</asp:Menu>

The following code is added to the code-behind page to simply display the ValuePath property of the selected MenuItem. When the webpage is displayed, the Menu appears and you can point to a menu item to see its child menu items.

Sample of Visual Basic Code

Partial Class Menu_Control
    Inherits System.Web.UI.Page

    Protected Sub Menu1_MenuItemClick(ByVal sender As Object, _
        ByVal e As System.Web.UI.WebControls.MenuEventArgs) _
        Handles Menu1.MenuItemClick
            Label1.Text = e.Item.ValuePath
    End Sub

End Class

Sample of C# Code

public partial class Menu_Control : System.Web.UI.Page
{
    protected void Menu1_MenuItemClick(object sender, MenuEventArgs e)
    {
        Label1.Text = e.Item.ValuePath;
    }
}
Practice Using the GridView and DetailsView Controls

In this practice, you use the GridView and DetailsView data-bound controls together to create a master-detail page.

EXERCISE Creating the Website, Adding Controls to the Page, and Configuring the Controls

In this exercise, you create a new website and add the database and data source control. You then add the data-bound controls and configure them accordingly.

  1. Open Visual Studio and create a new website called UsingDataBoundControls by using your preferred programming language.

  2. Add the northwnd.mdf file to your App_Data directory. You can copy the file from the samples installed from the CD.

  3. Open Default.aspx. Delete the default content on the page. Add a SqlDataSource control to the page from the Toolbox; name it SqlDataSourceReadList. This control will read data for display by the GridView control.

  4. In Design view of the Default.aspx page, click the smart tag in the upper-right corner of the SqlDataSource control to launch the Configure Data Source Wizard.

    1. On the first page, set the connection to the northwnd.mdf file in the App_Data directory and click Next.

    2. When prompted, save the connection string as ConnectionStringNorthwind, and then click Next again.

    3. On the Configure Select Statement page, select the Customers table from the Name list box. Select the CustomerID, CompanyName, ContactName, City, Country, and Phone fields. Click Next, and then click Finish to close the wizard.

    Your SqlDataSource markup should look similar to the following.

    <asp:SqlDataSource ID="SqlDataSource1" runat="server"
        ConnectionString="<%$ ConnectionStrings:ConnectionStringNorthwind %>"
        SelectCommand="SELECT [CustomerID], [CompanyName], [ContactName], [City],
      [Country], [Phone] FROM [Customers]">
    </asp:SqlDataSource>
  5. Drag a GridView control onto the Default.aspx page. Using either Design or Source view, configure the GridView control as follows:

    • Set the DataSourceId to SqlDataSourceReadList, created previously.

    • Set Enable Paging (AllowPaging property) to true.

    • Set Enable Sorting (AllowSorting property) to true.

    • Set AutoGenerateColumns to false.

    • Configure the CustomerID, CompanyName, ContactName, City, Country, and Phone fields to be displayed.

    • Add a CommandField to allow a user to select a row of data (you can do so in Design view by clicking Enable Selection).

    Your markup should look similar to the following.

    <asp:GridView ID="GridView1" runat="server"
        AllowPaging="True" AllowSorting="True"
        AutoGenerateColumns="False"
        DataKeyNames="CustomerID"
        DataSourceID="SqlDataSource1"
        width="700px">
        <Columns>
            <asp:CommandField ShowSelectButton="True" />
            <asp:BoundField DataField="CustomerID" HeaderText="ID"
                ReadOnly="True" SortExpression="CustomerID" />
            <asp:BoundField DataField="CompanyName" HeaderText="Company"
                SortExpression="CompanyName" />
            <asp:BoundField DataField="ContactName" HeaderText="Contact"
                SortExpression="ContactName" />
            <asp:BoundField DataField="City" HeaderText="City"
                SortExpression="City" />
            <asp:BoundField DataField="Country" HeaderText="Country"
                SortExpression="Country" />
            <asp:BoundField DataField="Phone" HeaderText="Phone"
                SortExpression="Phone" />
        </Columns>
    </asp:GridView>
  6. If you want, select the GridView in Design view and click the AutoFormat link on the task pane (from the smart tag). Select Professional or another formatting option.

  7. Run the website; you should be able to page through data, sort data, and select a row.

  8. Next, add another SqlDataSource control to the Default.aspx page; name it SqlDataSourceUpdate. Configure this control as before, by using the Configure Data Source Wizard.

    1. On the first page, select ConnectionStringNorthwind and click Next.

    2. The next step is to configure the SELECT statement to pick up the CustomerID parameter from the selected row on the GridView control. On the Configure The Select Statement page, select the Customers table. This time, select each field in the table. Then click the Where button to launch the Add WHERE Clause dialog box. Set the column to CustomerID. Set the Operator to = (the equal sign). Set the Source to Control. Under Parameter Properties, set the Control ID to GridView1. Click the Add button, and then click OK to close the dialog box.

    3. Click the Advanced button. In the Advanced Sql Generation Options dialog box, select the Generate INSERT, UPDATE, And DELETE Statements option. Click OK to close this dialog box. Click Next, and then click Finish to close the wizard.

    Your SqlDataSource control’s markup should look as follows.

    <asp:SqlDataSource ID="SqlDataSourceUpdate" runat="server"
        ConnectionString="<%$ ConnectionStrings:ConnectionStringNorthwind %>"
        DeleteCommand="DELETE FROM [Customers] WHERE [CustomerID] = @CustomerID"
        InsertCommand="INSERT INTO [Customers] ([CustomerID], [CompanyName],
      [ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode],
      [Country], [Phone], [Fax]) VALUES (@CustomerID, @CompanyName, @ContactName,
      @ContactTitle, @Address, @City, @Region, @PostalCode, @Country, @Phone, @Fax)"
        SelectCommand="SELECT [CustomerID], [CompanyName], [ContactName],
    [ContactTitle],
      [Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax] FROM
      [Customers] WHERE ([CustomerID] = @CustomerID)"
        UpdateCommand="UPDATE [Customers] SET [CompanyName] = @CompanyName,
      [ContactName] = @ContactName, [ContactTitle] = @ContactTitle, [Address] =
        @Address,
      [City] = @City, [Region] = @Region, [PostalCode] = @PostalCode, [Country] =
      @Country, [Phone] = @Phone, [Fax] = @Fax WHERE [CustomerID] = @CustomerID">
        <DeleteParameters>
            <asp:Parameter Name="CustomerID" Type="String" />
        </DeleteParameters>
        <InsertParameters>
            <asp:Parameter Name="CustomerID" Type="String" />
            <asp:Parameter Name="CompanyName" Type="String" />
            <asp:Parameter Name="ContactName" Type="String" />
            <asp:Parameter Name="ContactTitle" Type="String" />
            <asp:Parameter Name="Address" Type="String" />
            <asp:Parameter Name="City" Type="String" />
            <asp:Parameter Name="Region" Type="String" />
            <asp:Parameter Name="PostalCode" Type="String" />
            <asp:Parameter Name="Country" Type="String" />
            <asp:Parameter Name="Phone" Type="String" />
            <asp:Parameter Name="Fax" Type="String" />
        </InsertParameters>
        <SelectParameters>
            <asp:ControlParameter ControlID="GridView1" Name="CustomerID"
                PropertyName="SelectedValue" Type="String" />
        </SelectParameters>
        <UpdateParameters>
            <asp:Parameter Name="CompanyName" Type="String" />
            <asp:Parameter Name="ContactName" Type="String" />
            <asp:Parameter Name="ContactTitle" Type="String" />
            <asp:Parameter Name="Address" Type="String" />
            <asp:Parameter Name="City" Type="String" />
            <asp:Parameter Name="Region" Type="String" />
            <asp:Parameter Name="PostalCode" Type="String" />
            <asp:Parameter Name="Country" Type="String" />
            <asp:Parameter Name="Phone" Type="String" />
            <asp:Parameter Name="Fax" Type="String" />
            <asp:Parameter Name="CustomerID" Type="String" />
        </UpdateParameters>
    </asp:SqlDataSource>
  9. Add a DetailsView control to the page; place it under the GridView control.

  10. Switch to Design view and configure the DetailsView control by using the smart tag and related task list.

  11. Set the control’s data source to SqlDataSourceUpdate.

  12. Enable inserting and editing. (Deleting requires management of a foreign key constraint, so leave that cleared for this example.)

  13. Click Edit Templates from the task list of the DetailsView control.

  14. Select the EmptyData Template from the Display list in the task list.

  15. In the template, type No customer is currently selected.

  16. Add a LinkButton control to the template. Set the LinkButton control’s CausesValidation property to false (from the Properties pane). Set its CommandName property to New, and set its Text property to New.

  17. In the DetailsView Tasks window, click End Template Editing.

    Your DetailsView markup should look as follows.

    <asp:DetailsView ID="DetailsView1" runat="server" Height="50px" Width="125px"
        AutoGenerateRows="False" DataKeyNames="CustomerID"
        DataSourceID="SqlDataSourceUpdate">
        <EmptyDataTemplate>
            <b>No customer is currently selected<br />
            <asp:LinkButton ID="LinkButton1" runat="server"
                CausesValidation="False"
                CommandName="New">New</asp:LinkButton>
            </b>
        </EmptyDataTemplate>
        <Fields>
            <asp:BoundField DataField="CustomerID" HeaderText="ID"
                ReadOnly="True" SortExpression="CustomerID" />
            <asp:BoundField DataField="CompanyName" HeaderText="Company"
                SortExpression="CompanyName" />
            <asp:BoundField DataField="ContactName" HeaderText="Contact"
                SortExpression="ContactName" />
            <asp:BoundField DataField="ContactTitle" HeaderText="Contact Title"
                SortExpression="ContactTitle" />
            <asp:BoundField DataField="Address" HeaderText="Address"
                SortExpression="Address" />
            <asp:BoundField DataField="City" HeaderText="City"
                SortExpression="City" />
            <asp:BoundField DataField="Region" HeaderText="Region"
                SortExpression="Region" />
            <asp:BoundField DataField="PostalCode" HeaderText="Postal Code"
                SortExpression="PostalCode" />
            <asp:BoundField DataField="Country" HeaderText="Country"
                SortExpression="Country" />
            <asp:BoundField DataField="Phone" HeaderText="Phone"
                SortExpression="Phone" />
            <asp:BoundField DataField="Fax" HeaderText="Fax"
                SortExpression="Fax" />
            <asp:CommandField ShowEditButton="True"
                ShowInsertButton="True" />
        </Fields>
    </asp:DetailsView>
  18. If you want, select the DetailsView control in Design view and click the AutoFormat link in the task pane (from the smart tag). Select Professional or another formatting option.

  19. Next, add code to update the GridView when a record has been inserted or edited in the DetailsView control. To do so, add event handlers for both the ItemUpdated and ItemInserted events of the DetailsView control. Inside each event, rebind the GridView control. The following code shows an example.

    Sample of Visual Basic Code

    Protected Sub DetailsView1_ItemInserted(ByVal sender As Object, _
      ByVal e As System.Web.UI.WebControls.DetailsViewInsertedEventArgs) _
      Handles DetailsView1.ItemInserted
    
      GridView1.DataBind()
    
    End Sub
    
    Protected Sub DetailsView1_ItemUpdated(ByVal sender As Object, _
      ByVal e As System.Web.UI.WebControls.DetailsViewUpdatedEventArgs) _
      Handles DetailsView1.ItemUpdated
    
      GridView1.DataBind()
    
    End Sub

    Sample of C# Code

    protected void DetailsView1_ItemUpdated(object sender,
        DetailsViewUpdatedEventArgs e)
    {
        GridView1.DataBind();
    }
    
    protected void DetailsView1_ItemInserted(object sender,
        DetailsViewInsertedEventArgs e)
    {
        GridView1.DataBind();
    }
  20. Add a title to the top of the page for Manage Customers. Add another title for Customer Details.

  21. Run the webpage. Notice that the empty DetailsView control allows you to add a new record. Select a row from the GridView. Notice that it appears in the DetailsView section, as shown in Figure 12-21. Click the Edit link (which will appear when a row is selected in the GridView), and then edit a record.

Figure 12-21

Figure 12-21 The master-detail form shown in the browser window.

Lesson Summary

  • Simple data-bound controls consist of controls that inherit from the ListControl, such as DropDownList, ListBox, CheckBoxList, BulletedList, and RadioButtonList. For these controls, you set the DataTextField to the name of the column that contains the data you want to display to the user. You set the DataValueField to the column that contains the value or values you want to return to the server for a selected item.

  • Composite data-bound controls consist of the GridView, DetailsView, FormView, Repeater, ListView, and DataList controls. The GridView and DetailsView controls show data as tables. The other controls allow you to define templates for laying out your data.

  • Hierarchical data-bound controls consist of the Menu and TreeView controls. These controls are used for displaying data that contains parent-child relationships.

Lesson Review

You can use the following questions to test your knowledge of the information in Lesson 2, “Working with Data-Bound Web Server Controls”. The questions are also available on the companion CD in a practice test, if you prefer to review them in electronic form.

  1. You are creating a data-bound CheckBoxList control that allows a user to select options for configuring a vehicle. When the data is displayed to the user, you want the OptionName column to display. When the data is posted back to the server, you need the OptionId column value for all selected items. Which of the following attribute definitions would you set? (Choose all that apply.)

    1. DataTextField=OptionId

    2. DataTextField=OptionName

    3. DataValueField=OptionId

    4. DataValueField=OptionName

  2. You want to display a list of suppliers on a webpage. The supplier list must display 10 suppliers at a time, and you require the ability to edit individual suppliers. Which web control is the best choice for this scenario? (Choose all that apply.)

    1. The DetailsView control

    2. The Repeater control

    3. The GridView control

    4. The ListView control

  3. You want to display a list of parts in a master-detail scenario so that users can select a part number from a list that takes a minimum amount of space on the webpage. When the part is selected, a DetailsView control displays all the information about the part and allows users to edit the part. Which web control is the best choice to display the part number list for this scenario?

    1. The DropDownList control

    2. The RadioButtonList control

    3. The FormView control

    4. The TextBox control