GridView是ASP.NET 1.x的DataGrid控件的后继者。它提供了相同的基本功能集,同时增加了大量扩展和改进。如前所述,DataGrid(ASP.NET 2.0仍然完全支持)是一个功能非常强大的通用控件。然而,它有一个重大缺陷:它要求我们编写大量定制代码,甚至处理比较简单而常见的操作,诸如分页、排序、编辑或删除数据等也不例外。GridView控件旨在解决此限制,并以尽可能少的数据实现双向数据绑定。该控件与新的数据源控件系列紧密结合,而且只要底层的数据源对象支持,它还可以直接处理数据源更新。
这种实质上无代码的双向数据绑定是新的GridView控件最著名的特征,但是该控件还增强了很多其他功能。该控件之所以比DataGrid控件有所改进,是因为它能够定义多个主键字段、新的列类型以及样式和模板选项。GridView还有一个扩展的事件模型,允许我们处理或撤销事件。
GridView控件为数据源的内容提供了一个表格式的类网格视图。每一列表示一个数据源字段,而每一行表示一个记录。该类声明如下:
public class GridView : CompositeDataBoundControl,
ICallbackContainer,
ICallbackEventHandler
该基类确保数据绑定和命名容器支持。ICallbackContainer和ICallbackEventHandler接口提供了比现在支持的更有效的分页和排序功能。它通过使用新的脚本回调技术的客户端的out-of-band调用来完成。(稍候将会更详细地讨论这一点。)首先让我们来看看GridView控件的编程接口。
1. GridView控件的属性
GridView支持大量属性,这些属性属于如下几大类:行为、可视化设置、样式、状态和模板。表10.6详细描述了影响的行为的属性。
表10.6 GridView控件的行为属性
|
属性
|
描述
|
|
AllowPaging
|
指示该控件是否支持分页。
|
|
AllowSorting
|
指示该控件是否支持排序。
|
|
AutoGenerateColumns
|
指示是否自动地为数据源中的每个字段创建列。默认为true。
|
|
AutoGenerateDeleteButton
|
指示该控件是否包含一个按钮列以允许用户删除映射到被单击行的记录。
|
|
AutoGenerateEditButton
|
指示该控件是否包含一个按钮列以允许用户编辑映射到被单击行的记录。
|
|
AutoGenerateSelectButton
|
指示该控件是否包含一个按钮列以允许用户选择映射到被单击行的记录。
|
|
DataMember
|
指示一个多成员数据源中的特定表绑定到该网格。该属性与DataSource结合使用。如果DataSource是有一个DataSet对象,则该属性包含要绑定的特定表的名称。
|
|
DataSource
|
获得或设置包含用来填充该控件的值的数据源对象。
|
|
DataSourceID
|
指示所绑定的数据源控件。
|
|
EnableSortingAndPagingCallbacks
|
指示是否使用脚本回调函数完成排序和分页。默认情况下禁用。
|
|
RowHeaderColumn
|
用作列标题的列名。该属性旨在改善可访问性。
|
|
SortDirection
|
获得列的当前排序方向。
|
|
SortExpression
|
获得当前排序表达式。
|
|
UseAccessibleHeader
|
规定是否为列标题生成<th>标签(而不是<td>标签)。
|
SortDirection和SortExpression属性规定当前决定行的排列顺序的列上的排序方向和排序表达式。这两个属性都是在用户单击列的标题时由该控件的内置排序机制设置的。整个排序引擎通过AllowSorting属性启用和禁用。EnableSortingAndPagingCallbacks属性打开和关闭该控件的使用脚本回调进行分页和排序,而不用往返于服务器并改变整个页面的功能。
GridView控件内显示的每一行对应于一种特殊的网格项。预定义的项目类型几乎等于DataGrid的项目类型,包括标题、行和交替行、页脚和分页器等项目。这些项目是静态的,因为它们在控件的生命期内在应用程序中保持不变。其他类型的项目在短暂的时间(即,完成某种操作所需的时间)内是活动的。动态项目是编辑行、所选的行和EmptyData项。当网格绑定到一个空的数据源时,EmptyData标识该网格的主体。
0 && image.height>0){if(image.width>=510){this.width=510;this.height=image.height*510/image.width;}}" href="http://book.csdn.net/BookFiles/73/10/image002.jpg"> 注意 GridView控件提供了几个专门为了可访问性而设计的属性。这些属性是UseAccessibleHeader、Caption、CaptionAlign和RowHeaderColumn。设置RowHeaderColumn时,将用默认的标题样式(黑体字)输出该列的所有单元。然而,ShowHeader、HeaderStyle和其他与标题相关的属性并不会影响由RowHeaderColumn指示的列。
表10.7详细描述了GridView控件上可用的样式属性。
表10.7 GridView控件的样式属性
|
样式
|
描述
|
|
AlternatingRowStyle
|
定义表中每隔一行的样式属性。
|
|
EditRowStyle
|
定义正在编辑的行的样式属性。
|
|
FooterStyle
|
定义网格的页脚的样式属性。
|
|
HeaderStyle
|
定义网格的标题的样式属性。
|
|
EmptyDataRowStyle
|
定义空行的样式属性,这是在GridView绑定到空数据源时生成。
|
|
PagerStyle
|
定义网格的分页器的样式属性。
|
|
RowStyle
|
定义表中的行的样式属性。
|
|
SelectedRowStyle
|
定义当前所选行的样式属性。
|
表10.8列出了影响控件外观的大多数属性,而表10.9列出了模板属性。
表10.8 GridView控件的外观属性
|
属性
|
描述
|
|
BackImageUrl
|
指示要在控件背景中显示的图像的URL。
|
|
Caption
|
在该控件的标题中显示的文本。
|
|
CaptionAlign
|
标题文本的对齐方式。
|
|
CellPadding
|
指示一个单元的内容与边界之间的间隔(以像素为单位)。
|
|
CellSpacing
|
指示单元之间的间隔(以像素为单位)。
|
|
GridLines
|
指示该控件的网格线样式。
|
|
HorizontalAlign
|
指示该页面上的控件水平对齐。
|
|
EmptyDataText
|
指示当该控件绑定到一个空的数据源时生成的文本。
|
|
PagerSettings
|
引用一个允许我们设置分页器按钮的属性的对象。
|
|
ShowFooter
|
指示是否显示页脚行。
|
|
ShowHeader
|
指示是否显示标题行。
|
PagerSettings对象把所有可以对分页器设置的可视化属性组织在一起。其中有很多属性在DataGrid程序员看来应该是熟悉的。PagerSettings类还添加了一些新属性以满足新的预定义的按钮(第1页和最后一页),并在链接中使用图像代替文本。(我们需要合计出一条和使用DataGrid时相同的诀窍。)
表10.9 GridView控件的模板属性
|
模板
|
描述
|
|
EmptyDataTemplate
|
指示该控件绑定到一个空的数据源时要生成的模板内容。如果该属性和EmptyDataText属性都设置了,则该属性优先采用。如果两个属性都没有设置,则把该网格控件绑定到一个空的数据源时不生成该网格。
|
|
PagerTemplate
|
指示要为分页器生成的模板内容。该属性覆盖我们可能通过PagerSettings属性作出的任何设置。
|
最后剩下的是状态属性,表10.10列出了这些属性。状态属性返回有关控件的内部状态的信息。
表10.10 状态属性
|
属性
|
描述
|
|
BottomPagerRow
|
返回表格该网格控件的底部分页器的GridViewRow对象。
|
|
Columns
|
获得一个表示该网格中的列的对象的集合。如果这些列是自动生成的,则该集合总是空的。
|
|
DataKeyNames
|
获得一个包含当前显示项的主键字段的名称的数组。
|
|
DataKeys
|
获得一个表示在DataKeyNames中为当前显示的记录设置的主键字段的值。
|
|
EditIndex
|
获得和设置基于0的索引,标识当前以编辑模式生成的行。
|
|
FooterRow
|
返回一个表示页脚的GridViewRow对象。
|
|
HeaderRow
|
返回一个表示标题的GridViewRow对象。
|
|
PageCount
|
获得显示数据源的记录所需的页面数。
|
|
PageIndex
|
获得或设置基于0的索引,标识当前显示的数据页。
|
|
PageSize
|
指示在一个页面上要显示的记录数。
|
|
Rows
|
获得一个表示该控件中当前显示的数据行的GridViewRow对象集合。
|
|
SelectedDataKey
|
返回当前选中的记录的DataKey对象。
|
|
SelectedIndex
|
获得和设置标识当前选中行的基于0的索引。
|
|
SelectedRow
|
返回一个表示当前选中行的GridViewRow对象。
|
|
SelectedValue
|
返回DataKey对象中存储的键的显式值。类似于SelectedDataKey。
|
|
TopPagerRow
|
返回一个表示网格的顶部分页器的GridViewRow对象。
|
GridView旨在利用新的数据源对象模型,并在通过DataSourceID属性绑定到一个数据源控件时效果最佳。GridView还支持经典的DataSource属性,但是如果那样绑定数据,则其中一些特征(诸如内置的更新或分页)变得不可用。
2. GridView控件的事件
GridView控件没有不同于DataBind的方法。然而,如前所述,在很多情况下我们不需要调用GridView控件上的方法。当我们把GridView绑定到一个数据源控件时,数据绑定过程隐式地启动。
在ASP.NET 2.0中,很多控件,以及Page类本身,有很多对doing/done类型的事件。控件生命期内的关键操作通过一对事件进行封装:一个事件在该操作发生之前激发,一个事件在该操作完成后立即激发。GridView类也不例外。表10.11列出了GridView控件激发的事件。
表10.11 GridView控件激发的事件
|
事件
|
描述
|
|
PageIndexChanging,
PageIndexChanged
|
这两个事件都是在其中一个分页器按钮被单击时发生。它们分别在网格控件处理分页操作之前和之后激发。
|
|
RowCancelingEdit
|
在一个处于编辑模式的行的Cancel按钮被单击,但是在该行退出编辑模式之前发生。
|
|
RowCommand
|
单击一个按钮时发生。
|
|
RowCreated
|
创建一行时发生。
|
|
RowDataBound
|
一个数据行绑定到数据时发生。
|
|
RowDeleting, RowDeleted
|
这两个事件都是在一行的Delete按钮被单击时发生。它们分别在该网格控件删除该行之前和之后激发。
|
|
RowEditing
|
当一行的Edit按钮被单击时,但是在该控件进入编辑模式之前发生。
|
|
RowUpdating,
RowUpdated
|
这两个事件都是在一行的Update按钮被单击时发生。它们分别在该网格控件更新该行之前和之后激发。
|
|
SelectedIndexChanging,
SelectedIndexChanged
|
这两个事件都是在一行的Select按钮被单击时发生。它们分别在该网格控件处理选择操作之前和之后激发。
|
|
Sorting, Sorted
|
这两个事件都是在对一个列进行排序的超链接被单击时发生。它们分别在网格控件处理排序操作之前和之后激发。
|
RowCreated和RowDataBound事件与DataGrid的ItemCreated和ItemDataBound事件相同,只是换了个新名称。它们的行为完全与它们在ASP.NET 1.x中的一样。对于RowCommand事件也一样,它与DataGrid的ItemCommand事件一样。
可以使用宣布某种操作的事件,极大地增强了我们的编程能力。通过连接RowUpdating事件,可以交叉检查正在更新什么并对新值进行验证。同样,我们可能需要处理RowUpdating事件,用HTML对客户端提供的值进行编码,然后把它们持久地保存在底层数据存储中。这一简单技巧有助于防御脚本侵入。
3. 简单的数据绑定
如下代码片断说明了把数据绑定到一个GridView控件的最简单方法。数据源对象使该页面几乎不需要任何代码。
<asp:ObjectDataSource ID="MySource" runat="server"
TypeName="ProAspNet20.DAL.Customers"
SelectMethod="LoadAll">
</asp:ObjectDataSource>
<asp:GridView runat="server" id="grid" DataSourceID="MySource" />
设置DataSourceID属性触发数据绑定过程,它运行数据源查询,并填充该网格的用户界面。我们不需要编写任何绑定代码。(注意,我们仍然必须编写LoadAll方法和DAL。)
在默认情况下,GridView控件自动生成足够多的列,以包含来自数据源的所有数据。在其他情况下,我们可能需要单独控制和设计每一列。为此,要对绑定过程稍加提炼。
如果没有设置任何数据源属性,则GridView控件不会生成任何东西。如果绑定了一个空的数据源并且规定了EmptyDataTemplate模板,则向用户显示的结果有一个较友好的外观:
<asp:gridview runat="server" datasourceid="MySource">
<emptydatatemplate>
<asp:label runat="server">
There's no data to show in this view.
</asp:label>
</emptydatatemplate>
</asp:gridview>
如果该控件所绑定的数据源不空,则忽略EmptyDataTemplate属性。图10.2展示了空模板生成的输出。

0 && image.height>0){if(image.width>=510){this.width=510;this.height=image.height*510/image.width;}}" href="http://book.csdn.net/BookFiles/73/10/image005.jpg">
图10.2 绑定到一个空数据源的正在运行GridView控件
如果使用一个已声明的列集合,则网格的AutoGenerateColumns属性通常设置为false。然而,这不是一个严格的要求——网格可以声明的列和自动生成的列。在这种情况下,声明的列先显示。还要注意自动生成的列不是添加到Columns集合。因此,使用列自动生成时,Columns集合通常是空的。
1. 对列进行配置
Columns属性是一个DataControlField对象集合。DataControlField对象类似于DataGrid的DataGridColumn对象,但是它有一个更一般的名称,因为这些字段对象可以在其他不必生成列的数据绑定控件中重用。(例如,在DetailsView控件中,相同的类用来生成一行。)
我们既可以以声明的方式定义列,也可以以编程方式声明列。如果以编程的方式声明列,则只要实例化任何必需的数据字段对象,并把它们添加到Columns集合。如下代码把一个数据绑定的列添加到网格中:
BoundField field = new BoundField();
field.DataField = "companyname";
field.HeaderText = "Company Name";
grid.ColumnFields.Add(field);
各列数据按列字段在集合众出现的顺序进行显示。要在.aspx源文件中静态地声明列,则使用<Columns>标签,如下面所示:
<columns>
<asp:boundfield datafield="customerid" headertext="ID" />
<asp:boundfield datafield="companyname" headertext="Company Name" />
</columns>
表10.12列出GridView控件中使用列字段类。所有的类都继承DataControlField。
表10.12 GridView控件支持的列类型
|
类型
|
描述
|
|
BoundField
|
默认的列类型。作为纯文本显示一个字段的值。
|
|
ButtonField
|
作为命令按钮显示一个字段的值。我们可以选择链接按钮或按钮开关样式。
|
|
CheckBoxField
|
作为一个复选框显示一个字段的值。它通常用来生成布尔值。
|
|
CommandField
|
ButtonField的增强版本,表示一个特殊的命令,诸如Select、Delete、Insert或Update。该属性对GridView控件几乎每什么用;该字段是为DetailsView控件定制的。(GridView和DetailsView共享从DataControlField派生的类集。)
|
|
HyperLinkField
|
作为超链接显示一个字段的值。单击该超链接时,浏览器到航道指定的URL。
|
|
ImageField
|
作为一个<img> HTML标签的Src属性显示一个字段的值。绑定字段的内容应该是物理图象的URL。
|
|
TemplateField
|
为列中的每一项显示用户定义的内容。当我们需要创建一个定制的列字段时,则使用该列类型。模板可以包含任意多个数据字段,还可以结合文字、图像和其他控件。
|
表10.13列出了所有的列类型共享的主要属性。
表10.13 GridView列的公共属性
|
属性
|
描述
|
|
AccessibleHeaderText
|
表示Assistive Technology设备的屏幕阅读器读取的缩写文本的文本。
|
|
FooterStyle
|
获得该列的页脚的样式对象。
|
|
FooterText
|
获得和设置该列的页脚的文本。
|
|
HeaderImageUrl
|
获得和设置放在该列的标题中的图像的URL。
|
|
HeaderStyle
|
获得该列的标题的样式对象。
|
|
HeaderText
|
获得和设置该列的标题的文本。
|
|
InsertVisible
|
指示当它的父数据绑定控件处于插入模式时,该字段是否可见。该属性不适用于GridView控件。
|
|
ItemStyle
|
获得各列的单元的样式对象。
|
|
ShowHeader
|
指示是否生成该列的标题。
|
|
SortExpression
|
获得和设置该列的标题被单击时用来排序网格内容的表达式。通常,该字符串属性被设置为所绑定的数据字段的名称。
|
表10.13所列的属性代表每个列类型实际提供的属性的一个子集。特别是,每个列类型定义了一个定制的属性集,用以定义和配置所绑定的字段。有关GridView的列类型的编程接口的详情,请参考MSDN文档。
2. 绑定字段
BoundField类表示在一个数据绑定控件(诸如GridView或DetailsView)中作为纯文本显示的一个字段。为了规定要显示的字段,把DataField属性设置为该字段的名称。通过设置DataFormatString属性,可以应用一个定制的格式化字符串于所显示的值。如果NullDisplayText属性的值为null,则允许我们规定要显示的交替文本。最后,通过把ConvertEmptyStringToNull属性设置为true,强制该类把空字符串看作null值。
BoundField可以通过Visible属性以编程的方式隐藏起来,而ReadOnly属性防止所显示的值在编辑模式被修改。要在头部或页脚部分显示一个标题,请分别设置HeaderText和FooterText属性。我们还可以选择在头部显示一个图像,而不是文本,这时要设置HeaderImageUrl属性。
3. 按钮字段
按钮字段适合于把一个可单击的元素放入一个网格的列中。通常使用一个按钮字段触发针对当前行的一个操作。按钮字段表示我们希望通过一个服务器端事件处理的任何操作。当该按钮被单击时,页面回发并激发一个RowCommand事件。图10.3展示了一个示例。

0 && image.height>0){if(image.width>=510){this.width=510;this.height=image.height*510/image.width;}}" href="http://book.csdn.net/BookFiles/73/10/image006.jpg">
图10.3 GridView控件中的按钮字段
如下清单给出了上图所示网格的标记代码:
<asp:GridView ID="GridView1" runat="server" DataSourceID="SqlDataSource1"
AutoGenerateColumns="false" AllowPaging="true"
OnRowCommand="GridView1_RowCommand">
<HeaderStyle backcolor="gray" font-bold="true" height="200%" />
<PagerStyle backcolor="gray" font-bold="true" height="200%" />
<PagerSettings Mode="NextPreviousFirstLast" />
<Columns>
<asp:BoundField datafield="productname"
headertext="Product" />
<asp:BoundField datafield="quantityperunit"
headertext="Packaging" />
<asp:BoundField datafield="unitprice"
headertext="Price" DataFormatString="{0:c}">
<itemstyle width="80px" horizontalalign="right" />
</asp:BoundField>
<asp:ButtonField buttontype="Button" text="Add" CommandName="Add" />
</Columns>
</asp:GridView>
产品信息使用几个BoundField对象显示出来。该示例按钮列允许我们把产品添加到购物车中。当用户单击该按钮时,激发RowCommand服务器事件。在多个按钮列可用的情况下,CommandName属性允许我们推断出哪个按钮被单击了。我们赋给CommandName是代码隐藏类可以理解的任何惟一的字符串。下面给出了一个实例:
void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName.Equals("Add"))
{
// Get the index of the clicked row
int index = Convert.ToInt32(e.CommandArgument);
// Create a new shopping item and add it to the cart
AddToShoppingCart(index);
}
}
在该示例中,按钮列为所有的数据项显示一个固定文本。通过设置ButtonField类上的Text属性可以做到这一点。如果需要把按钮文本绑定到当前数据项上的一个特定字段,则把DataTextField属性设置为该字段的名称:
我们可以选择不同样式的按钮:按压式按钮、链接按钮或图像按钮。要以图像样式生成该按钮,则使用如下代码:
<asp:buttonfield buttontype="Image" CommandName="Add"
ImageUrl="/proaspnet20/images/cart.gif" />
要把一个ToolTip添加到该按钮(或图像)上,则需要处理RowCreated事件。(我将在本章后面详细介绍该事件。)
4. 超链接字段
超链接列把用户指向一个不同的URL,该URL可以有选择地在一个内部框架中显示出来。该链接的文本和URL可以从所绑定的数据源中获得。特别是,URL可以按以下两种方法之一进行设置:通过直接绑定到一个数据源字段,或通过使用一个硬编码的带有定制查询字符串的URL。如果URL存储在数据源的一个字段字段中,则选择直接绑定。在这种情况下,把DataNavigateUrlFields属性设置为该列的名称。然而,在某些情况下,要访问的URL与特定的应用程序有关,并不是存储在数据源中。在这种情况下,可以用一个硬编码的URL和查询字符串中的一个参数数组设置DataNavigateUrlFormatString属性:
<asp:HyperLinkField DataTextField="productname"
HeaderText="Product"
DataNavigateUrlFields="productid"
DataNavigateUrlFormatString="productinfo.aspx?id={0}"
Target="ProductView" />
当用户单击该按钮时,浏览器用productinfo.aspx?id=xxx URL的内容填充规定的框架窗口,其中xxx取自productid字段。该URL可以包含多个参数。要包含多个数据绑定值,只要把DataNavigateUrlFields属性设置为一个逗号隔开的字段名列表。该行为扩展了DataGrid的超链接列的行为,因为它支持多个参数。
超链接的文本也可以进行格式化。DataTextFormatString属性可以包含任何有效的标记,并使用{0}占位符保留数据绑定值的位置。(参见图10.4。)

0 && image.height>0){if(image.width>=510){this.width=510;this.height=image.height*510/image.width;}}" href="http://book.csdn.net/BookFiles/73/10/image007.jpg">
图10.4 GridView控件中的超链接字段
0 && image.height>0){if(image.width>=510){this.width=510;this.height=image.height*510/image.width;}}" href="http://book.csdn.net/BookFiles/73/10/image008.jpg"> 提示 为超链接的页面的选择一个目标时,还可以使用下面所列的任何一种标准目标:_self、_parent和_new。Microsoft Internet Explorer和Firefox都支持_search,它使用一个停靠在浏览器左端的配套Web面板。(参见图10.5。)
5. CheckBox字段
我们迄今所考虑的列类型对于经验丰富的ASP.NET 1.x开发人员来讲并不觉得新奇。虽然被重命名了,但是它们的总体行为仍然非常类似于DataGrids的类似列类型的行为。另一方面,CheckBoxField类型是在ASP.NET 2.0中是一个新类型,并且只适用于GridView和其他视图控件。在ASP.NET 1.x中获得一个复选框的最简单的方法是通过模板(一般是针对DataGrids)。
CheckBoxField列是显示一个复选框的一个较简单的绑定列。我们可以只把它绑定到一个包含布尔值的数据字段。有效的布尔值取自一个SQL Server表中的一个Bit类型(和其他数据库中的类似类型)的列,如果该控件绑定到一个定制集合,则取自一个bool类型的属性。特别是,如果把一个CheckBoxField列绑定到一个整数属性,则会得到一个异常,从而隐式地假设0为false,非0为true。
6. 图像字段
ImageField列类型表示一个在数据绑定控件中作为图像显示的字段。该单元包含一个<img>元素,因此底层的字段必须引用一个有效的URL。然而,我们可以任意组合URL。例如,我们可以使用DataImageUrlField执行直接绑定,其中该字段的内容填充<img>标签的Src属性。另外,我们可以使该列的单元指向一个外部页面(或者HTTP处理程序),从任何来源获取该图像的字节,并把它们下传给浏览器。如下代码说明了这种方法:

0 && image.height>0){if(image.width>=510){this.width=510;this.height=image.height*510/image.width;}}" href="http://book.csdn.net/BookFiles/73/10/image009.jpg">
图10.5 GridView控件中的CheckBbox字段
<Columns>
<asp:ImageField DataImageUrlField="employeeid"
DataImageUrlFormatString="showemployeepicture.aspx?id={0}"
DataAlternateTextField="lastname">
<ControlStyle Width="120px" />
</asp:ImageField>
<asp:TemplateField headertext="Employee">
<ItemStyle Width="220px" />
<ItemTemplate>
<b><%# Eval("titleofcourtesy") + " " +
Eval("lastname") + ", " +
Eval("firstname") %></b> <br />
<%# Eval("title")%>
<hr />
<i><%# Eval("notes")%></i>
</ItemTemplate>
</asp:templatefield>
</Columns>
ImageField列中的单元用下一个URL的输出进行填充:
ShowEmployeePicture.aspx?id=xxx
不用说,xxx是employeeid字段中与DataImageUrlField关联的值。有趣的是,替代文本也可以是数据绑定的。我们对替代文本使用DataAlternateTextField属性。图10.6给出了该特征的一个内部预览。图10.6中的页面利用一个模板列生成