Programming Microsoft ASP.NET 2.0 Core Reference

 

Data Source-Based Data Binding

Web applications are, for the most part, just data-driven applications. For this reason, the ability to bind HTML elements such as drop-down lists or tables to structured data is a key feature for any development platform. Data binding is the process that retrieves data from a fixed source and dynamically associates this data to properties on server controls. Valid target controls are those that have been specifically designed to support data binding that is, data-bound controls. Data-bound controls are not another family of controls; they're simply server controls that feature a few well-known data-related properties and feed them using a well-known set of collection objects.

Feasible Data Sources

Many .NET classes can be used as data sources and not just those that have to do with database content. In ASP.NET, any object that exposes the IEnumerable interface is a valid bindable data source. The IEnumerable interface defines the minimal API to enumerate the contents of the data source:

public interface IEnumerable { IEnumerator GetEnumerator(); }

Many bindable objects, though, actually implement more advanced versions of IEnumerable, such as ICollection and IList. In particular, you can bind a Web control to the following classes:

To be honest, I should note that the DataSet and DataTable classes don't actually implement IEnumerable or any other interfaces that inherit from it. However, both classes do store collections of data internally. These collections are accessed using the methods of an intermediate interface IListSource which performs the trick of making DataSet and DataTable classes look like they implement a collection.

ADO.NET Classes

As we saw in Chapter 8, ADO.NET provides a bunch of data container classes that can be filled with any sort of data, including results of a database query. These classes represent excellent resources for filling data-bound controls such as lists and grids. If having memory-based classes such as the DataSet in the list is no surprise, it's good to find data readers there, too. An open data reader can be passed to the data-binding engine of a control. The control will then walk its way through the reader and populate the user interface while keeping the connection to the database busy.

Note 

Data binding works differently for Web pages and Microsoft Windows desktop applications. Aside from the internal implementations, both Web and Windows Forms can share the same data source objects with the exception of the data reader. You can bind a data reader only to ASP.NET controls. Likewise, only Windows Forms controls can be bound to instances of the DataViewManager class that we briefly mentioned in Chapter 8.

The DataSet class can contain more than one table; however, only one table at a time can be associated with standard ASP.NET data-bound controls. If you bind the control to a DataSet, you need to set an additional property to select a particular table within the DataSet. Be aware that this limitation is not attributable to ASP.NET as a platform; it is a result of the implementation of the various data-bound controls. In fact, you could write a custom control that accepts a DataSet as its sole data-binding parameter.

DataSet and DataTable act as data sources through the IListSource interface; DataView and data readers, on the other hand, implement IEnumerable directly.

Collection-Based Classes

At the highest level of abstraction, a collection serves as a container for instances of other classes. All collection classes implement the ICollection interface, which in turn implements the IEnumerable interface. As a result, all collection classes provide a basic set of functionalities. All collection classes have a Count property to return the number of cached items; they have a CopyTo method to copy their items, in their entirety or in part, to an external array; they have a GetEnumerator method that instantiates an enumerator object to loop through the child items. GetEnumerator is the method behind the curtain whenever you call the foreach statement in C# and the For Each statement in Microsoft Visual Basic .NET.

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

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

You'll likely use custom collection classes in ASP.NET data-binding scenarios more often than you'll use predefined collection classes. The simplest way to code a custom collection in .NET 1.x is to derive a new class from CollectionBase and override at least the Add method and the Item property, as shown in the following code snippet:

public class OrderCollection : CollectionBase { public OrderCollection() { } // Add method public void Add(OrderInfo o) { InnerList.Add(o); } // Indexer ("Item") property public OrderInfo this[int index] { get { return (OrderInfo) InnerList[index]; } set { InnerList[index] = value; } } } public class OrderInfo { private int _id; public int ID { get { return _id; } set { _id = value; } } private DateTime _date; public DateTime Date { get { return _date; } set { _date = value; } } ... }

It is important that the element class OrderInfo, in the preceding code implements data members as properties, instead of fields, as shown below:

public class OrderInfo { public int ID; public DateTime Date; }

Data members coded as fields are certainly faster to write, but they are not discovered at run time unless the class provides a custom type descriptor (in other words, it implements the ICustomTypeDescriptor interface) that exposes fields as properties.

In ASP.NET 2.0, the advent of generics greatly simplifies the development of custom collections. In some cases, the code to write reduces to the following:

public class OrderCollection : List<OrderInfo> { }

Data-Binding Properties

In ASP.NET, there are two main categories of data-bound controls list controls and iterative controls. As we'll see in more detail later on, list controls repeat a fixed template for each item found in the data source. Iterative controls are more flexible and let you define the template to repeat explicitly, as well as other templates that directly influence the final layout of the control.

All data-bound controls implement the DataSource and DataSourceID properties, plus a few more, as detailed in Figure 9-1.

Figure 9-1: Class diagram for data binding in ASP.NET 2.0.

Note that the figure refers to the ASP.NET 2.0 object model. In ASP.NET 1.x, there's no DataSourceID property. Likewise, no intermediate classes exist such as BaseDataBoundControl and DataBoundControl. ListControl and BaseDataList form the common base for list and iterative controls.

Note 

Both in ASP.NET 1.x and ASP.NET 2.0 the Repeater control a low-level iterative control doesn't inherit from either of the classes in the diagram. It inherits directly from the Control class.

The DataSource Property

The DataSource property lets you specify the data source object the control is linked to. Note that this link is logical and does not result in any overhead or underlying operation until you explicitly order to bind the data to the control. As mentioned, you activate data binding on a control by calling the DataBind method. When the method executes, the control actually loads data from the associated data source, evaluates the data-bound properties (if any), and generates the markup to reflect changes:

public virtual object DataSource {get; set;}

The DataSource property is declared of type object and can ultimately accept objects that implement either IEnumerable (including data readers) or IListSource. By the way, only DataSet and DataTable implement the IListSource interface.

The DataSource property of a data-bound control is generally set programmatically. However, nothing prevents you from adopting a kind of declarative approach, as follows:

<asp:DropDownList runat="server" DataSource="<%# GetData() %>" ... />

GetData is a public or protected member of the host page class that returns a bindable object.

Note 

How can a data-bound control figure out which actual object it is bound to? Will it be a collection, a data reader, or perhaps a DataTable? All standard data-bound controls are designed to work only through the IEnumerable interface. For this reason, any object bound to DataSource is normalized to an object that implements IEnumerable. In some cases, the normalization is as easy (and fast) as casting the object to the IEnumerable interface. In other cases specifically, when DataTable and DataSet are involved an extra step is performed to locate a particular named collection of data that corresponds to the value assigned to the DataMember property. We'll return to this point and discuss some code in my other recent book, Programming Microsoft ASP.NET 2.0 Applications: Advanced Topics (Microsoft Press, 2005), while developing custom data-bound controls.

The DataSourceID Property

Introduced with ASP.NET 2.0, the DataSourceID property gets or sets the ID of the data source component from which the data-bound control retrieves its data. This property is the point of contact between ASP.NET 2.0 data-bound controls and the new family of data source controls that includes SqlDataSource and ObjectDataSource. (I'll cover these controls in more detail later in the chapter.)

public virtual string DataSourceID {get; set;}

By setting DataSourceID, you tell the control to turn to the associated data source control for any needs regarding data retrieval, paging, sorting, counting, or updating.

Like DataSource, DataSourceID is available on all data-bound controls. The two properties are mutually exclusive. If both are set, you get an invalid operation exception at run time. Note, though, that you also get an exception if DataSourceID is set to a string that doesn't correspond to an existing data source control.

The DataMember Property

The DataMember property gets or sets the name of the data collection to extract when data binding to a data source:

public virtual string DataMember {get; set;}

You use the property to specify the name of the DataTable to use when the DataSource property is bound to a DataSet object:

DataSet data = new DataSet(); SqlDataAdapter adapter = new SqlDataAdapter(cmdText, connString); adapter.Fill(data);] // Table is the default name of the first table in a // DataSet filled by an adapter grid.DataMember = "Table"; grid.DataSource = data; grid.DataBind();

DataMember and DataSource can be set in any order, provided that both are set before DataBind is invoked. DataMember has no relevance if you bind to data using DataSourceID with standard data source components.

Note 

This is not a limitation of the binding technology, but rather a limitation of standard data source components, which don't support multiple views. We'll return to this point later when discussing data source components.

The DataTextField Property

Typically used by list controls, the DataTextField property specifies which property of a databound item should be used to define the display text of the nth element in a list control:

public virtual string DataTextField {get; set;}

For example, for a drop-down list control the property feeds the displayed text of each item in the list. The following code creates the control shown in Figure 9-2:

CountryList.DataSource = data; CountryList.DataTextField = "country"; CountryList.DataBind();

Figure 9-2: A drop-down list control filled with the country column of a database table.

The same happens for ListBox, CheckBoxList, and other list controls. Unlike DataMember, the DataTextField property is necessary also in case the binding is operated by data source components.

Note 

List controls can automatically format the content of the field bound through the DataTextField property. The format expression is indicated via the DataTextFormatString property.

The DataValueField Property

Similar to DataTextField, the DataValueField property specifies which property of a data-bound item should be used to identify the nth element in a list control:

public virtual string DataValueField {get; set;}

To understand the role of this property, consider the markup generated for a drop-down list, set as in the code snippet shown previously:

<select name="CountryList" > <option selected="selected" value="[All]">[All]</option> <option value="Argentina">Argentina</option> <option value="Austria">Austria</option> ... </select>

The text of each <option> tag is determined by the field specified through DataTextField; the value of the value attribute is determined by DataValueField. Consider the following code filling a ListBox with customer names:

CustomerList.DataMember = "Table"; CustomerList.DataTextField = "companyname"; CustomerList.DataValueField = "customerid"; CustomerList.DataSource = data; CustomerList.DataBind();

If DataValueField is left blank, the value of the DataTextField property is used instead. Here's the corresponding markup:

<select size="4" name="CustomerList" > <option value="BOTTM">Bottom-Dollar Markets</option> <option value="LAUGB">Laughing Bacchus Wine Cellars</option> ... </select>

As you can see, the value attribute now is set to the customer ID the unique, invisible value determined by the customerid field. The content of the value attribute for the currently selected item is returned by the SelectedValue property of the list control. If you want to access programmatically the displayed text of the current selection, use the SelectedItem.Text expression.

The AppendDataBoundItems Property

Introduced in ASP.NET 2.0, AppendDataBoundItems is a Boolean property that indicates whether the data-bound items should be appended to or whether they should overwrite the existing contents of the control. By default, AppendDataBoundItems is set to false, meaning that data-bound contents replace any existing contents. This behavior is the same as you have in ASP.NET 1.x, where this property doesn't exist:

public virtual bool AppendDataBoundItems {get; set;}

AppendDataBoundItems is useful when you need to combine constant items with data-bound items. For example, imagine you need to fill a drop-down list with all the distinct countries in which you have a customer. The user will select a country and see the list of customers who live there. To let users see all the customers in any country, you add an unbound element, such as [All]:

<asp:DropDownList runat="server" AppendDataBoundItems="true"> <asp:ListItem Text="[All]" /> </asp:DropDownList>

With AppendDataBoundItems set to false (which is the default behavior in ASP.NET 1.x), the [All] item will be cleared before data-bound items are added. In ASP.NET 1.x, you need to add it programmatically after the binding operation completes.

The DataKeyField Property

The DataKeyField property gets or sets the key field in the specified data source. The property serves the needs of ASP.NET 1.x grid-like controls (DataList and DataGrid) and lets them (uniquely) identify a particular record. Note that the identification of the record is univocal only if the original data source has a unique-constrained field:

public virtual string DataKeyField {get; set;}

The DataKeyField property is coupled with the DataKeys array property. When DataKeyField is set, DataKeys contains the value of the specified key field for all the control's data items currently displayed in the page. We'll cover this in more detail in the next chapter when we talk about DataGrid controls.

The new grid control of ASP.NET (the GridView control) extends the DataKeyField to an array of strings and renames it DataKeyNames. The DataKeys property is maintained, though defined differently, as we'll see in the next chapter.

List Controls

List controls display (or at least need to have in memory) many items at the same time specifically, the contents of the data source. Depending on its expected behavior, the control will pick the needed items from memory and properly format and display them. List controls include DropDownList, CheckBoxList, RadioButtonList, ListBox, and, in ASP.NET 2.0, also the BulletedList control. All list controls inherit from the base ListControl class both in ASP.NET 1.x and 2.0.

The DropDownList Control

The DropDownList control enables users to select one item from a single-selection drop-down list. You can specify the size of the control by setting its height and width in pixels, but you can't control the number of items displayed when the list drops down. Table 9-1 lists the most commonly used properties of the control.

Table 9-1: Properties of the DropDownList Control

Property

Description

AppendDataBoundItems

Indicates whether statically defined items should be maintained or cleared when adding data-bound items. Not supported in ASP.NET 1.x.

AutoPostBack

Indicates whether the control should automatically post back to the server when the user changes the selection.

DataMember

The name of the table in the DataSource to bind.

DataSource

The data source that populates the items of the list.

DataSourceID

ID of the data source component to provide data. Not supported in ASP.NET 1.x.

DataTextField

Name of the data source field to supply the text of list items.

DataTextFormatString

Formatting string used to control list items are displayed.

DataValueField

Name of the data source field to supply the value of a list item.

Items

Gets the collection of items in the list control.

SelectedIndex

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

SelectedItem

Gets the selected item in the list.

SelectedValue

Gets the value of the selected item in the list.

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

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

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

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

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

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

The CheckBoxList Control

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

<asp:CheckBoxList runat="server" >

Table 9-2 lists the specific properties of the CheckBoxList control.

Table 9-2: Properties of the CheckBoxList Control

Property

Description

AppendDataBoundItems

Indicates whether statically defined items should be maintained or cleared when adding data-bound items. Not supported in ASP.NET 1.x.

AutoPostBack

Indicates whether the control should automatically post back to the server when the user changes the selection.

CellPadding

Indicates pixels between the border and contents of the cell.

CellSpacing

Indicates pixels between cells.

DataMember

The name of the table in the DataSource to bind.

DataSource

The data source that populates the items of the list.

DataSourceID

ID of the data source component to provide data. Not supported in ASP.NET 1.x.

DataTextField

Name of the data source field to supply the text of list items.

DataTextFormatString

Formatting string used to control list items are displayed.

DataValueField

Name of the data source field to supply value of a list item.

Items

Gets the collection of items in the list control.

RepeatColumns

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

RepeatDirection

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

RepeatLayout

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

SelectedIndex

Gets or sets the index of the first selected item in the list the one with the lowest index.

SelectedItem

Gets the first selected item.

SelectedValue

Gets the value of the first selected item.

TextAlign

Gets or sets the text alignment for the check boxes.

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

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

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

Figure 9-3 shows a sample page that lets you select some country names and composes an ad hoc query to list all the customers from those countries.

Figure 9-3: A horizontally laid out CheckBoxList control in action.

Note that the SelectedXXX properties work in a slightly different manner for a CheckBoxList control. The SelectedIndex property indicates the lowest index of a selected item. By setting SelectedIndex to a given value, you state that no items with a lower index should be selected any longer. As a result, the control automatically deselects all items with an index lower than the new value of SelectedIndex. Likewise, SelectedItem returns the first selected item, and SelectedValue returns the value of the first selected item.

The RadioButtonList Control

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

if (radioButtons.SelectedValue != null) { // Process the selection here ... }

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

The ListBox Control

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

<asp:listbox runat="server" rows="5" selectionmode="Multiple" />

You can decide the height of the control through the Rows property. The height is measured in number of rows rather than pixels or percentages. When it comes to data binding, the ListBox control behaves like the controls discussed earlier in the chapter.

Two properties make this control slightly different from other list controls the Rows property, which represents the number of visible rows in the control, and the SelectionMode property, which determines whether one or multiple items can be selected. The programming interface of the list box also contains the set of SelectedXXX properties we considered earlier. In this case, they work as they do for the CheckBoxList control that is, they returns the selected item with the lowest index.

Note 

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

The BulletedList Control

The BulletedList control is a programming interface built around the <ul> and <ol> HTML tags, with some extra features such as the bullet style, data binding, and support for custom images. The BulletedList control is not supported in ASP.NET 1.x. The following example uses a custom bullet object:

<asp:bulletedlist runat="server" bullet> <asp:listitem>One</asp:listitem> <asp:listitem>Two</asp:listitem> <asp:listitem>Three</asp:listitem> </asp:bulletedlist>

The bullet style lets you choose the style of the element that precedes the item. You can use numbers, squares, circles, and uppercase and lowercase letters. The child items can be rendered as plain text, hyperlinks, or buttons. Table 9-3 details the main properties of a BulletedList control.

Table 9-3: Properties of the BulletedList Control

Property

Description

AppendDataBoundItems

Indicates whether statically defined items should be maintained or cleared when adding data-bound items

BulletImageUrl

Gets or sets the path to the image to use as the bullet

BulletStyle

Determines the style of the bullet

DataMember

The name of the table in the DataSource to bind

DataSource

The data source that populates the items of the list

DataSourceID

ID of the data source component to provide data

DataTextField

Name of the data source field to supply text of list items

DataTextFormatString

Formatting string used to control list items are displayed

DataValueField

Name of the data source field to supply value of a list item

DisplayMode

Determines how to display the items: plain text, link buttons, or hyperlinks

FirstBulletNumber

Gets or sets the value that starts the numbering

Items

Gets the collection of items in the list control

Target

Indicates the target frame in case of hyperlink mode

The items of a BulletedList control supports a variety of graphical styles disc, circle, and custom image, plus a few numberings including roman numbering. The initial number can be programmatically set through the FirstBulletNumber property. The DisplayMode property determines how to display the content of each bullet plain text (the default), link button, or hyperlink. In the case of link buttons, the Click event is fired on the server to let you handle the event when the page posts back. In the case of hyperlinks, the browser will display the target page in the specified frame the Target property. The target URL coincides with the contents of the field specified by DataValueField.

Figure 9-4 shows a sample page that includes a RadioButtonList and a BulletedList control. The radio-button list is bound to the contents of a system enumerated type BulletStyle and displays as selectable radio buttons the various bullet styles. To bind the contents of an enumerated type to a data-bound control, you do as follows:

BulletOptions.DataSource = Enum.GetValues(typeof(BulletStyle)); BulletOptions.SelectedIndex = 0; BulletOptions.DataBind();

Figure 9-4: A sample page to preview the style of a BulletedList control.

To retrieve and set the selected value, use the following code:

BulletStyle style = (BulletStyle) Enum.Parse(typeof(BulletStyle), BulletOptions.SelectedValue); BulletedList1.BulletStyle = style;

Iterative Controls

Iterative controls are a special type of data-bound controls that supply a template-based mechanism to create free-form user interfaces. Iterative controls take a data source, loop through the items, and iteratively apply user-defined HTML templates to each row. This basic behavior is common to all three ASP.NET iterators Repeater, DataList, and DataGrid. Beyond that, iterative controls differ from each other in terms of layout capabilities and functionality.

Iterative controls differ from list controls because of their greater rendering flexibility. An iterative control lets you apply an ASP.NET template to each row in the bound data source. A list control, on the other hand, provides a fixed and built-in template for each data item. List controls are customizable to some extent, but you can't change anything other than the text displayed. No changes to layout are supported. On the other hand, using a list control is considerably easier than setting up an iterative control, as we'll see in a moment. Defining templates requires quite a bit of declarative code, and if accomplished programmatically, it requires that you write a class that implements the ITemplate interface. A list control only requires you to go through a few data-binding properties.

We'll take a look at DataGrid controls in Chapter 10 and reserve more space for lower-level iterators such as Repeater and DataList in my other recent book, Programming Microsoft ASP.NET 2.0 Applications: Advanced Topics. When they are properly customized and configured, there's no graphical structure be it flat or hierarchical that the Repeater and DataList controls can't generate. Let's briefly meet each control.

The Repeater Control

The Repeater control displays data using user-provided layouts. It works by repeating a specified ASP.NET template for each item displayed in the list. The Repeater is a rather basic templated data-bound control. It has no built-in layout or styling capabilities. All formatting and layout information must be explicitly declared and coded using HTML tags and ASP.NET classes.

The Repeater class acts as a naming container by implementing the marker interface INamingContainer. (See Chapter 3.) Table 9-4 lists the main properties exposed by the control, not including those inherited from the base class.

Table 9-4: Properties of the Repeater Control

Property

Description

AlternatingItemTemplate

Template to define how every other item is rendered.

DataMember

The name of the table in the DataSource to bind.

DataSource

The data source that populates the items of the list.

DataSourceID

ID of the data source component to provide data. Not supported in ASP.NET 1.x.

FooterTemplate

Template to define how the footer is rendered.

HeaderTemplate

Template to define how the header is rendered.

Items

Gets a RepeaterItemCollection object that is, a collection of RepeaterItem objects. Each element of the collection represents a displayed data row in the Repeater.

ItemTemplate

Template to define how items are rendered.

SeparatorTemplate

Template to define how the separator between items is to be rendered.

For the most part, properties are the template elements that form the control's user interface. The Repeater populates the Items collection by enumerating all the data items in the bound data source. For each data-bound item (for example, a table record), it creates a RepeaterItem object and adds it to the Items collection. The RepeaterItemCollection class is a plain collection class with no special or peculiar behavior. The RepeaterItem class represents a displayed element within the overall structure created by the Repeater. The RepeaterItem contains properties to point to the bound data item (such as a table record), the index, and the type of the item (regular item, alternating item, header, footer, and so on). Here's a quick example of a Repeater:

<asp:Repeater runat="server"> <HeaderTemplate> <h2>We have customers in the following cities</h2> <hr /> </HeaderTemplate> <SeparatorTemplate> <hr noshade /> </SeparatorTemplate> <ItemTemplate> <%# Eval("City")%> &nbsp;&nbsp;<b><%# Eval("Country")%></b> </ItemTemplate> <FooterTemplate> <hr /> <%# CalcTotal() %> cities </FooterTemplate> </asp:Repeater>

Bound to the output of the following query, the structure produces what is shown in Figure 9-5:

SELECT DISTINCT country, city FROM customers WHERE country=@TheCountry

Figure 9-5: A sample Repeater control in action. No predefined list control can generate such free-form output.

The @TheCountry parameter is the name of the country picked from the drop-down list:

data = new DataTable(); SqlDataAdapter adapter = new SqlDataAdapter(cmdText, connString); adapter.SelectCommand.Parameters.AddWithValue("@TheCountry", Countries.SelectedValue); adapter.Fill(data); Repeater1.DataSource = data; Repeater1.DataBind();

Of all templates, only ItemTemplate and AlternatingItemTemplate are data-bound, meaning that they are repeated for each item in the data source. You need a mechanism to access public properties on the data item (such as a table record) from within the template. The Eval method takes the name of the property (for example, the name of the table column) and returns the content. We'll learn more about Eval and <%# %> code blocks in a moment when discussing data-binding expressions.

The DataList Control

The DataList is a data-bound control that begins where the Repeater ends and terminates a little before the starting point of the DataGrid control. In some unrealistically simple cases, you could even take some code that uses a Repeater, replace the control, and not even notice any difference. The DataList overtakes the Repeater in several respects, mostly in the area of graphical layout. The DataList supports directional rendering, meaning that items can flow horizontally or vertically to match a specified number of columns. Furthermore, it provides facilities to retrieve a key value associated with the current data row and has built-in support for selection and in-place editing. (I discuss these features in Programming Microsoft ASP.NET 2.0 Applications: Advanced Topics.)

In addition, the DataList control supports more templates and can fire some extra events beyond those of the Repeater control. Data binding and the overall behavior are nearly identical for the Repeater and DataList controls.

The DataList works by making some assumptions about the expected results. This is both good and bad news for you as a programmer. It means that in some cases much less code is needed to accomplish the same effect; on the other hand, it also indicates that you should know the behavior of the control very well to govern it. For example, the DataList assumes that no HTML tag is split across templates. This fact isn't a problem per se, but it can result in badly formed or totally unexpected HTML output. In addition, by default the DataList renders its entire output as an HTML table, meaning that if this is exactly what you want, there's no need for you to comply with <table> or <td> elements.

In addition to being a naming container, the DataList class implements the IRepeatInfoUser interface. The IRepeatInfoUser interface defines the properties and methods that must be implemented by any list control that repeats a list of items. This interface is also supported by the CheckBoxList and RadioButtonList controls and is the brains behind the RepeatXXX properties we met earlier. Here's how to rewrite the previous example to get stricter control over the output:

<asp:DataList runat="server" RepeatColumns="5" GridLines="Both"> <FooterStyle Font-Bold="true" ForeColor="blue" /> <HeaderTemplate> <h2>We have customers in the following cities</h2> </HeaderTemplate> <ItemTemplate> <%# Eval("City") %> &nbsp;&nbsp;<b><%# Eval("Country")%></b> </ItemTemplate> <FooterTemplate> <%# CalcTotal() %> cities </FooterTemplate> </asp:DataList>

The output is shown in Figure 9-6. Note the FooterStyle tag; the DataList also lets you explicitly style the content of each supported template. In this case, we're going to get boldface and blue text in the footer panel.

Figure 9-6: A sample DataList control in action. Note the extended layout capabilities that let you divide by columns by simply setting a property.

The DataGrid Control

The DataGrid is an extremely versatile data-bound control that is a fixed presence in any real-world ASP.NET 1.x application. While fully supported, in ASP.NET 2.0, the DataGrid is pushed into the background by the introduction of a new and much more powerful grid control the GridView. We'll cover both in the next chapter.

The DataGrid control renders a multicolumn, fully templated grid and provides a highly customizable, Microsoft Office Excel-like user interface. In spite of the rather advanced programming interface and the extremely rich set of attributes, the DataGrid simply generates an HTML table with interspersed hyperlinks to provide interactive functionalities such as sorting, paging, selection, and in-place editing.

The DataGrid is a column-based control and supports various types of data-bound columns, including text columns, templated columns, and command columns. You associate the control with a data source using the DataSource property. Just as for other data-bound controls, no data will be physically loaded and bound until the DataBind method is called. The simplest way of displaying a table of data using the ASP.NET grid is as follows:

<asp:DataGrid runat="server" />

The control will then automatically generate an HTML table column for each property available in the bound data source. This is only the simplest scenario, however. If needed, you can specify which columns should be displayed and style them at will:

grid.DataSource = data; grid.DataBind();

Figure 9-7 demonstrates the grid's output for a sample that returns three fields. As mentioned, we'll cover the DataGrid control in much greater detail in the next chapter.

Figure 9-7: A sample DataGrid control in action.

 

Категории