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 的基本用法,说明控件如何用最少的用户代码生成表示来提供丰富的功能。
图 4. 通过使用具有自动生成列的 DataGrid 产生的示例
截自 DataGrid1.aspx:
<%@ Page language="C#" src="DataGrid.cs" inherits="Samples.DataGridPage"%>
...
<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["TitlesDataSet"];
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。
图 5. 通过使用具有指定列的 DataGrid 产生的示例
摘自 DataGrid2.aspx:
<%@ Page language="C#" src="DataGrid.cs" inherits="Samples.DataGridPage"%>
...
<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。指定列集合使用户可以控制每列的类型。
DataGrid3
DataGrid3 通过添加可视格式化和内容格式化构建于 DataGrid2 之上。
图 6. 由设置了样式和格式化属性的 DataGrid 产生的示例
摘自 DataGrid3.aspx:
<%@ Page language="C#" src="DataGrid.cs" inherits="Samples.DataGridPage"%>
...
<asp:DataGrid runat=server id="titlesGrid"
AutoGenerateColumns="false"
Width="80%"
BackColor="White"
BorderWidth="1px" BorderStyle="Solid" CellPadding="2" CellSpacing="0"
BorderColor="Tan"
Font-Name="宋体" Font-Size="8pt">
<property name="Columns">
<asp:BoundColumn headerText="Title" DataField="title"/>
<asp:BoundColumn headerText="Author" DataField="au_name"/>
<asp:BoundColumn headerText="Date Published" DataField="pubdate"
DataFormatString="{0:MMM yyyy}"/>
<asp:BoundColumn headerText="Price" DataField="price"
DataFormatString="{0:c}">
<property name="ItemStyle">
<asp:TableItemStyle HorizontalAlign="Right"/>
</property>
</asp:BoundColumn>
</property>
<property name="headerStyle">
<asp:TableItemStyle BackColor="DarkRed" ForeColor="White"
Font-Bold="true"/>
</property>
<property name="ItemStyle">
<asp:TableItemStyle ForeColor="DarkSlateBlue"/>
</property>
<property name="AlternatingItemStyle">
<asp:TableItemStyle BackColor="Beige"/>
</property>
</asp:DataGrid>
此 .aspx 文件显示了与前面相同的 DataGrid 控件声明,并设置了各种样式属性。这将导致视觉上更具吸引力的表示。仍就不需要对代码进行任何更改,使用与以前示例相同的有代码支持的文件。
因为它是从 WebControl 得到的,所以 DataGrid 控件继承了诸如 Width、BackColor、BorderStyle 和 Font.Name 之类的样式属性。此外,DataGrid 提供诸如 CellPadding 这样的属性,这些属性是特定于表的。这些属性允许从总体上定制控件。
声明还显示了设置的若干项目样式,如 headerStyle 和 AlternatingItemStyle。这些样式控制着它们相应项目的外观。请注意此示例中出现的样式合并。备选项目与一般项目的前景色相同,因为它们的样式是 AlternatingItemStyle 和 ItemStyle 的组合。最后,此示例还通过右对齐价格列中的文本说明了为特定列设置样式。
DataGrid 还允许您格式化其单元格中的文本内容。这是通过设置 BoundColumn 的 DataFormatString 属性值完成的。该列使用其格式说明格式化使用 String.Format 的单元格内容。此属性可随格式化类型(如日期或货币)一起预置或附加任意内容。此外,由于格式化考虑了当前页的 CultureInfo 和请求,所以它也支持全局化。如果未指定格式,则使用该值的 ToString 方法。
DataGrid4
DataGrid4 说明如何通过处理 SelectedIndexChanged 事件来利用 DataGrid 中的选择。
图 7. 由允许选择其包含项目的 DataGrid 产生的示例
截自 DataGrid4.aspx:
<%@ Page language="C#" src="DataGrid4.cs" inherits="Samples.DataGrid4Page"%>
...
<asp:DataGrid runat=server id="titlesGrid"
AutoGenerateColumns="false"
Width="80%"
BackColor="White"
BorderWidth="1px" BorderStyle="Solid" CellPadding="2" CellSpacing="0"
BorderColor="Tan"
Font-Name="宋体" Font-Size="8pt"
DataKeyField="title_id"
OnSelectedIndexChanged="OnSelectedIndexChangedTitlesGrid">
<property name="Columns">
<asp:ButtonColumn Text="Select" Command="Select"/>
<asp:BoundColumn headerText="Title" DataField="title"/>
<asp:BoundColumn headerText="Author" DataField="au_name"/>
<asp:BoundColumn headerText="Date Published" DataField="pubdate"
DataFormatString="{0:MMM yyyy}"/>
<asp:BoundColumn headerText="Price" DataField="price"
DataFormatString="{0:c}">
<property name="ItemStyle">
<asp:TableItemStyle HorizontalAlign="Right"/>
</property>
</asp:BoundColumn>
</property>
<property name="headerStyle">
<asp:TableItemStyle BackColor="DarkRed" ForeColor="White"
Font-Bold="true"/>
</property>
<property name="ItemStyle">
<asp:TableItemStyle ForeColor="DarkSlateBlue"/>
</property>
<property name="AlternatingItemStyle">
<asp:TableItemStyle BackColor="Beige"/>
</property>
<property name="SelectedItemStyle">
<asp:TableItemStyle BackColor="PaleGoldenRod" Font-Bold="true"/>
</property>
</asp:DataGrid>
...
<asp:Label runat=server id="selectionInfoLabel" Font-Name="宋体" Font-Size="8pt"/>
在此 .aspx 文件中,为 DataGrid 的 SelectedIndexChanged 事件注册了一个事件处理程序。此事件处理程序是在有代码支持的文件中实现的。已在列集合中添加了一个命令 为“Select”的 ButtonColumn,使得 DataGrid 为每个项目表示一个包含 Select 按钮的附加列。同时指定了 SelectedItemStyle。此样式用于从视觉上区分选定的项目。最后还指定了 DataGrid 的 DataKeyField 属性。此字段将置入 DataGrid 的 DataKeys 集合,该集合将在有代码支持的文件中用到。
DataGrid4.cs:
namespace Samples {
...
public class DataGrid4Page : Page {
protected DataGrid titlesGrid;
protected Label selectionInfoLabel;
public ICollection GetTitlesList() {
// 从在应用程序状态中高速缓存的 DataSet 中检索标题列表。
DataSet titlesDataSet = (DataSet)Application["TitlesDataSet"];
if (titlesDataSet != null) {
return titlesDataSet.Tables["Title"].DefaultView;
}
else {
return null;
}
}
private void LoadTitlesGrid() {
// 从数据库中检索数据
ICollection titlesList = GetTitlesList();
// 设置控件的数据源并重新设置其选择,
titlesGrid.DataSource = titlesList;
titlesGrid.SelectedIndex = -1;
// 并使该控件使用此数据源构建其项目
titlesGrid.DataBind();
// 更新选定的标题信息
UpdateSelectedTitleInfo();
}
protected override void OnLoad(EventArgs e) {
base.OnLoad(e);
if (!IsPostBack) {
// 首次请求此页
LoadTitlesGrid();
}
}
// 处理 DataGrid 的 OnSelectedIndexChanged 事件
protected void OnSelectedIndexChangedTitlesGrid(object sender,
EventArgs e) {
UpdateSelectedTitleInfo();
}
private void UpdateSelectedTitleInfo() {
// 获取选定的索引
int selIndex = titlesGrid.SelectedIndex;
string selTitleID = null;
string selectionInfo;
if (selIndex != -1) {
// 显示选定标题的关键字段
selTitleID = (string)titlesGrid.DataKeys[selIndex];
selectionInfo = "ID of selected title: " + selTitleID;
}
else {
selectionInfo = "No title is currently selected.";
}
selectionInfoLabel.Text = selectionInfo;
}
}
}
此 .cs 文件包含处理 SelectedIndexChanged 事件以及在 DataGrid 下显示选定标题的 ID 的逻辑。DataGrid 处理命令事件,该事件是通过包含在其项目中的按钮触发的。它识别标准命令“Select”,该命令使其更改它的 SelectedIndex 属性,并通过触发此事件来将此更改通知用户的代码。
在实现事件处理程序的过程中,示例代码调用 UpdateSelectedTitleInfo 方法。该方法负责显示有关选定书名的信息,本例中为标题的 ID。在更现实的方案中,此 ID 可用来链接某个页面,以显示有关选定标题的更多详细信息。
ID 是通过访问 DataKeys 集合进行检索的。该集合是因为设置了 DataKeyField 属性而置入的。通常,将它设置为主关键字或使用户可以唯一标识项目的某些其它字段,并将此信息用作后续的数据库查询或过滤数据中的准则。
此示例说明除了仅仅表示数据源中的对象之外,如何进一步支持诸如选择数据源中对象之类的操作。DataGrid 包含对若干其它特性(如排序、分页、现场编辑和 TemplateColumns)的支持。但是,这些特定特性超出了本文的讨论范围,将在以后的文章中加以探讨。
Repeater、DataList 或 DataGrid?
Repeater、DataList 和 DataGrid 控件共享公用编程模型。同时,每个控件都被设计为侧重某个特定方案,为正确的方案选择正确的列表绑定控件是一个重要的决策。本节说明控件层次结构和每种控件的功能,以及每种控件可能用于的典型方案的示例。
正如在下面的类层次结构中看到的那样,Repeater 是一种小巧轻便的控件。它只继承了基本Control类的功能,如 ID 属性和子控件集合。另一方面,DataList 控件和 DataGrid 控件都继承了 WebControl 功能,如样式和外观属性。
图 8. 列表绑定控件的类层次结构
在对象模型方面,repeater 控件是最简单的控件。它同时也是最小的数据绑定控件并且基本上是不同的,即它不会强制使用任何特殊的 UI 布局。最后的表示遵循生成文本的方法,其方式是通过重复为此控件指定的模板内容。此控件对样式和外观属性或行为不提供任何内建的支持。对于需要完全控制表示的方案而言,它是一个极好的选择。
DataList 控件是强制使用分列布局或流布局的 repeater。它继承了 WebControl 中实现的外观属性,并增加了适用于它所创建的项目的其它样式属性。DataList 控件还包括对其项目标准操作(如选择、编辑和删除)的支持。它很适用于生成分布于一列或多列的水平或垂直的项目序列流。
DataGrid 控件强制使用列或行的列表布局。与 DataList 类似,此控件提供样式和外观属性。除选择和编辑之外,DataGrid 还支持对整个项目集合的高级操作,如分页和排序。DataGrid 和 DataList 的一个主要区别是 DataGrid 不包含任何模板属性,即 DataGrid 控件的项目或行是非模板化的。但是,将 TemplateColumn 添加到 DataGrid 中就可以在特定列中使用模板。
下表是列表绑定控件所提供的功能的摘要。
功能 Repeater DataList DataGrid
模板 是(必需) 是(必需) 列内(可选)
列表布局 否 否 是
流布局 是 是 否
分列/报纸栏目样式布局 否 是 否
样式和外观属性 否 是 是
选择 否 是 是
编辑 否 是 是
删除 否 是 是
分页 否 否 是
排序 否 否 是
相关资源
随 Microsoft .NET Framework SDK 发布的 QuickStart 示例包含这些控件的若干示例,以及说明使用 XML 和 Web 服务存取数据的示例。SDK 附带的文档包括相关主题的概念性资料,如 ASP+ 页面框架和服务器控件,以及说明作为此框架一部分的控件的对象模型的参考书目。
……