### 使用 ASP+ 列表绑定控件（中）

Repeater1Page 类覆盖了 Page 类的 OnLoad 方法。此表示在对该页
的首次请求中调用 DataBind。这将导致对这些页上的数据绑定表达式求
值并使 repeater 控件列举数据源以及创建其项目。仅在首次请求时调用
DataBind 方法。这之所以能正常工作是因为 repeater 能够在从前一次保
存状态的回传过程中重新创建其项目，而无需数据源实例。
此页将类型 ICollection 的公用属性显露出来。这将在设置 repeater
的 DataSource 属性值的数据绑定表达式中使用。属性的获取实现使用包
含一组 SiteInfo 对象序列的 ArrayList。此属性是公用的，因为只有页类
的公用和保护成员可在数据绑定表达式中使用。
每个 SiteInfo 对象有两个属性：SiteName 和 SiteURL。当对模板中
的 HyperLink 控件进行数据绑定时将访问这些属性。在此控件的绑定表达
式中，Container.DataItem 表示要将特定项绑定到其上的单个 SiteInfo
对象。DataBinder.Eval(Container.DataItem, "SiteName") 访问当前
SiteInfo 对象的 SiteName 属性。
Repeater1 示例向您介绍了几个基本概念：
●定义模板
●模板中的数据绑定语法和数据绑定表达式
●将 ArrayList 的 ICollection 表示用作数据源
●在最初处理页的过程中调用 DataBind 方法
DataList 控件
DataList 控件是一个模板化控件，它提供使用样式属性可视化地格式
化其表示的能力。它也可以产生多列布局。
摘自 DataList1.aspx：
〈%@ Page language="C#" src="DataList1.cs" inherits="Samples.
DataList1Page"%〉
...
〈asp:DataList runat=server id="peopleDataList"
RepeatColumns="2" RepeatDirection="Vertical" RepeatMode="Table"
Width="100%"〉
〈property name="AlternatingItemStyle"〉
〈asp:TableItemStyle BackColor="#EEEEEE"/〉
〈/property〉
〈template name="ItemTemplate"〉
〈asp:Panel runat=server font-size="12pt" font-bold="true"〉
〈%# ((Person)Container.DataItem).Name %〉
〈/asp:Panel〉
〈asp:Label runat=server Width="20px"
BorderStyle="Solid" BorderWidth="1px" BorderColor="Black"
BackColor='〈%# ((Person)Container.DataItem).FavoriteColor
%〉'〉
〈/asp:Label〉
〈asp:Label runat=server Font-Size="10pt"
Text='〈%# GetColorName(((Person)Container.DataItem).
FavoriteColor) %〉'〉
〈/asp:Label〉
〈/template〉
〈/asp:DataList〉
此 .aspx 文件显示了用来生成此示例的 DataList 的声明。
在此示例中，DataList 的多列布局是通过将 RepeatColumns 属性设
置为“2”来实现的。将 RepeatDirection 设置为“Vertical”会使项目从
上到下、然后从左到右排列。相反，值设置为“Horizontal”会导致项目
从左到右、然后从上到下排列。
aspx 语法包含对少数几种 DataList 的样式属性的设置。在此示例中，
DataList 的 Width 被设置为其父级的 100%。设置具灰色背景的 Alternating
ItemStyle 是为了获得带有条纹的外观。此示例还说明模板可以包含任意
复杂的控件定义，以满足在每个项目内获得理想布局的需要。
最后此模板中的数据绑定表达式通过将 Container.DataItem 转换为其
类型来使用前期绑定。这不会招致与使用 DataBinder.Eval（如 Repeater1
中所示)相关联的后期绑定的代价。但是，这种方法可能会产生可读性较
差的表达式。以下示例还给出了一个调用 GetColorName 方法（该方法是在
本页有代码支持的文件中实现的）的表达式示例。
DataList1.cs:
namespace Samples {
...
public class DataList1Page : Page {
protected DataList peopleDataList;
protected string GetColorName(Color c) {
return
TypeDescriptor.GetConverter(typeof(Color)).Convert
ToString(c);
}
private void LoadPeopleList() {
// 创建数据源
Person[] people = new Person[] {
new Person("Nikhil Kothari", Color.Green),
new Person("Steve Millet", Color.Purple),
new Person("Chris Anderson", Color.Blue),
new Person("Mike Pope", Color.Orange),
new Person("Anthony Moore", Color.Yellow),
new Person("Jon Jung", Color.MediumAquamarine),
new Person("Susan Warren", Color.SlateBlue),
new Person("Izzy Gryko", Color.Red)
};
// 设置控件的数据源
peopleDataList.DataSource = people;
// 并使该控件用此数据源构建其项目
peopleDataList.DataBind();
}
protected override void OnLoad(EventArgs e) {
base.OnLoad(e);
if (!IsPostBack) {
// 首次请求此页
LoadPeopleList();
}
}
}
public sealed class Person {
private string name;
private Color favoriteColor;
public Person(string name, Color favoriteColor) {
this.name = name;
this.favoriteColor = favoriteColor;
}
public Color FavoriteColor {
get { return favoriteColor; }
}
public string Name {
get { return name; }
}
}
}
在此页中，控件的 DataSource 属性是通过程序设置的，与在 aspx 文
件中声明性地设置相对。两种方法的结果相同。无法选择哪种方法，都必
须调用 DataBind 方法，以便控件可以列举其数据源并创建它要表示的项
目。
此示例中所用的数据源是 Person 对象的一个简单数组。由于每个数
组都实现 ICollection 方法，所以数组适合用作数据源。这显示了将数据
结构和类型用作数据源时可获得的灵活程度。
DataList1 示例介绍了下列概念：
●在模板中定义丰富的 HTML UI
●使用简单数组作为数据源
●通过程序设置数据源
●数据绑定语法中所允许的各种表达式
DataGrid 控件
DataGrid 控件使您可以生成数据源格式丰富的列表表示。此外，它
还支持随其它操作选择项目。
本节的四个示例使用包含有关书名信息（标题、标题 ID、作者、价格
和出版日期）的表。全部数据都用 TitlesDB.xml 中的 XML 予以维持。在建
立页面来表示此表的内容并选择书籍时，这些示例遵循增量方法。代码列
表包含黑体文本，以表明一个示例构建于以前示例时所作的更改。
截自 TitlesDB.xml：
〈root〉
〈schema id="DocumentElement" targetNamespace=""
xmlns=http://www.w3.org/1999/XMLSchema
xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"〉
〈element name="Title"〉
〈complexType content="elementOnly"〉
〈element name="title_id" type="string"〉〈/element〉
〈element name="title" type="string"〉〈/element〉
〈element name="au_name" type="string"〉〈/element〉
〈element name="price" msdata:DataType="System.
Currency"
minOccurs="0"
type="string"〉〈/element〉
〈element name="pubdate" type="timeInstant"〉
〈/element〉
〈/complexType〉
〈unique name="TitleConstraint" msdata:PrimaryKey="True"〉
〈selector〉.〈/selector〉
〈field〉title_id〈/field〉
〈/unique〉
〈/element〉
〈/schema〉
〈DocumentElement〉
〈Title〉
〈title_id〉BU1032〈/title_id〉
〈title〉The Busy Executive's Database Guide〈/title〉
〈au_name〉Marjorie Green〈/au_name〉
〈price〉19.99〈/price〉
〈pubdate〉1991-06-12T07:00:00〈/pubdate〉
〈/Title〉
...
〈/DocumentElement〉
〈/root〉
在典型的 Web 应用程序中，为了获得最大的可伸缩性和性能上的好处，
很可能会使用 Web 服务或商业对象来存取数据。为了简化这些示例并将注
意力集中在使用 DataGrid 而不是数据存取上，我们选择在应用程序启动
时一次性加载数据，并在 Global.asax 中的 ASP 应用程序状态中高速缓
存所得的 DataSet，如下所示。
截自 Global.asax：
public void Application_OnStart() {
FileStream fs = null;
DataSet ds = null;
try {
fs = new FileStream(Server.MapPath("TitlesDB.xml"),
FileMode.Open,
FileAccess.Read);
ds = new DataSet();
// 将 xml 文件中的数据加载到 DataSet 中
ds.ReadXml(fs);
} finally {
if (fs != null) {
fs.Close();
fs = null;
}
}
// 将数据集高速缓存到应用程序状态中，以便在单个页面中使用
Application["TitlesDataSet"] = ds;
}
DataGrid1
DataGrid1 说明 DataGrid 的基本用法，说明控件如何用最少的用户代
码生成表示来提供丰富的功能。
截自 DataGrid1.aspx：
〈%@ Page language="C#" src="DataGrid.cs" inherits="Samples.Data
GridPage"%〉
...
〈asp:DataGrid runat=server id="titlesGrid"〉
〈/asp:DataGrid〉
上面的.aspx 文件显示在不设置 DataGrid 控件任何属性的情况下对
其进行声明。
DataGrid.cs：
namespace Samples {
...
public class DataGridPage : Page {
protected DataGrid titlesGrid;
public ICollection GetTitlesList() {
// 从在应用程序状态中高速缓存的 DataSet 中检索标题列
表。
DataSet titlesDataSet = (DataSet)Application["Titles
DataSet"];
if (titlesDataSet != null) {
return titlesDataSet.Tables["Title"].DefaultView;
}
else {
return null;
}
}
private void LoadTitlesGrid() {
// 从数据库中检索数据
ICollection titlesList = GetTitlesList();
// 设置控件的数据源
titlesGrid.DataSource = titlesList;
// 并使它用此数据源构建其项目
titlesGrid.DataBind();
}
protected override void OnLoad(EventArgs e) {
base.OnLoad(e);
if (!IsPostBack) {
// 首次请求此页
LoadTitlesGrid();
}
}
}
}
.cs 文件包含用于此页的代码。此代码与 DataList1 示例中使用的代码
功能相同。在对此页的首次请求中，它覆盖 OnLoad 方法以检索数据并在
调用 DataBind 之前设置控件的 DataSource 属性。这将使 DataGrid 创建其项
目，这些项目是表中必要的行。在回传处理的过程中，DataGrid 从状态
（该状态包括在上一次请求中所保存的单元格内容）重新创建项目。
此示例说明了 DataGrid 控件的 AutoGenerateColumns 属性的功能。
此属性的默认值为 true。当设置为 true 时，DataGrid 将使用 reflection
检查其数据源和对象，并为每个公用属性或字段创建一个列。在此示例中，
控件表示“标题”表中当前的所有字段。这一功能允许用最少的用户代码
快速而容易地生成任何数据源的列表表示。
每个自动生成列的类型都是 BoundColumn。这种列类型将与其关联的
属性值转换为要用作表单元格文本的字符串。
DataGrid2
DataGrid2 说明具有在.aspx 文件中定义的 Columns 集合的 DataGrid。
摘自 DataGrid2.aspx：
〈%@ Page language="C#" src="DataGrid.cs" inherits="Samples.Data
GridPage"%〉
...
〈asp:DataGrid runat=server id="titlesGrid"
AutoGenerateColumns="false"〉
〈property name="Columns"〉
〈asp:BoundColumn headerText="Title" DataField="title"/〉
〈asp:BoundColumn headerText="Author" DataField="au_name"/〉
〈asp:BoundColumn headerText="Date Published" DataField="
pubdate"/〉
〈asp:BoundColumn headerText="Price" DataField="price"/〉
〈/property〉
〈/asp:DataGrid〉
此.aspx 文件显示了一个具有用户指定的列集合的 DataGrid 控件。
此示例使用与 DataGrid1 相同的有代码支持的文件，因为不需要更改任
何代码。
DataGrid 的 AutoGenerateColumns 属性被设置为假，从而阻止控件自
动生成列，而让用户负责定义将要在表中表示的列。
有许多好处：
●您可控制列的顺序。以声明的顺序表示列。另一方面，自动生成的列是
按用映像检索到的顺序表示的，此顺序不必与代码中的列顺序或数据库表
本身的列顺序相匹配。
●可以用列的 headerText 属性来指定每列的标头。在前一个示例中，列标
头指明了字段名，这可能并不合适。当在此模式下使用控件时，Columns
还提供其它可设置的属性。
●自动生成的列的类型始终是 BoundColumn。指定列集合使用户可以控制
每列的类型。