可编辑的嵌套 GridView(一体化)






4.86/5 (111投票s)
如何在 ASP.NET 中使用 C# 创建一个一体化的可编辑嵌套 GridView。
引言
本文解释了如何创建一个 ASP.NET 可编辑嵌套 GridView。在这里,我将解释如何为 GridView 提供编辑/添加/删除/更新/分页/排序的所有功能,并且不仅仅是一个 GridView,我还将解释如何将这些功能扩展到嵌套的 Grid (GridView 中套 GridView)。我提供了功能齐全的源代码,它们是自解释的。
背景
我之前的文章解释了嵌套可编辑 DataGrids 的功能。本文提供了 GridView (Visual Studio 2005, .NET 2.0) 中的所有这些功能。通过 GridView 和 DataSource 控件的组合,创建可编辑的 GridView 非常容易。
Using the Code
这是一个名为 EditNestedGridView 的虚拟目录的 Web 应用程序。您可以创建相同的虚拟目录来运行此应用程序,或者创建任何其他虚拟目录并映射到此目录的路径,以便从浏览器访问它。由于我使用的是 Access 2003 作为我的数据库,因此您需要在计算机上安装 Microsoft Access。我修改并使用了 NorthWind 数据库。我已将其包含在名为 App_Data 文件夹的代码包中。我使用 C# 进行代码隐藏文件。在 Visual Studio 2005 中,选择 File --> Open --> Web Site,然后导航到 EditNestedGridView 文件夹。
分步过程
随附的代码是自解释的,但我会尽量详细解释。
- 由于我将使用
DataSource
控件,因此我们首先创建一个AccessDataSource
控件,如下所示: - 现在,让我们创建一个简单的
GridView
控件,并将其连接到先前创建的DataSource
控件,如下所示: - 到目前为止,我们已经创建了一个父
GridView
。现在我们将把这些功能也扩展到子GridView
。 - 为了绑定子
GridView
,我们不能像用于父GridView
那样使用静态DataSource
控件。我们将不得不根据相应父行的客户 ID 动态准备查询,这可以在父 Grid 的RowDataBound
事件中完成,如下所示:protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e) { GridViewRow row = e.Row; string strSort = string.Empty; // Make sure we aren't in header/footer rows if (row.DataItem == null) { return; } //Find Child GridView control GridView gv = new GridView(); gv = (GridView)row.FindControl("GridView2"); //Prepare the query for Child GridView by passing //the Customer ID of the parent row gv.DataSource = ChildDataSource(((DataRowView)e.Row.DataItem)["CustomerID"].ToString(), strSort); gv.DataBind(); }
在这里,
ChildDataSource
函数使用传递的客户 ID 构建查询并返回AccessDataSource
。 - 现在,我们也有了子 Grid 中的数据,并且可以动态展开和折叠。让我们像对待父 Grid 一样逐个添加效果。但是,在进一步操作之前,有一个棘手的部分。对于父 Grid,只有一个唯一的 ID (
GridView1
),而对于子 Grid,将有多个在运行时生成的唯一 ID。如果我们能识别出我们需要的那个,就可以解决这个问题。在父 Grid 的情况下,分页和排序由
DataSource
控件处理。对于子 Grid,我们必须手动处理它,使用相应的事件PageIndexChanging
和Sorting
。分页事件的示例代码如下:protected void GridView2_PageIndexChanging(object sender, GridViewPageEventArgs e) { GridView gvTemp = (GridView)sender; gvUniqueID = gvTemp.UniqueID; gvNewPageIndex = e.NewPageIndex; GridView1.DataBind(); }
在这里,我们识别了需要分页的子 Grid 的运行时唯一 ID 以及新页码。我们将在父 Grid 的
RowDataBound
事件中使用这些变量值,如下所示:protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e) { ........................ //Find Child GridView control GridView gv = new GridView(); gv = (GridView)row.FindControl("GridView2"); //Check if any additional conditions (Paging, Sorting, Editing, etc) //to be applied on child GridView if (gv.UniqueID == gvUniqueID) { gv.PageIndex = gvNewPageIndex; gv.EditIndex = gvEditIndex; //Check if Sorting used if (gvSortExpr != string.Empty) { GetSortDirection(); strSort = " ORDER BY " + string.Format("{0} {1}", gvSortExpr, gvSortDir); } //Expand the Child grid ClientScript.RegisterStartupScript(GetType(), "Expand", "<script language="javascript"></script>"); } .......................... }
<asp:AccessDataSource ID="AccessDataSource1" runat="server"
DataFile="App_Data/Northwind.mdb"
SelectCommand="SELECT [Customers].[CustomerID],
[Customers].[CompanyName],[Customers].[ContactName],
[Customers].[ContactTitle],[Customers].[Address] FROM [Customers]
ORDER BY [Customers].[CustomerID]"></asp:AccessDataSource>
DataSource
控件的主要优势在于,它简化了检索和绑定数据,甚至进行排序、分页或编辑数据所需的自定义代码量。
<asp:GridView ID="GridView1" AllowPaging="True" BackColor="#f1f1f1"
AutoGenerateColumns=false DataSourceID="AccessDataSource1"
DataKeyNames="CustomerID"
style="Z-INDEX: 101; LEFT: 8px; POSITION: absolute; TOP: 32px"
ShowFooter=true Font-Size=Small
Font-Names="Verdana" runat="server" GridLines=None BorderStyle=Outset>
GridView
非常类似于 DataGrid
,它拥有 DataGrid
的所有列功能,例如 TemplateColumn
、BoundColumn
,用于将数据作为列填充。EditItemTemplate
和 FooterTemplate
可用于编辑和添加目的。以下代码显示了父 Grid 的列:
<asp:TemplateField HeaderText="Customer ID" SortExpression="CustomerID">
<ItemTemplate>
<asp:Label ID="lblCustomerID" Text='<%# Eval("CustomerID") %>'
runat="server"></asp:Label>
</ItemTemplate>
<EditItemTemplate>
<asp:Label ID="lblCustomerID" Text='<%# Eval("CustomerID") %>'
runat="server"></asp:Label>
</EditItemTemplate>
<FooterTemplate>
<asp:TextBox ID="txtCustomerID" Text='' runat="server"></asp:TextBox>
</FooterTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Company Name" SortExpression="CompanyName">
<ItemTemplate><%# Eval("CompanyName") %></ItemTemplate>
<EditItemTemplate>
<asp:TextBox ID="txtCompanyName" Text='<%# Eval("CompanyName") %>'
runat="server"></asp:TextBox>
</EditItemTemplate>
<FooterTemplate>
<asp:TextBox ID="txtCompanyName" Text='' runat="server"></asp:TextBox>
</FooterTemplate>
</asp:TemplateField>
..........................
..........................
<asp:CommandField HeaderText="Edit" ShowEditButton="True" />
<asp:TemplateField HeaderText="Delete">
<ItemTemplate>
<asp:LinkButton ID="linkDeleteCust" CommandName="Delete"
runat="server">Delete</asp:LinkButton>
</ItemTemplate>
<FooterTemplate>
<asp:LinkButton ID="linkAddCust" CommandName="AddCustomer"
runat="server">Add</asp:LinkButton>
</FooterTemplate>
</asp:TemplateField>
现在我们已经有了所有的列,我们需要事件处理程序来处理添加/编辑/删除操作。处理这些事件比处理 DataGrid
的事件要简单得多。DataSource
控件负责分页和排序操作。这是包含所有这些事件的最终父 GridView
控件:
<asp:GridView ID="GridView1" AllowPaging="True" BackColor="#f1f1f1"
AutoGenerateColumns=false DataSourceID="AccessDataSource1"
DataKeyNames="CustomerID"
style="Z-INDEX: 101; LEFT: 8px; POSITION: absolute; TOP: 32px"
ShowFooter=true Font-Size=Small
Font-Names="Verdana" runat="server" GridLines=None
OnRowDataBound="GridView1_RowDataBound"
OnRowCommand = "GridView1_RowCommand"
OnRowUpdating = "GridView1_RowUpdating" BorderStyle=Outset
OnRowDeleting = "GridView1_RowDeleting"
OnRowDeleted = "GridView1_RowDeleted"
OnRowUpdated = "GridView1_RowUpdated" AllowSorting=true>
有了以上所有选项,GridView
的外观如下:
在添加另一个 GridView
之前,我们必须了解 GridView
如何将其内容作为 HTML 标签发出。对于 Internet Explorer 浏览器,GridView
就像一个普通的 Table
,带有 TR
和 TD
标签。因此,如果我们能操纵父 GridView
来强制关闭一个行并将其子 GridView
作为另一行发出,我们就完成了。
显示的是一些 HTML 表格单元格和行标签,它们有效地拦截了 GridView
当前将生成的输出,并用我们自己的特殊实现替换。也就是说,我们在表格绘制时告诉表格关闭当前单元格、当前行,然后添加一个带有单个空白列(用于间距)的新行,以及另一个跨越所有列的列,我们将使用它来显示第二个 GridView
。以下是解释此代码片段:
<asp:TemplateField>
<ItemTemplate>
<tr>
<td colspan="100%">
<div id="div<%# Eval("CustomerID") %>"
style="display:none;position:relative;left:15px;OVERFLOW: auto;WIDTH:97%" >
在这里,我创建了一个 ID 为 div Eval("CustomerID")
的 div,其 ID 为 Customer (父行),它保存子 GridView
,以便我们可以使用 DIV
ID 动态地隐藏和展开它。此外,我们需要主 GridView
中的一列来保存用于展开和折叠子 GridView
的图像,如下所示:
<asp:TemplateField>
<ItemTemplate>
<a href="javascript:expandcollapse('div<%# Eval("CustomerID") %>', 'one');">
在这里,JavaScript 函数 expandcollapse
将负责展开和折叠操作。
其余操作 (排序/编辑/更新/删除) 也可以类似分页的方式处理。请参阅上面附加的源代码。
结论
GridView
比 DataGrid
拥有更多的功能,这使得编码更加容易,而且我们可以在中间包含 HTML 标签以获得更大的灵活性。