GridView嵌套GridView
GridView嵌套可以显示当前选定的父记录组织同时显示所有子记录。例如,你可以用它创建一个完整的按类别组织的产品列表。下一个示例演示如何在单个网格中显示一个完整的分组产品列表,如下图所示:
![](https://images.cnblogs.com/cnblogs_com/zjz008/DetailsSingleTable.jpg)
使用的基本技术是为附表创建一个GridView,它的每行又嵌入一个GridView,这些子GridView使用TemplateField来插入到父GridView中。唯一需要注意的是,不能在绑定父GridView的同时绑定子GridView,因为此时父行还没有被创建。相反,需要等待父GridView的DataBound时间发生。
在这个示例中父GridView定义了两个列,它们都是TemplateField类型。第一个列组合了类别名称和类型
第二个列包含嵌入的产品的GridView,它有两个绑定列。下面是略去相关样式特性后简要的代码:
注意第二个GridView的标记并没有设置DataSourceID属性。那是因为当父网格被绑定到它的数据源时,这些网格的数据源都通过编程来提供。
现在创建两个数据源,一个用于获取产品类别,另一个用于获取特定类别的产品。第一个查询填充父GridView:
可以把第一个网格直接绑定到数据源:
这段代码非常典型,奥妙在于如何绑定子GridView。第二个数据源包含被多次调用以填充于GridView的查询。每次它获取不同类别中的产品。CategoryID作为一个参数被提供:
为了绑定子GridView,必须相应GridView.RowDataBound事件,它在每次行生成并绑定到父GridView时产生。此时,可以从第二列获取子GridView。并通过编程调用数据源的Select()方法把它绑定到产品信息。为了确保只显示当前类别的产品,还必须获取当前项的CategoryID字段并把它作为参数传递。代码如下:
![](https://images.cnblogs.com/cnblogs_com/zjz008/DetailsSingleTable.jpg)
使用的基本技术是为附表创建一个GridView,它的每行又嵌入一个GridView,这些子GridView使用TemplateField来插入到父GridView中。唯一需要注意的是,不能在绑定父GridView的同时绑定子GridView,因为此时父行还没有被创建。相反,需要等待父GridView的DataBound时间发生。
在这个示例中父GridView定义了两个列,它们都是TemplateField类型。第一个列组合了类别名称和类型
<asp:TemplateField HeaderText="Category">
<ItemStyle VerticalAlign="Top" Width="20%"></ItemStyle>
<ItemTemplate>
<br>
<b>
<%# Eval("CategoryName") %>
</b>
<br>
<br>
<%# Eval("Description" ) %>
<br>
</ItemTemplate>
</asp:TemplateField>
<ItemStyle VerticalAlign="Top" Width="20%"></ItemStyle>
<ItemTemplate>
<br>
<b>
<%# Eval("CategoryName") %>
</b>
<br>
<br>
<%# Eval("Description" ) %>
<br>
</ItemTemplate>
</asp:TemplateField>
第二个列包含嵌入的产品的GridView,它有两个绑定列。下面是略去相关样式特性后简要的代码:
<asp:TemplateField HeaderText="Products">
<ItemStyle VerticalAlign="Top"></ItemStyle>
<ItemTemplate>
<asp:GridView id="gridChild" runat="server" Font-Size="XX-Small" BackColor="White" AutoGenerateColumns="False"
CellPadding="4" BorderColor="#CC9966" BorderWidth="1px" Width="100%" BorderStyle="None">
<RowStyle ForeColor="#330099" BackColor="White"></RowStyle>
<HeaderStyle Font-Bold="True" ForeColor="#FFFFCC" BackColor="#990000"></HeaderStyle>
<Columns>
<asp:BoundField DataField="ProductName" HeaderText="Product Name">
<ItemStyle Width="250px" />
</asp:BoundField>
<asp:BoundField DataField="UnitPrice" HeaderText="Unit Price" DataFormatString="{0:C}" />
</Columns>
</asp:GridView>
</ItemTemplate>
</asp:TemplateField>
<ItemStyle VerticalAlign="Top"></ItemStyle>
<ItemTemplate>
<asp:GridView id="gridChild" runat="server" Font-Size="XX-Small" BackColor="White" AutoGenerateColumns="False"
CellPadding="4" BorderColor="#CC9966" BorderWidth="1px" Width="100%" BorderStyle="None">
<RowStyle ForeColor="#330099" BackColor="White"></RowStyle>
<HeaderStyle Font-Bold="True" ForeColor="#FFFFCC" BackColor="#990000"></HeaderStyle>
<Columns>
<asp:BoundField DataField="ProductName" HeaderText="Product Name">
<ItemStyle Width="250px" />
</asp:BoundField>
<asp:BoundField DataField="UnitPrice" HeaderText="Unit Price" DataFormatString="{0:C}" />
</Columns>
</asp:GridView>
</ItemTemplate>
</asp:TemplateField>
注意第二个GridView的标记并没有设置DataSourceID属性。那是因为当父网格被绑定到它的数据源时,这些网格的数据源都通过编程来提供。
现在创建两个数据源,一个用于获取产品类别,另一个用于获取特定类别的产品。第一个查询填充父GridView:
<asp:SqlDataSource ID="sourceCategories" runat="server" ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>"
ProviderName="System.Data.SqlClient" SelectCommand="SELECT * FROM Categories"></asp:SqlDataSource>
ProviderName="System.Data.SqlClient" SelectCommand="SELECT * FROM Categories"></asp:SqlDataSource>
可以把第一个网格直接绑定到数据源:
<asp:GridView id="gridMaster" runat="server" GridLines="None" BorderWidth="1px" BorderColor="Tan"
Font-Names="Verdana" CellPadding="2" AutoGenerateColumns="False" BackColor="LightGoldenrodYellow"
ForeColor="Black" DataKeyNames="CategoryID" Font-Size="X-Small" DataSourceID="sourceCategories" OnRowDataBound="gridMaster_RowDataBound">
Font-Names="Verdana" CellPadding="2" AutoGenerateColumns="False" BackColor="LightGoldenrodYellow"
ForeColor="Black" DataKeyNames="CategoryID" Font-Size="X-Small" DataSourceID="sourceCategories" OnRowDataBound="gridMaster_RowDataBound">
这段代码非常典型,奥妙在于如何绑定子GridView。第二个数据源包含被多次调用以填充于GridView的查询。每次它获取不同类别中的产品。CategoryID作为一个参数被提供:
<asp:SqlDataSource ID="sourceProducts" runat="server" ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>"
ProviderName="System.Data.SqlClient" SelectCommand="SELECT * FROM Products WHERE CategoryID=@CategoryID">
<SelectParameters>
<asp:Parameter Name="CategoryID" Type="Int32" />
</SelectParameters>
</asp:SqlDataSource>
ProviderName="System.Data.SqlClient" SelectCommand="SELECT * FROM Products WHERE CategoryID=@CategoryID">
<SelectParameters>
<asp:Parameter Name="CategoryID" Type="Int32" />
</SelectParameters>
</asp:SqlDataSource>
为了绑定子GridView,必须相应GridView.RowDataBound事件,它在每次行生成并绑定到父GridView时产生。此时,可以从第二列获取子GridView。并通过编程调用数据源的Select()方法把它绑定到产品信息。为了确保只显示当前类别的产品,还必须获取当前项的CategoryID字段并把它作为参数传递。代码如下:
protected void gridMaster_RowDataBound(object sender, GridViewRowEventArgs e)
{
// Look for GridView items.
if (e.Row.RowType == DataControlRowType.DataRow)
{
// Retrieve the GridView control in the second column.
GridView gridChild = (GridView)e.Row.Cells[1].Controls[1];
sourceProducts.SelectParameters[0].DefaultValue = gridMaster.DataKeys[e.Row.DataItemIndex].Value.ToString();
object data = sourceProducts.Select(DataSourceSelectArguments.Empty);
// Bind the grid.
gridChild.DataSource = data;
gridChild.DataBind();
}
}
{
// Look for GridView items.
if (e.Row.RowType == DataControlRowType.DataRow)
{
// Retrieve the GridView control in the second column.
GridView gridChild = (GridView)e.Row.Cells[1].Controls[1];
sourceProducts.SelectParameters[0].DefaultValue = gridMaster.DataKeys[e.Row.DataItemIndex].Value.ToString();
object data = sourceProducts.Select(DataSourceSelectArguments.Empty);
// Bind the grid.
gridChild.DataSource = data;
gridChild.DataBind();
}
}