演练:对绑定到 GridView Web 服务器控件的行执行批量更新
更新:2007 年 11 月
如果对 GridView 控件启用了编辑功能,默认情况下一次只能编辑一行。本演练展示了如何扩展 GridView 控件的功能,以便用户能修改多行然后通过单击一个按钮保存所有更改。本演练使用 SqlDataSource 控件从数据源中检索结果并管理更新。SqlDataSource 控件将作为 GridView 控件的数据源。
通过此演练,您将学会如何执行以下任务:
在 Microsoft Visual Web Developer 中连接到 SQL Server 数据库。
使用 SqlDataSource 控件管理数据访问。
在 GridView 控件中显示从数据库返回的数据。
配置 GridView 控件以使用户可以一次编辑多行。
系统必备
若要完成本演练,您需要:
Visual Web Developer (Visual Studio)。
Microsoft 数据访问组件 (MDAC) 2.7 版或更高版本。
如果使用的是 Microsoft Windows XP 或 Windows Server 2003,那么您已经有了 MDAC 2.7。但是,如果使用的是 Microsoft Windows 2000,您可能需要升级您计算机上已经安装的 MDAC。有关更多信息,请参见 MSDN Library 中的“Microsoft Data Access Components (MDAC) Installation”(Microsoft 数据访问组件 (MDAC) 安装)。
SQL Server Northwind 数据库的访问权限。如果需要 SQL Server Northwind 数据库的副本,请参见 SQL Server 2005 Books Online(《SQL Server 2005 联机丛书》)中的“Installing Sample Databases”(安装示例数据库)。
说明: 如果需要有关如何登录到运行 SQL Server 的计算机的信息,请与服务器管理员联系。
创建网站
如果您已经通过完成 演练:在 Visual Web Developer 中创建基本网页 在 Visual Web Developer 中创建了网站,则可以使用该网站,并转至下一部分。否则,按照下面的步骤创建一个新的网站和网页。
创建文件系统网站
打开 Visual Web Developer。
在**“文件”菜单上单击“新建”,然后单击“网站”。如果您使用的是 Visual Web Developer 速成版,则在“文件”菜单上单击“新建网站”**。
出现**“新建网站”**对话框。
在**“Visual Studio 已安装的模板”下单击“ASP.NET 网站”**。
在**“位置”列表中单击“文件系统”**,然后输入要保存网站网页的文件夹的名称。
例如,输入文件夹名称“C:\WebSites\BulkUpdate”。
在**“语言”**列表中,单击您想使用的编程语言。
单击**“确定”**。
Visual Web Developer 创建该文件夹和一个名为 Default.aspx 的新页。
为 GridView 控件添加数据源
若要在 ASP.NET 网页上显示数据,需要下列元素:
与数据源(如数据库)的连接。
在下面的过程中,您将创建一个到 SQL Server Northwind 数据库的连接。
该页上一个用于与数据源(数据库)进行交互以读写数据的数据源控件。
该页上的一个用于显示数据的控件。
在下面的过程中,您将通过 GridView 控件显示数据。GridView 控件将从 SqlDataSource 控件中获取其数据。
为 GridView 控件添加数据源
打开或切换到 Default.aspx 页。
切换到“设计”视图。
从工具箱的**“数据”**选项卡中将 SqlDataSource 控件拖到页面上。
如果**“SqlDataSource 任务”智能标记没有显示,请右击 SqlDataSource 控件,然后单击“显示智能标记”**。
在**“SqlDataSource 任务”面板中单击“配置数据源”**。
出现**“配置数据源”**向导。
单击**“新建连接”**。
即会出现**“添加连接”**对话框。
如果需要,请执行下列操作之一:您看到的具体用户界面取决于您之前在 Visual Web Developer 中创建的数据连接。
如果**“数据源”列表没有显示“Microsoft SQL Server (SqlClient)”,则单击“更改”,然后在“更改数据源”对话框中选择“Microsoft SQL Server”**。
如果出现的是**“选择数据源”对话框而不是“连接属性”对话框,则请在“数据源”列表中选择要使用的数据源类型。在此演练中,数据源的类型为“Microsoft SQL Server”。在“数据提供程序”列表中,单击“用于 SQL Server 的 .NET Framework 数据提供程序”,然后单击“继续”**。
在**“添加连接”页上的“服务器名”**文本框中,输入运行 SQL Server Northwind 数据库的计算机的名称。
在**“登录到服务器”**下,选择适当的选项以访问 SQL Server 数据库(集成安全性或特定 ID 与密码)。如果需要,则输入用户名和密码。
说明: 如果需要有关如何登录到运行 SQL Server 的计算机的信息,请与服务器管理员联系。
如果输入了密码,请选中**“保存密码”**复选框。
单击**“选择或输入一个数据库名”**,然后输入“Northwind”。
单击**“测试连接”,并在确定该连接生效后单击“确定”**。
在**“配置数据源”向导中单击“下一步”**。
确保选中了**“是,将此连接另存为”**复选框。
将连接命名为“NorthwindConnectionString”,然后单击**“下一步”**。
在**“配置 Select 语句”页中,选择“指定来自表或视图的列”**。
在**“名称”**列表中选择“Employees”。
在**“列”**下选择“EmployeeID”、“LastName”和“FirstName”。
单击**“高级”**。
选中**“生成 INSERT、UPDATE 和 DELETE 语句”复选框,然后单击“确定”**。
单击**“下一步”**。
单击**“完成”**。
添加显示数据的 GridView 控件
配置了用于管理数据的数据源控件之后,该页上还需要一个用于显示数据的控件。
在下面的过程中,您将通过 GridView 控件显示数据。GridView 控件将从先前添加的 SqlDataSource 控件中获取其数据。
若要使用户能一次编辑所有 GridView 控件的内容(而不是一次只编辑一行),必须自定义 GridView 控件。您将用可编辑的元素替换每一列中的默认显示元素,然后将它们绑定到数据源。为完成此操作,您将创建 TemplateField 列。在每个 TemplateField 列的 ItemTemplate 中,将添加一个绑定的 TextBox 控件,用户可以在该控件中编辑数据。
添加并配置用于显示数据的 GridView 控件
确保您位于 Default.aspx 页的“设计”视图中。
从工具箱的**“数据”选项卡中将一个“GridView”**控件拖到页面上。
在**“GridView 任务”面板的“选择数据源”**列表框中,选择之前添加的 SqlDataSource 控件“SqlDataSource1”。
选择**“启用分页”**。
单击**“编辑列”**。
出现**“字段”**对话框。
在**“选定的字段”下选择“FirstName”**。
单击**“将此字段转换为 TemplateField”**。
使用与先前转换“FirstName”字段相同的步骤,将“LastName”字段转换为模板字段。不要转换“EmployeeId”字段,因为该字段包含主键,因此是不可编辑的。
单击**“确定”**。
在**“GridView 任务”面板中单击“编辑模板”**。
在**“显示”列表中的“FirstName”下,单击“EditItemTemplate”**。
GridView 控件显示一个可编辑区域,且**“FirstName”**列的默认布局处于编辑模式。
右击 EditItemTemplate 中的 TextBox 控件,然后单击**“复制”**。
右击 GridView 控件,然后单击**“显示智能标记”**。
在**“显示”列表中的“FirstName”下,单击“ItemTemplate”**。
GridView 控件现在以显示模式显示**“FirstName”**列的默认布局。
删除现有的 Label 控件。
右击**“ItemTemplate”可编辑区域,然后单击“粘贴”**。
您已将 TextBox 控件(包括该控件的数据绑定配置)从 EditItemTemplate 布局复制到 ItemTemplate 布局。
选择 TextBox 控件,在“属性”窗口中,将**“(ID)”**属性设置为 FirstNameTextBox。这可确保您粘贴的 TextBox 控件与您复制的控件具有不同的 ID。
将**“MaxLength”**属性设置为 10(数据库中字段的最大长度)。
这可确保用户输入的信息不会超过为数据库中的“FirstName”字段所配置的字段容量。
重复前九步,但这次修改**“LastName”模板字段。用从“EditItemTemplate”**布局中复制的 TextBox 替换现有的 Label 控件,并将 ID 属性设置为“LastNameTextBox”。
对于 TextBox 控件的 MaxLength 属性,指定值 20。
右击 GridView 控件,然后单击**“结束模板编辑”**。
添加执行批量更新的过程
配置了用于显示可编辑数据的 GridView 控件之后,需要添加用于执行批量更新的代码。本节将执行以下任务:
添加 Button 控件,并在该控件的 Click 处理程序中添加代码,从而以批量形式更新对 GridView 控件的各行所做的更改。
添加用于存储原始数据值的 DataTable 对象。
添加用于确定行是否被修改的代码。将把 GridView 控件中所显示的当前值与存储在 DataTable 对象中的原始值进行比较。如果一个或多个所显示的值与原始值不匹配,则该行将在数据库中更新。否则,该行将不包括在批量更新中。
创建执行批量更新的过程
切换到“设计”视图。
在 RowDataBound 字段中键入“GridView1_RowDataBound”并按 Enter。
Visual Web Developer 将为 GridView 控件的 RowDataBound 事件创建事件处理程序。代码类似于下面的代码示例。
Protected Sub GridView1_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles GridView1.RowDataBound End Sub
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e) { }
用下面的代码(包括私有变量)替换生成的过程。
Private tableCopied As Boolean = False Private originalDataTable As System.Data.DataTable Protected Sub GridView1_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles GridView1.RowDataBound If e.Row.RowType = DataControlRowType.DataRow Then If Not tableCopied Then originalDataTable = CType(e.Row.DataItem, System.Data.DataRowView).Row.Table.Copy() ViewState("originalValuesDataTable") = originalDataTable tableCopied = True End If End If End Sub
private bool tableCopied = false; private DataTable originalDataTable; protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e) { if (e.Row.RowType == DataControlRowType.DataRow) if (!tableCopied) { originalDataTable = ((DataRowView)e.Row.DataItem).Row.Table.Copy(); ViewState["originalValuesDataTable"] = originalDataTable; tableCopied = true; } }
只要 GridView 控件执行数据绑定,便会运行此代码。在绑定第一行时,代码在 DataTable 对象中保存原始数据库值的副本,该对象又存储在 ViewState 中。
切换到“设计”视图。
从工具箱的**“标准”选项卡中,将一个“Button”**控件拖到页面上。
在“属性”窗口中单击属性按钮 () 以显示 Button 控件的属性。
在**“(ID)”**字段中输入“UpdateButton”。
在**“文本”**字段中,输入“更新”。
单击事件按钮 () 以显示 Button 控件的事件。
在**“单击”**字段中键入“UpdateButton_Click”并按 Enter。
Visual Web Developer 将为 Button 控件的 Click 事件创建事件处理程序。代码类似于下面的代码示例。
Protected Sub UpdateButton_Click(ByVal sender As Object, ByVal e As EventArgs) End Sub
protected void UpdateButton_Click(object sender, EventArgs e) { }
用下面的代码替换生成的过程。
Protected Sub UpdateButton_Click(ByVal sender As Object, ByVal e As EventArgs) originalDataTable = CType(ViewState("originalValuesDataTable"), System.Data.DataTable) For Each r As GridViewRow In GridView1.Rows If IsRowModified(r) Then GridView1.UpdateRow(r.RowIndex, False) Next ' Rebind the Grid to repopulate the original values table. tableCopied = False GridView1.DataBind() End Sub Protected Function IsRowModified(ByVal r As GridViewRow) As Boolean Dim currentID As Integer Dim currentLastName As String Dim currentFirstName As String currentID = Convert.ToInt32(GridView1.DataKeys(r.RowIndex).Value) currentLastName = CType(r.FindControl("LastNameTextBox"), TextBox).Text currentFirstName = CType(r.FindControl("FirstNameTextBox"), TextBox).Text Dim row As System.Data.DataRow = _ originalDataTable.Select(String.Format("EmployeeID = {0}", currentID))(0) If Not currentLastName.Equals(row("LastName").ToString()) Then Return True If Not currentFirstName.Equals(row("FirstName").ToString()) Then Return True Return False End Function
protected void UpdateButton_Click(object sender, EventArgs e) { originalDataTable = (DataTable)ViewState["originalValuesDataTable"]; foreach (GridViewRow r in GridView1.Rows) if (IsRowModified(r)) { GridView1.UpdateRow(r.RowIndex, false); } // Rebind the Grid to repopulate the original values table. tableCopied = false; GridView1.DataBind(); } protected bool IsRowModified(GridViewRow r) { int currentID; string currentLastName; string currentFirstName; currentID = Convert.ToInt32(GridView1.DataKeys[r.RowIndex].Value); currentLastName = ((TextBox)r.FindControl("LastNameTextBox")).Text; currentFirstName = ((TextBox)r.FindControl("FirstNameTextBox")).Text; DataRow row = originalDataTable.Select(String.Format("EmployeeID = {0}", currentID))[0]; if (!currentLastName.Equals(row["LastName"].ToString())) { return true; } if (!currentFirstName.Equals(row["FirstName"].ToString())) { return true; } return false; }
说明: 此过程使用每个可编辑的 TextBox 控件中的值与缓存的 DataTable 对象中所存储的值执行字符串比较。如果对 TextBox 控件中的文本进行了格式设置,那么其值可能相同,但其字符串表示形式会不匹配。例如,如果将 DateTime 值的格式设置为短日期格式 ({0:d}),则日期 TextBox 控件中的值可能为 3/2/2005。而 DataTable 对象中日期值的字符串表示形式为 3/2/2005 12:00 AM。在这些情况下,必须添加比较逻辑,将格式和本地化设置考虑在内。
此过程循环访问 GridView 控件的每一行,并对每一行调用自定义 IsRowModified 函数。该函数将当前行与 DataTable 对象中相应的行进行比较,且如果该行发生了更改则返回 true。对于发生更改的任意行,按钮的 Click 处理程序中的代码将调用 GridView 控件的 UpdateRow 方法。
测试页面
现在可以运行页面以测试代码。
测试页面
按 Ctrl+F5 运行该页。
该页显示在浏览器中。GridView 控件将以可编辑数据页的形式显示 Northwind Employees 表中的数据行。
修改某些值。
单击**“更新”**。
修改的行将在数据库中进行更新。
关闭浏览器。
后续步骤
本演练阐述了如何扩展 GridView 控件的功能,从而能够更新 ASP.NET 网页上的多个数据行。您可能还希望扩展应用程序的功能,使用户可以使用 DetailsView 或 FormView 控件添加新的数据行。您还可以使用户使用除 TextBox 控件之外的控件来编辑值,如 DropDownList 控件。有关更多信息,请参见下列主题: