The GridView excels at showing a dense table
with multiple rows of information. However, sometimes you want to
provide a detailed look at a single record. You could work out a
solution using a template column in a GridView, but ASP.NET includes two
controls that are tailored for this purpose: the DetailsView and the
FormView. Both show a single record at a time but can include optional
pager buttons that let you step through a series of records (showing one
per page). Both give you an easy way to insert a new record, which the
GridView doesn't allow. And both support templates, but the FormView requires them. This is the key distinction between the two controls.
One other difference is the fact that the DetailsView
renders its content inside a table, while the FormView gives you the
flexibility to display your content without a table. Thus, if you're
planning to use templates, the FormView gives you the most flexibility.
But if you want to avoid the complexity of templates, the DetailsView
gives you a simpler model that lets you build a multirow data display
out of field objects, in much the same way that the GridView is built
out of column objects.
Now that you understand the features of the GridView,
you can get up to speed with the DetailsView and the FormView quite
quickly. That's because both borrow a portion of the GridView model.
1. The DetailsView
The DetailsView displays a single record at a time. It places each field in a separate row of a table.
The DetailsView also allows you to move from one record to the
next using paging controls, if you've set the AllowPaging property to
True. You can configure the paging controls using the PagerStyle and
PagerSettings properties in the same way as you tweak the pager for the
GridView.
Figure 1 shows the DetailsView when it's bound to a set of product records, with full product information.
It's tempting to use the DetailsView pager controls
to make a handy record browser. Unfortunately, this approach can be
quite inefficient. One problem is that a separate postback is required
each time the user moves from one record to another (whereas a grid
control can show multiple records on the same page). But the real
drawback is that each time the page is posted back, the full set of
records is retrieved, even though only a single record is shown. This
results in needless extra work for the database server. If you choose to
implement a record browser page with the DetailsView, at a bare minimum
you must enable caching to reduce the database work.
It's almost always a better idea to use another
control to let the user choose a specific record (for example, by
choosing an ID from a list box), and then show the full record in the
DetailsView using a parameterized command that matches just the selected
record.
|
|
1.1. Defining Fields
The DetailsView uses reflection to generate the
fields it shows. This means it examines the data object and creates a
separate row for each field it finds, just like the GridView. You can
disable this automatic row generation by setting AutoGenerateRows to
False. It's then up to you to declare information you want to display.
Interestingly, you use the same field tags to build a
DetailsView as you use to design a GridView. For example, fields from
the data item are represented with the BoundField tag, buttons can be
created with the ButtonField, and so on.
The following code defines a DetailsView that shows product information. This tag creates the same grid of information shown in Figure 16-17, when AutoGenerateRows was set to True.
<asp:DetailsView ID="DetailsView1" runat="server" AutoGenerateRows="False"
DataSourceID="sourceProducts">
<Fields>
<asp:BoundField DataField="ProductID" HeaderText="ProductID"
ReadOnly="True" />
<asp:BoundField DataField="ProductName" HeaderText="ProductName" />
<asp:BoundField DataField="SupplierID" HeaderText="SupplierID" />
<asp:BoundField DataField="CategoryID" HeaderText="CategoryID" />
<asp:BoundField DataField="QuantityPerUnit" HeaderText="QuantityPerUnit" />
<asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice" />
<asp:BoundField DataField="UnitsInStock" HeaderText="UnitsInStock" />
<asp:BoundField DataField="UnitsOnOrder" HeaderText="UnitsOnOrder" />
<asp:BoundField DataField="ReorderLevel" HeaderText="ReorderLevel" />
<asp:CheckBoxField DataField="Discontinued" HeaderText="Discontinued" />
</Fields>
...
</asp:DetailsView>
You can use the BoundField tag to set properties such as header text, formatting string, editing behavior, and so on .
In addition, you can use the ShowHeader property. When it's False, the
header text is left out of the row, and the field data takes up both
cells.
Rather than coding each field by hand, you can use
the same shortcut you used with the GridView. Simply select the control
at design time, and select Refresh Schema from the smart tag.
|
|
The field model isn't the only part of the GridView
that the DetailsView control adopts. It also uses a similar set of
styles, a similar set of events, and a similar editing model. The only
difference is that instead of creating a dedicated column for editing
controls, you simply set one of the Boolean properties of the
DetailsView, such as AutoGenerateDeleteButton, AutoGenerateEditButton,
and AutoGenerateInsertButton. The links for these tasks are added to the
bottom of the DetailsView. When you add or edit a record, the
DetailsView uses standard text box controls (see Figure 2),
just like the GridView does. For more editing flexibility, you'll want
to use templates with the DetailsView (by adding a TemplateField instead
of a BoundField) or the FormView control (as described next).
2. The FormView
If you need the ultimate flexibility of templates,
the FormView provides a template-only control for displaying and editing
a single record.
The beauty of the FormView template model is that it
matches the model of the TemplateField in the GridView quite closely.
This means you can work with the following templates:
ItemTemplate
EditItemTemplate
InsertItemTemplate
FooterTemplate
HeaderTemplate
EmptyDataTemplate
PagerTemplate
NOTE
Unlike the GridView and DetailsView, which allow
you to add as many TemplateField objects as you want, the FormView
allows just a single copy of each template. If you want to show multiple
values, you must add multiple binding expressions to the same
ItemTemplate.
You can use the same template content you use with a
TemplateField in a GridView in the FormView. Here's how you can use the same template in the FormView:
<asp:FormView ID="FormView1" runat="server" DataSourceID="sourceProducts">
<ItemTemplate>
<b>In Stock:</b>
<%# Eval("UnitsInStock") %>
<br />
<b>On Order:</b>
<%# Eval("UnitsOnOrder") %>
<br />
<b>Reorder:</b>
<%# Eval("ReorderLevel") %>
<br />
</ItemTemplate>
</asp:FormView>
Like the DetailsView, the FormView can show a single
record at a time. (If the data source has more than one record, you'll
see only the first one.) You can deal with this issue by setting the
AllowPaging property to True so that paging links are automatically
created. These links allow the user to move from one record to the next,
as in the previous example with the DetailsView.
Another option is to bind to a data source that returns just one record. Figure 3
shows an example where a drop-down list control lets you choose a
product, and a second data source shows the matching record in the
FormView control.
Here's the markup you need to define the drop-down list and its data source:
<asp:SqlDataSource ID="sourceProducts" runat="server"
ConnectionString="<%$ ConnectionStrings:Northwind %>"
SelectCommand="SELECT ProductID, ProductName FROM Products">
</asp:SqlDataSource>
<asp:DropDownList ID="lstProducts" runat="server"
AutoPostBack="True" DataSourceID="sourceProducts"
DataTextField="ProductName" DataValueField="ProductID" Width="184px">
</asp:DropDownList>
The FormView uses the template from the previous
example (it's the shaded region on the page). Here's the markup for the
FormView (not including the template) and the data source that gets the
full details for the selected product.
<asp:SqlDataSource ID="sourceProductFull" runat="server"
ConnectionString="<%$ ConnectionStrings:Northwind %>"
SelectCommand="SELECT * FROM Products WHERE ProductID=@ProductID">
<SelectParameters>
<asp:ControlParameter Name="ProductID"
ControlID="lstProducts" PropertyName="SelectedValue" />
</SelectParameters>
</asp:SqlDataSource>
<asp:FormView ID="formProductDetails" runat="server"
DataSourceID="sourceProductFull"
BackColor="#FFE0C0" CellPadding="5">
<ItemTemplate>
...
</ItemTemplate>
</asp:FormView>