In this article I will explain with an example, how to build a nested GridViews i.e. GridView inside GridView with expand collapse functionality to show and hide the child GridView in ASP.Net using C# and VB.Net.
	
		 
	
		Database
	
		Here I am making use of Microsoft’s Northwind Database. You can download it from here.
	
	
		 
	
		 
	
		HTML Markup
	
		The HTML Markup consists of:
	
		GridView – For displaying parent records.
	
		Inside the GridView, there another GridView which is used to display child records placed inside an ASP.Net Panel control.
	
		
			<asp:GridView ID="gvCustomers" runat="server" AutoGenerateColumns="false" CssClass="Grid" 
		
			    DataKeyNames="CustomerID" OnRowDataBound="OnRowDataBound">
		
			    <Columns>
		
			        <asp:TemplateField>
		
			            <ItemTemplate>
		
			                <img alt="" style="cursor: pointer" src="images/plus.png" />
		
			                <img alt="" style="cursor: pointer; display:none" src="images/minus.png" />
		
			                <asp:Panel ID="pnlOrders" runat="server" Style="display: none">
		
			                    <asp:GridView ID="gvOrders" runat="server" AutoGenerateColumns="false" CssClass="ChildGrid">
		
			                        <Columns>
		
			                            <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>
	 
	
		 
	
		 
	
		Generic function to populate DataTable 
	
		The following function is used throughout this article to populate DataTable with Database records.
	
		It accepts the SQL Query as parameter and it returns the DataTable object containing the Database records.
	
		C#
	
		
			private static DataTable GetData(string query)
		
			{
		
			    string strConnString = ConfigurationManager.ConnectionStrings["constr"].ConnectionString;
		
			    using (SqlConnection con = new SqlConnection(strConnString))
		
			    {
		
			        using (SqlDataAdapter sda = new SqlDataAdapter())
		
			        {
		
			            using (DataTable dt = new DataTable())
		
			            {
		
			                sda.Fill(dt);
		
			                return dt;
		
			            }
		
			        }
		
			    }
		
			}
	 
	
		 
	
		VB.Net
	
		
			Private Shared Function GetData(query As String) As DataTable
		
			    Dim conString As String = ConfigurationManager.ConnectionStrings("constr").ConnectionString
		
			    Using con As New SqlConnection(conString)
		
			        Using sda As New SqlDataAdapter(query, con)
		
			            Using dt As New DataTable()
		
			                sda.Fill(dt)
		
			                Return dt
		
			            End Using
		
			        End Using
		
			    End Using
		
			End Function
	 
	
		 
	
		 
	
		Binding Parent GridView
	
		Inside the Page Load event, GetData method is called.
	
		Inside GetData method, the records fetched from the Customers table are bound to the parent ASP.Net GridView.
	
		C#
	
		
			protected void Page_Load(object sender, EventArgs e)
		
			{
		
			    if (!this.IsPostBack)
		
			    {
		
			        gvCustomers.DataSource = GetData("SELECT TOP 10 * FROM Customers");
		
			        gvCustomers.DataBind();
		
			    }
		
			}
	 
	
		 
	
		VB.Net
	
		
			Protected Sub Page_Load(sender As Object, e As EventArgs) Handles Me.Load
		
			    If Not Me.IsPostBack Then
		
			        gvCustomers.DataSource = GetData("SELECT TOP 10 * FROM Customers")
		
			        gvCustomers.DataBind()
		
			    End If
		
			End Sub
	 
	
		 
	
		 
	
		Binding the Child GridView with the Orders for each Customer in the Parent GridView
	
		Inside the OnRowDataBound event handler, CustomerId is referenced using the DataKeys property and then, the child GridView is referenced.
	
	
		 
	
		Finally, the child GridView is populated with the records from the Orders table fetched based on CustomerId.
	
		C#
	
		
			protected void OnRowDataBound(object sender, GridViewRowEventArgs e)
		
			{
		
			    if (e.Row.RowType == DataControlRowType.DataRow)
		
			    {
		
			        string customerId = gvCustomers.DataKeys[e.Row.RowIndex].Value.ToString();
		
			        GridView gvOrders = e.Row.FindControl("gvOrders") as GridView;
		
			        gvOrders.DataSource = GetData(string.Format("SELECT TOP 3 * FROM Orders WHERE CustomerId='{0}'", customerId));
		
			        gvOrders.DataBind();
		
			    }
		
			}
	 
	
		 
	
		VB.Net
	
		
			Protected Sub OnRowDataBound(sender As Object, e As GridViewRowEventArgs)
		
			    If e.Row.RowType = DataControlRowType.DataRow Then
		
			        Dim customerId As String = gvCustomers.DataKeys(e.Row.RowIndex).Value.ToString()
		
			        Dim gvOrders As GridView = TryCast(e.Row.FindControl("gvOrders"), GridView)
		
			        gvOrders.DataSource = GetData(String.Format("SELECT TOP 3 * FROM Orders WHERE CustomerId='{0}'", customerId))
		
			        gvOrders.DataBind()
		
			    End If
		
			End Sub
	 
	
		 
	
		 
	
		Client Side Expand Collapse functionality using jQuery
	
		Inside the HTML Markup, the jQuery JS script file is inherited. 
	
		Plus Button
	
		The plus image has been assigned with a jQuery click event handler. 
	
		Inside this event handler, the child Grid html is referenced and appended to the Parent GridView row and the minus image is displayed and the plus image is made hidden.
	
		 
	
		Minus Button
	
		The minus image has been assigned with a jQuery click event handler. 
	
		Inside this event handler, the child Grid is removed from the Parent GridView row and the plus image is displayed and the minus image is made hidden.
	
		
			<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
		
			<script type="text/javascript">
		
			    $("[src*=plus]").on("click", function () {
		
			        $(this).closest("tr").after("<tr><td></td><td class='orders' colspan = '999'>" + $(this).closest("tr").find("[id*=Orders]").html() + "</td></tr>");
		
			        $(this).closest("tr").find("[src*=minus]").show();
		
			        $(this).hide();
		
			    });
		
			    $("[src*=minus]").on("click", function () {
		
			        $(this).closest("tr").next().remove();
		
			        $(this).closest("tr").find("[src*=plus]").show();
		
			        $(this).hide();
		
			    });
		
			</script>
	 
	
		 
	
		 
	
		Screenshot
	![ASP.Net Nested GridViews – GridView inside GridView with Expand and Collapse feature]() 
	
		 
	
		 
	
		Demo
	
	
		 
	
		 
	
		Downloads