4. 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 requires only that you go through a few data-binding properties.
The Repeater Control
The Repeater
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. Table 4 lists the main properties exposed by the control, not counting those inherited from the base class.
Table 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 ID="Repeater1" runat="server">
<HeaderTemplate>
<h2>We have customers in the following cities</h2>
<hr />
</HeaderTemplate>
<SeparatorTemplate>
<hr noshade style="border:dashed 1px blue" />
</SeparatorTemplate>
<ItemTemplate>
<%# Eval("City")%> <b><%# Eval("Country")%></b>
</ItemTemplate>
<FooterTemplate>
<hr />
<%# CalcTotal() %> cities
</FooterTemplate>
</asp:Repeater>
Bound to the output of the following query, the structure produces what’s shown in Figure 5:
SELECT DISTINCT country, city FROM customers WHERE country=@TheCountry
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 the 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 can 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. 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. The DataList assumes that no HTML tag is split across templates and renders its entire output as an HTML table.
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 ID="DataList1" 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") %> <b><%# Eval("Country")%></b>
</ItemTemplate>
<FooterTemplate>
<%# CalcTotal() %> cities
</FooterTemplate>
</asp:DataList>
The output is shown in Figure 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.
The DataGrid Control
The DataGrid
is an extremely versatile data-bound control that is a fixed presence
in any real-world ASP.NET 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.
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" id="grid" />
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 7 demonstrates the grid’s output for a sample that returns three fields.