In this article I will explain how to develop a multilevel nested GridView i.e. GridView with inner GridView and the inner GridView with another child GridView, thus creating a multilevel hierarchy of GridViews.
	
		For this example I making of Three (3) Levels of GridView.
	
	
		 
	
		Database
	
		I’ll make use of Customers, Orders and Products Table of Microsoft’s Northwind Database which you can easily download and install using the link provided below
	
	
		 
	
		HTML Markup
	
		The HTML Markup contains a simple ASP.Net GridView with a child ASP.Net GridView of Orders consisting of another Child GridView of Products in the ItemTemplate of TemplateField of ASP.Net GridViews. 
	
		
			Note: I am storing Customer ID and Order Id in the DataKeys property of the GridView as that will be required to populate the Child or Nested GridView of Orders as well as Products
	 
	
		 
	
		
			<asp:GridView ID="gvCustomers" runat="server" AutoGenerateColumns="false" CssClass="Grid"
		
			    DataKeyNames="CustomerID">
		
			    <Columns>
		
			        <asp:TemplateField>
		
			            <ItemTemplate>
		
			                <asp:ImageButton ID="imgOrdersShow" runat="server" OnClick="Show_Hide_OrdersGrid" ImageUrl="~/images/plus.png"
		
			                    CommandArgument="Show" />
		
			                <asp:Panel ID="pnlOrders" runat="server" Visible="false" Style="position: relative">
		
			                    <asp:GridView ID="gvOrders" runat="server" AutoGenerateColumns="false" PageSize="5"
		
			                        AllowPaging="true" OnPageIndexChanging="OnOrdersGrid_PageIndexChanging" CssClass="ChildGrid"
		
			                        DataKeyNames="OrderId">
		
			                        <Columns>
		
			                            <asp:TemplateField>
		
			                                <ItemTemplate>
		
			                                    <asp:ImageButton ID="imgProductsShow" runat="server" OnClick="Show_Hide_ProductsGrid" ImageUrl="~/images/plus.png"
		
			                                        CommandArgument="Show" />
		
			                                    <asp:Panel ID="pnlProducts" runat="server" Visible="false" Style="position: relative">
		
			                                        <asp:GridView ID="gvProducts" runat="server" AutoGenerateColumns="false" PageSize="2"
		
			                                            AllowPaging="true" OnPageIndexChanging="OnProductsGrid_PageIndexChanging" CssClass="Nested_ChildGrid">
		
			                                            <Columns>
		
			                                                <asp:BoundField ItemStyle-Width="150px" DataField="ProductId" HeaderText="Product Id" />
		
			                                                <asp:BoundField ItemStyle-Width="150px" DataField="ProductName" HeaderText="Product Name" />
		
			                                            </Columns>
		
			                                        </asp:GridView>
		
			                                    </asp:Panel>
		
			                                </ItemTemplate>
		
			                            </asp:TemplateField>
		
			                            <asp:BoundField ItemStyle-Width="150px" DataField="OrderId" HeaderText="Order Id" />
		
			                            <asp:BoundField ItemStyle-Width="150px" DataField="OrderDate" HeaderText="Date" />
		
			                        </Columns>
		
			                    </asp:GridView>
		
			                </asp:Panel>
		
			            </ItemTemplate>
		
			        </asp:TemplateField>
		
			        <asp:BoundField ItemStyle-Width="150px" DataField="ContactName" HeaderText="Contact Name" />
		
			        <asp:BoundField ItemStyle-Width="150px" DataField="City" HeaderText="City" />
		
			    </Columns>
		
			</asp:GridView>
	 
	
		 
	
		 
	
		Namespaces
	
		You will need to import the following namespaces
	
		C#
	
		
			using System.Data;
		
			using System.Data.SqlClient;
		
			using System.Configuration;
	 
	
		 
	
		VB.Net
	
		
			Imports System.Data
		
			Imports System.Data.SqlClient
		
			Imports System.Configuration
	 
	
		 
	
		 
	
		Binding the Customers records to the Level 1 GridView
	
		Below is the code to bind the parent Level 1 ASP.Net GridView with the records of Customers table from the Northwind Database.
	
		C#
	
		
			protected void Page_Load(object sender, EventArgs e)
		
			{
		
			    if (!IsPostBack)
		
			    {
		
			        gvCustomers.DataSource = GetData("select top 10 * from Customers");
		
			        gvCustomers.DataBind();
		
			    }
		
			}
		
			 
		
			private static DataTable GetData(string query)
		
			{
		
			    string constr = ConfigurationManager.ConnectionStrings["constr"].ConnectionString;
		
			    using (SqlConnection con = new SqlConnection(constr))
		
			    {
		
			        using (SqlCommand cmd = new SqlCommand())
		
			        {
		
			            cmd.CommandText = query;
		
			            using (SqlDataAdapter sda = new SqlDataAdapter())
		
			            {
		
			                cmd.Connection = con;
		
			                sda.SelectCommand = cmd;
		
			                using (DataSet ds = new DataSet())
		
			                {
		
			                    DataTable dt = new DataTable();
		
			                    sda.Fill(dt);
		
			                    return dt;
		
			                }
		
			            }
		
			        }
		
			    }
		
			}
	 
	
		 
	
		VB.Net
	
		
			Protected Sub Page_Load(sender As Object, e As EventArgs) Handles Me.Load
		
			    If Not IsPostBack Then
		
			        gvCustomers.DataSource = GetData("select top 10 * from Customers")
		
			        gvCustomers.DataBind()
		
			    End If
		
			End Sub
		
			 
		
			Private Shared Function GetData(query As String) As DataTable
		
			    Dim constr As String = ConfigurationManager.ConnectionStrings("constr").ConnectionString
		
			    Using con As New SqlConnection(constr)
		
			        Using cmd As New SqlCommand()
		
			            cmd.CommandText = query
		
			            Using sda As New SqlDataAdapter()
		
			                cmd.Connection = con
		
			                sda.SelectCommand = cmd
		
			                Using ds As New DataSet()
		
			                    Dim dt As New DataTable()
		
			                    sda.Fill(dt)
		
			                    Return dt
		
			                End Using
		
			            End Using
		
			        End Using
		
			    End Using
		
			End Function
	 
	
		 
	
		 
	
		Displaying the Child (Level 2) GridView with the Orders for each Customer in the Parent (Level 1) GridView
	
		On the Click event of the Expand ImageButton of the Parent GridView, I am first searching the Child GridView in the corresponding GridView Row and then populating it with the records from the Orders table of the Northwind Database based on Customer Id stored in the DataKey property for the row to which the ImageButton belongs.
	
		I have made use of the CommandArgument property of the ImageButton to determine whether the operation is of Expand or Collapse
	
		Also I have implemented Paging for the Child GridView using the OnOrdersGrid_PageIndexChanging event
	
		Note:  GetData is a generic function and the same function discussed above is used here.
	
		C#
	
		
			protected void Show_Hide_OrdersGrid(object sender, EventArgs e)
		
			{
		
			    ImageButton imgShowHide = (sender as ImageButton);
		
			    GridViewRow row = (imgShowHide.NamingContainer as GridViewRow);
		
			    if (imgShowHide.CommandArgument == "Show")
		
			    {
		
			        row.FindControl("pnlOrders").Visible = true;
		
			        imgShowHide.CommandArgument = "Hide";
		
			        imgShowHide.ImageUrl = "~/images/minus.png";
		
			        string customerId = gvCustomers.DataKeys[row.RowIndex].Value.ToString();
		
			        GridView gvOrders = row.FindControl("gvOrders") as GridView;
		
			        BindOrders(customerId, gvOrders);
		
			    }
		
			    else
		
			    {
		
			        row.FindControl("pnlOrders").Visible = false;
		
			        imgShowHide.CommandArgument = "Show";
		
			        imgShowHide.ImageUrl = "~/images/plus.png";
		
			    }
		
			}
		
			 
		
			private void BindOrders(string customerId, GridView gvOrders)
		
			{
		
			    gvOrders.ToolTip = customerId;
		
			    gvOrders.DataSource = GetData(string.Format("select * from Orders where CustomerId='{0}'", customerId));
		
			    gvOrders.DataBind();
		
			}
		
			 
		
			protected void OnOrdersGrid_PageIndexChanging(object sender, GridViewPageEventArgs e)
		
			{
		
			    GridView gvOrders = (sender as GridView);
		
			    gvOrders.PageIndex = e.NewPageIndex;
		
			    BindOrders(gvOrders.ToolTip, gvOrders);
		
			}
	 
	
		 
	
		VB.Net
	
		
			Protected Sub Show_Hide_OrdersGrid(sender As Object, e As EventArgs)
		
			    Dim imgShowHide As ImageButton = TryCast(sender, ImageButton)
		
			    Dim row As GridViewRow = TryCast(imgShowHide.NamingContainer, GridViewRow)
		
			    If imgShowHide.CommandArgument = "Show" Then
		
			        row.FindControl("pnlOrders").Visible = True
		
			        imgShowHide.CommandArgument = "Hide"
		
			        imgShowHide.ImageUrl = "~/images/minus.png"
		
			        Dim customerId As String = gvCustomers.DataKeys(row.RowIndex).Value.ToString()
		
			        Dim gvOrders As GridView = TryCast(row.FindControl("gvOrders"), GridView)
		
			        BindOrders(customerId, gvOrders)
		
			    Else
		
			        row.FindControl("pnlOrders").Visible = False
		
			        imgShowHide.CommandArgument = "Show"
		
			        imgShowHide.ImageUrl = "~/images/plus.png"
		
			    End If
		
			End Sub
		
			 
		
			Private Sub BindOrders(customerId As String, gvOrders As GridView)
		
			    gvOrders.ToolTip = customerId
		
			    gvOrders.DataSource = GetData(String.Format("select * from Orders where CustomerId='{0}'", customerId))
		
			    gvOrders.DataBind()
		
			End Sub
		
			 
		
			Protected Sub OnOrdersGrid_PageIndexChanging(sender As Object, e As GridViewPageEventArgs)
		
			    Dim gvOrders As GridView = TryCast(sender, GridView)
		
			    gvOrders.PageIndex = e.NewPageIndex
		
			    BindOrders(gvOrders.ToolTip, gvOrders)
		
			End Sub
	 
	
		 
	
		 
	
		Displaying the Child (Level 3) GridView with the Products for each Order placed by a Customer in the Products Grid (Level 3) GridView
	
		On the Click event of the Expand ImageButton of the Orders GridView, I am first searching the Products GridView in the corresponding GridView Row and then populating it with the records from the Products table of the Northwind Database based on Order Id stored in the DataKey property for the row to which the ImageButton belongs.
	
		Same as above, I have made use of the CommandArgument property of the ImageButton to determine whether the operation is of Expand or Collapse
	
		Also as above I have implemented Paging for the Products GridView using the OnProductsGrid_PageIndexChanging event
	
		C#
	
		
			protected void Show_Hide_ProductsGrid(object sender, EventArgs e)
		
			{
		
			    ImageButton imgShowHide = (sender as ImageButton);
		
			    GridViewRow row = (imgShowHide.NamingContainer as GridViewRow);
		
			    if (imgShowHide.CommandArgument == "Show")
		
			    {
		
			        row.FindControl("pnlProducts").Visible = true;
		
			        imgShowHide.CommandArgument = "Hide";
		
			        imgShowHide.ImageUrl = "~/images/minus.png";
		
			        int orderId = Convert.ToInt32( (row.NamingContainer as GridView).DataKeys[row.RowIndex].Value);
		
			        GridView gvProducts = row.FindControl("gvProducts") as GridView;
		
			        BindProducts(orderId, gvProducts);
		
			    }
		
			    else
		
			    {
		
			        row.FindControl("pnlProducts").Visible = false;
		
			        imgShowHide.CommandArgument = "Show";
		
			        imgShowHide.ImageUrl = "~/images/plus.png";
		
			    }
		
			}
		
			 
		
			private void BindProducts(int orderId, GridView gvProducts)
		
			{
		
			    gvProducts.ToolTip = orderId.ToString();
		
			    gvProducts.DataSource = GetData(string.Format("SELECT ProductId, ProductName FROM Products WHERE ProductId IN (SELECT ProductId FROM [Order Details] WHERE OrderId = '{0}')", orderId));
		
			    gvProducts.DataBind();
		
			}
		
			 
		
			protected void OnProductsGrid_PageIndexChanging(object sender, GridViewPageEventArgs e)
		
			{
		
			    GridView gvProducts = (sender as GridView);
		
			    gvProducts.PageIndex = e.NewPageIndex;
		
			    BindProducts(int.Parse(gvProducts.ToolTip), gvProducts);
		
			}
	 
	
		 
	
		VB.Net
	
		
			Protected Sub Show_Hide_ProductsGrid(sender As Object, e As EventArgs)
		
			    Dim imgShowHide As ImageButton = TryCast(sender, ImageButton)
		
			    Dim row As GridViewRow = TryCast(imgShowHide.NamingContainer, GridViewRow)
		
			    If imgShowHide.CommandArgument = "Show" Then
		
			        row.FindControl("pnlProducts").Visible = True
		
			        imgShowHide.CommandArgument = "Hide"
		
			        imgShowHide.ImageUrl = "~/images/minus.png"
		
			        Dim orderId As Integer = Convert.ToInt32(TryCast(row.NamingContainer, GridView).DataKeys(row.RowIndex).Value)
		
			        Dim gvProducts As GridView = TryCast(row.FindControl("gvProducts"), GridView)
		
			        BindProducts(orderId, gvProducts)
		
			    Else
		
			        row.FindControl("pnlProducts").Visible = False
		
			        imgShowHide.CommandArgument = "Show"
		
			        imgShowHide.ImageUrl = "~/images/plus.png"
		
			    End If
		
			End Sub
		
			 
		
			Private Sub BindProducts(orderId As Integer, gvProducts As GridView)
		
			    gvProducts.ToolTip = orderId.ToString()
		
			    gvProducts.DataSource = GetData(String.Format("SELECT ProductId, ProductName FROM Products WHERE ProductId IN (SELECT ProductId FROM [Order Details] WHERE OrderId = '{0}')", orderId))
		
			    gvProducts.DataBind()
		
			End Sub
		
			 
		
			Protected Sub OnProductsGrid_PageIndexChanging(sender As Object, e As GridViewPageEventArgs)
		
			    Dim gvProducts As GridView = TryCast(sender, GridView)
		
			    gvProducts.PageIndex = e.NewPageIndex
		
			    BindProducts(Integer.Parse(gvProducts.ToolTip), gvProducts)
		
			End Sub
	 
	
		 
	
		 
	
		Client Side Scripting
	
		Finally some client side scripting using jQuery is required in order to create insert an HTML Row for displaying the Nested or Child GridView
	
		
			<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
		
			<script type="text/javascript">
		
			    $(function () {
		
			        $("[id*=imgOrdersShow]").each(function () {
		
			            if ($(this)[0].src.indexOf("minus") != -1) {
		
			                $(this).closest("tr").after("<tr><td></td><td colspan = '999'>" + $(this).next().html() + "</td></tr>");
		
			                $(this).next().remove();
		
			            }
		
			        });
		
			        $("[id*=imgProductsShow]").each(function () {
		
			            if ($(this)[0].src.indexOf("minus") != -1) {
		
			                $(this).closest("tr").after("<tr><td></td><td colspan = '999'>" + $(this).next().html() + "</td></tr>");
		
			                $(this).next().remove();
		
			            }
		
			        });
		
			    });
		
			</script>
	 
	
		 
	
		 
	
		 
	
		CSS Classes for styling the GridViews
	
		You can either place the following CSS classes on the page itself or in some CSS Class file.
	
		
			<style type="text/css">
		
			    .Grid td
		
			    {
		
			        background-color: #A1DCF2;
		
			        color: black;
		
			        font-size: 10pt;
		
			        line-height: 200%;
		
			    }
		
			    .Grid th
		
			    {
		
			        background-color: #3AC0F2;
		
			        color: White;
		
			        font-size: 10pt;
		
			        line-height: 200%;
		
			    }
		
			    .ChildGrid td
		
			    {
		
			        background-color: #eee !important;
		
			        color: black;
		
			        font-size: 10pt;
		
			        line-height: 200%;
		
			    }
		
			    .ChildGrid th
		
			    {
		
			        background-color: #6C6C6C !important;
		
			        color: White;
		
			        font-size: 10pt;
		
			        line-height: 200%;
		
			    }
		
			    .Nested_ChildGrid td
		
			    {
		
			        background-color: #fff !important;
		
			        color: black;
		
			        font-size: 10pt;
		
			        line-height: 200%;
		
			    }
		
			    .Nested_ChildGrid th
		
			    {
		
			        background-color: #2B579A !important;
		
			        color: White;
		
			        font-size: 10pt;
		
			        line-height: 200%;
		
			    }
		
			</style>
	 
	
		 
	
	
		 
	
		 
	
		Demo
	
	
		 
	
		Downloads