随 Visual Studio® 2008 一同发布的 ASP.NET 3.5 引入了新的数据绑定控件—ListView。我知道您正在想什么:为什么 ASP.NET 里还需要另一个数据绑定控件呢?毕竟,当显示数据收集时,我们已经有超过 10 个控件可供选择,其中包括逐渐不再使用的 DataGrid、新的和改进的 GridView、非常可靠和简单的 Repeater、独特和灵活的 DataList、方便的 FormView 及其稍显冗余的同行 DetailsView。当然,还有一维列表控件 BulletedList、ListBox、DropDownList、RadioButtonList 和 CheckBoxList。
理论上,ListView 可以取代 ASP.NET 里的所有其它数据绑定控件。这一点没有疑义。您可以使用 ListView 控件代替上面列表中的其他每个控件。ListView 还可以使一些数据绑定任务比使用前几个控件工作起来更加便利,包括 CSS 样式设定、灵活的分页和完善的排序、插入、删除和更新功能。
我们让介绍 ListView 的典型使用模式,然后讲解控件的功能,展示其灵活性和强大的能力。在本专栏的结尾,您将掌握足够的信息来决定应该在您的 ASP.NET 工具箱中保留多少个数据绑定控件。
ListView 基础
ListView 是模板驱动的控件,这意味着它默认情况下不会呈现任何数据——您必须以模板的形式完全指定希望它呈现的 HTML。与大多数模板控件类似,ItemTemplate 将成为您工作的重点,您需要将绑定数据集中每一行不断重复的 HTML 内容放在 ItemTemplate 里。
ListView 中的新功能,也是它与其它控件的真正不同之处在于引进了 LayoutTemplate。在 LayoutTemplate 中,您可以将要输出的顶级 HTML 定义为控件呈现的内容。例如,如果希望 ListView 作为表格呈现,则可以在 LayoutTemplate 中包含顶级 <table> 和 <thead> 元素,把行和单元格的呈现留给 ItemTemplate,如图 1 所示(在本示例中,绑定的数据源将显示包含电影标题和发行日期的简单表格)。图 2 显示了浏览器呈现。
<asp:ListView runat="server" ID="_simpleTableListView"
DataSourceID="_moviesDataSource">
<LayoutTemplate>
<table>
<thead>
<tr>
<th>ID</th>
<th>Title</th>
<th>Release Date</th>
</tr>
</thead>
<tbody>
<asp:PlaceHolder runat="server" ID="itemPlaceholder" />
</tbody>
</table>
</LayoutTemplate>
<ItemTemplate>
<tr>
<td><%# Eval("movie_id") %></td>
<td><%# Eval("title") %></td>
<td><%# Eval("release_date", "{0:d}") %></td>
</tr>
</ItemTemplate>
</asp:ListView>
DataSourceID="_moviesDataSource">
<LayoutTemplate>
<table>
<thead>
<tr>
<th>ID</th>
<th>Title</th>
<th>Release Date</th>
</tr>
</thead>
<tbody>
<asp:PlaceHolder runat="server" ID="itemPlaceholder" />
</tbody>
</table>
</LayoutTemplate>
<ItemTemplate>
<tr>
<td><%# Eval("movie_id") %></td>
<td><%# Eval("title") %></td>
<td><%# Eval("release_date", "{0:d}") %></td>
</tr>
</ItemTemplate>
</asp:ListView>
Figure 2 显示在表格中的列表
LayoutTemplate 和 ItemTemplate 之间的关联由 LayoutTemplate 中 ID 设置为 itemPlaceholder 的单一服务器端控件完成。(您可以使用 ListView 的 ItemPlaceholderID 属性更改 ID 字符串的默认值。)在第一个示例中,我将 PlaceHolder 控件的实例放置在模板中,即我希望注入 ItemTemplate 内容的位置。请注意:尽管必须支持子控件,但并没有限制必须使用什么类型的控件作为占位符——ID 才是重要。例如,我可以使用服务器端表格行代替 PlaceHolder 控件编写 LayoutTemplate,实现同样的效果:
<LayoutTemplate>
<table>
<thead>
<tr>
<th>ID</th>
<th>Title</th>
<th>Release Date</th>
</tr>
</thead>
<tbody>
<tr runat="server" ID="itemPlaceholder" />
</tbody>
</table>
</LayoutTemplate>
<table>
<thead>
<tr>
<th>ID</th>
<th>Title</th>
<th>Release Date</th>
</tr>
</thead>
<tbody>
<tr runat="server" ID="itemPlaceholder" />
</tbody>
</table>
</LayoutTemplate>
通常情况下,出于以下两个原因,我更喜欢使用通用的 PlaceHolder 控件。第一个原因是名称匹配得很好。而且,该控件并不呈现其自身的 HTML,而是用 ItemTemplate 的内容代替,因此如果控件除在层次结构中保留位置以外无任何其它目的,这是更合乎逻辑的选择。
当然,使 ListView 如此灵活的原因是您可以完全控制 LayoutTemplate 的内容。您不是只能使用表格——您可以将任何希望呈现的 HTML 放置在 LayoutTemplate 中,只要注入 itemPlaceholder 控件位置时 ItemTemplate 的内容有效即可。以下是绑定到相同电影数据源的 ListView 示例,但这次不是表格,是带有标题和发行日期的电影显示在项目符号列表中(结果列表如图 3 所示):
Figure 3 相同列表,不同格式
<asp:ListView runat="server"
ID="_simpleTableListView"
DataSourceID="_moviesDataSource">
<LayoutTemplate>
<ul>
<asp:PlaceHolder runat="server"
ID="itemPlaceholder" />
</ul>
</LayoutTemplate>
<ItemTemplate>
<li><%# Eval("title") %>,
<%# Eval("release_date", "{0:d}") %> </li>
</ItemTemplate>
</asp:ListView>
ID="_simpleTableListView"
DataSourceID="_moviesDataSource">
<LayoutTemplate>
<ul>
<asp:PlaceHolder runat="server"
ID="itemPlaceholder" />
</ul>
</LayoutTemplate>
<ItemTemplate>
<li><%# Eval("title") %>,
<%# Eval("release_date", "{0:d}") %> </li>
</ItemTemplate>
</asp:ListView>
ListView 和 CSS
ASP.NET 开发人员长久以来在创建 CSS 驱动的站点时都受到单独控件的限制。许多默认控件呈现内联样式,或者难于使 CSS 类与其 HTML 输出部分相关联。实际上 Microsoft 在 2006 年 4 月已发布名为“CSS 控件适配器”的工具包,该工具包为几个完全由 CSS 驱动的控件(包括 GridView)提供了可选呈现机制,帮助纠正该问题(有关详细信息,请参见 2006 年 10 月的“非常 ASP.NET”专栏 msdn.microsoft.com/msdnmag/issues/06/10/ExtremeASPNET)。这些备用呈现机制从未并入完整版当中,所以需要单独安装且缺少设计人员支持。
ListView 通过让您完全控制何时何地应用样式表,使您在站点里利用 CSS 变得更为简捷。一种常见的情形是开发人员为特定页面手动预先设计,通常包含 HTML 和 CSS。采用传统的 GridView 呈现数据表的特定设计总是很难保证正确,因为 GridView 类仅提供用于修改 HTML 结果的有限挂接集。
我见过许多开发人员经历过的试验和错误,将样式属性应用到网格,查看页面源以准确理解样式放置的位置,并反复试验直到网格能够按要求呈现为止。使用 ListView,您不必再做这些猜测工作了,因为现在您可以控制布局和内容。
例如,假设提供给您的表格需要按照图 4 所示的方式显示,并使用由 .htm 和 .css 文件组成的设计,如图 5中所示。
<div class="PrettyGrid">
<table cellpadding="0" cellspacing="0" summary="">
<thead>
<tr>
<th scope="col"><a href="http://.">ID</a></th>
<th scope="col"><a href="http://.">Title</a></th>
<th scope="col"><a href="http://.">Release date</a></th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Where the Wild Things Are</td>
<td>12/15/2008</td>
</tr>
<!--
-->
</tbody>
</table>
<div class="Pagination">
<span>1</span>
<a href="http://.">2</a>
<a href="http://.">3</a>
</div>
</div>
<table cellpadding="0" cellspacing="0" summary="">
<thead>
<tr>
<th scope="col"><a href="http://.">ID</a></th>
<th scope="col"><a href="http://.">Title</a></th>
<th scope="col"><a href="http://.">Release date</a></th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Where the Wild Things Are</td>
<td>12/15/2008</td>
</tr>
<!--
</tbody>
</table>
<div class="Pagination">
<span>1</span>
<a href="http://.">2</a>
<a href="http://.">3</a>
</div>
</div>
CSS
.PrettyGrid
{
width: 100%;
}
.PrettyGrid div.Pagination,
.PrettyGrid div.Pagination a,
.PrettyGrid div.Pagination span
{
color: #00FFFF;
background: #284775;
font-weight: normal;
padding: 2px;
}
.PrettyGrid table
{
border: solid 1px #CCCCCC;
width: 100%;
}
/*
*/
{
width: 100%;
}
.PrettyGrid div.Pagination,
.PrettyGrid div.Pagination a,
.PrettyGrid div.Pagination span
{
color: #00FFFF;
background: #284775;
font-weight: normal;
padding: 2px;
}
.PrettyGrid table
{
border: solid 1px #CCCCCC;
width: 100%;
}
/*