Click here to Skip to main content
15,885,182 members
Articles / Web Development / ASP.NET

Nested GridView in ASP.NET using C#

Rate me:
Please Sign up or sign in to vote.
4.50/5 (2 votes)
25 May 2014CPOL2 min read 34K   9   7
Nested Gridview in ASP.NET using C#

Introduction

This example shows you how you can create Nested GridView, i.e., GridView under another GridView using little JQuery code. Let's explain.

Nested GridView

Nested GridView

Background

I’m using Northwind database here.

Quick Start

In Master GridView, I’ll show you the Customer’s details, i.e., ContactName and City from ‘Customer’ table. Then in the Child GridView, I’ll show you Order details of corresponding Customers, i.e., OrderID and OrderDate.

Creating Main GridView

ASP.NET
<asp:GridView
	ID="grdViewCustomers"
	runat="server"
	AutoGenerateColumns="false"
	DataKeyNames="CustomerID"
	OnRowDataBound="grdViewCustomers_OnRowDataBound"
	CssClass="Grid">
	<Columns>
		<asp:BoundField
			ItemStyle-Width="150px"
			DataField="ContactName"
			HeaderText="Contact Name" />
		<asp:BoundField
			ItemStyle-Width="150px"
			DataField="City"
			HeaderText="City" />
	</Columns>
</asp:GridView>

So, now it shows only two columns, i.e., ContactName and City. Now, I’ll insert ‘plus sign image’ to the First Column of every row. This is because, when I click this ‘plus sign image’ then the Child GridView will be displayed and the ‘plus sign image’ will be the ‘minus sign image’. And when I click the ‘minus sign image’, the Child GridView will remove from our sight and ‘minus sign image’ becomes the ‘plus sign image’ like toggle. So, I’ve to take an ItemTemplate within a TemplateField inside the Columns at first position. Let's see:

ASP.NET
<asp:GridView
	ID="grdViewCustomers"
	runat="server"
	AutoGenerateColumns="false"
	DataKeyNames="CustomerID"
	OnRowDataBound="grdViewCustomers_OnRowDataBound"
	CssClass="Grid">
	<Columns>
		<!-- Inserting 'plus sign' -->
		<asp:TemplateField ItemStyle-Width="20px">
			<ItemTemplate>
				<a href="JavaScript:divexpandcollapse
				('div<%# Eval("CustomerID") %>');">
					<img alt="Details" id="imgdiv<%# Eval
					("CustomerID") %>" src="images/plus.png" />
				</a>
			</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>

Now, you see that I’ve linked a JavaScript function to the ‘plus sign image’ which does all the functionality that I’ve told above against the Click event of the ‘plus sign image’. This JavaScript function takes the Div name in which the Child GridView exists. There will be one Child GridView for each row of the Master GridView. So, the Div id must be different. That’s why I concatenate Div id with CustomerID and there will one ‘plus sign image’ for each row of the Master GridView, so I also concatenate the img id with CustomerID. Now let's add the Div just after the link of the ‘plus sign image’ and implement Child GridView under that Div:

XML
<asp:GridView
	ID="grdViewCustomers"
	runat="server"
	AutoGenerateColumns="false"
	DataKeyNames="CustomerID"
	OnRowDataBound="grdViewCustomers_OnRowDataBound"
	CssClass="Grid">
	<Columns>
		<!-- Inserting 'plus sign' -->
		<asp:TemplateField ItemStyle-Width="20px">
			<ItemTemplate>
				<a href="JavaScript:divexpandcollapse
				('div<%# Eval("CustomerID") %>');">
					<img alt="Details" id="imgdiv<%# Eval
					("CustomerID") %>" src="images/plus.png" />
				</a>
				<!-- Adding the Div container -->
				<div id="div<%# Eval("CustomerID") %>" style="display: none;">
					<!-- Adding Child GridView -->
					<asp:GridView
						ID="grdViewOrdersOfCustomer"
						runat="server"
						AutoGenerateColumns="false"
						DataKeyNames="CustomerID"
						CssClass="ChildGrid">
						<Columns>
							<asp:BoundField
								ItemStyle-Width="150px"
								DataField="OrderID"
								HeaderText="Order ID" />
							<asp:BoundField
								ItemStyle-Width="150px"
								DataField="OrderDate"
								HeaderText="Order Date" />
						</Columns>
					</asp:GridView>
				</div>
			</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>

Let's see the little JQuery which checks whether the ‘plus sign image’ source contains the path of the ‘plus sign’ image or ‘minus sign’ image and do the said functionality accordingly:

JavaScript
function divexpandcollapse(divname) {
	var img = "img" + divname;
	if ($("#" + img).attr("src") == "images/plus.png") {
		$("#" + img)
			.closest("tr")
			.after("<tr><td></td><td colspan = 
			'100%'>" + $("#" + divname)
			.html() + "</td></tr>")
		$("#" + img).attr("src", "images/minus.png");
	} else {
		$("#" + img).closest("tr").next().remove();
		$("#" + img).attr("src", "images/plus.png");
	}
}

Now the client side part is over. The main part is how you fill the Child GridView? Don’t worry, there is an event which is triggered when there is one container control within the row of the GridView. The event is OnRowDataBound. And I’ve already added, this event to the Master GridView properties and the name of event handler is: grdViewCustomers_OnRowDataBound. And we also fill the Master GridView in the Page_Load() event. So let's implement:

C#
protected void grdViewCustomers_OnRowDataBound(object sender, GridViewRowEventArgs e)
{
	if (e.Row.RowType == DataControlRowType.DataRow)
	{
		string customerID = grdViewCustomers.DataKeys[e.Row.RowIndex].Value.ToString();
		GridView grdViewOrdersOfCustomer = 
		(GridView)e.Row.FindControl("grdViewOrdersOfCustomer");
		grdViewOrdersOfCustomer.DataSource = SelectData("SELECT top 3 CustomerID, 
		OrderID, OrderDate FROM Orders WHERE CustomerID='" + customerID + "'");
		grdViewOrdersOfCustomer.DataBind();
	}
}

private DataTable SelectData(string sqlQuery)
{
	string connectionString = 
	System.Web.Configuration.WebConfigurationManager.ConnectionStrings
                            ["SQLServerConnectionString"].ConnectionString;
	using (SqlDataAdapter sqlDataAdapter = new SqlDataAdapter(sqlQuery, connectionString))
	{
		DataTable dt = new DataTable("Customers");
		sqlDataAdapter.Fill(dt);
		return dt;
	}
}

protected void Page_Load(object sender, EventArgs e)
{
	grdViewCustomers.DataSource = SelectData
	("SELECT top 3 CustomerID, ContactName, City FROM Customers");
	grdViewCustomers.DataBind();
}

It's done!

History

This is the first release of this article. In the next release, I’ll show you how you add a button in nested GridView and how the whole thing can be done using AJAX. Thank you for reading!

If you have any doubts, please post your questions. If you really like this article, please share it.

Don’t forget to vote or comment about my writing.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer National Informatics Centre (NIC)
India India
Hello! Myself Debopam Pal. I've completed my MCA degree from West Bengal University of Technology at 2013. I'm from India. I’ve started to work with MS Technologies in 2013 specially in C# 4.0, ASP.NET 4.0. I've also worked in PHP 5. Now I work in JAVA/J2EE, Struts2. Currently I'm involved in a e-Governance Project since Jan, 2014. In my leisure time I write Blog, Articles as I think that every developer should contribute something otherwise resource will be finished one day. Thank you for your time.

Visit: Linkedin Profile | Facebook Profile | Google+ Profile | CodeProject Profile

Comments and Discussions

 
QuestionAdd other gridview nested in the first nested greidview Pin
Ugo Basile15-Mar-19 1:45
Ugo Basile15-Mar-19 1:45 
Generalgood job Pin
Member 109765296-Aug-14 20:35
Member 109765296-Aug-14 20:35 
Answernested GridView based on stored procedures Pin
krakoss@mail.ru27-May-14 18:27
professionalkrakoss@mail.ru27-May-14 18:27 
1- SP...
SQL
ALTER PROCEDURE dbo.tUpravTMunUch
AS
	SELECT        tUprav.nameUprav, tUprav.idUp
	    FROM            tUprav RIGHT OUTER JOIN
	                             tMunUch ON tUprav.idUp = tMunUch.idUprav
	    WHERE        (NOT (tMunUch.nameMunUch IS NULL))
	    GROUP BY tUprav.nameUprav, tUprav.idPodrazdel, tUprav.idUp
	    ORDER BY tUprav.idPodrazdel, tUprav.nameUprav 
	RETURN

2-SP...
SQL
ALTER PROCEDURE dbo.tUpNameMunUch
	
	@idUp AS INT

AS
	/* SET NOCOUNT ON */
	SELECT        tMunUch.idMunUch, tMunUch.idUprav, tMunUch.nameMunUch
	FROM            tMunUch INNER JOIN
	                         tUprav ON tMunUch.idUprav = tUprav.idUp
	WHERE        (tUprav.idUp = @idUp)
	ORDER BY tMunUch.nameMunUch
	RETURN

code Default.aspx
ASP.NET
<%@ Page Title="" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="MunUch_Default" %>

<asp:Content ID="Content1" ContentPlaceHolderID="cphContent" runat="Server">
    <div class="divText">
        <asp:Panel CssClass="grid" ID="pnlCust" runat="server">
            <asp:Panel ID="pnlUpdate" runat="server">
                <asp:GridView 
                    Width="100%" 
                    AllowPaging="True" 
                    ID="gvMaster" 
                    AutoGenerateColumns="False"
                    runat="server" 
                    ShowHeader="False" 
                    PageSize="100" 
                    GridLines="Horizontal"
                    DataKeyNames="idUp"
                    OnRowDataBound="gvMaster_OnRowDataBound">
                    <Columns>
                        <asp:TemplateField ItemStyle-Width="25px">
                            <ItemTemplate>
                                <asp:Panel Style="margin: 5px; cursor: pointer" ID="pnlMaster" runat="server">
                                    <asp:Image ID="imgCollapsible" ImageUrl="~/images/e.gif" runat="server" />
                                </asp:Panel>
                            </ItemTemplate>
                        </asp:TemplateField>
                        <asp:TemplateField>
                            <ItemTemplate>
                                <%#Eval("nameUprav")%>
                                <asp:Panel Style="margin: 2px;" ID="pnlDetails" runat="server">
                                    <asp:GridView AutoGenerateColumns="false" ID="gvDetails" runat="server"
                                        ShowHeader="true" EnableViewState="false" PageSize="100">
                                        <Columns>
                                            <asp:TemplateField HeaderText="учреждения" HeaderStyle-CssClass="Flyout"
                                                HeaderStyle-HorizontalAlign="Center" ItemStyle-CssClass="divText">
                                                <ItemTemplate>
                                                    <asp:Panel Style="min-width: 638px" ID="pnlDetails1" runat="server">
                                                        <%#Eval("nameMunUch")%>
                                                    </asp:Panel>
                                                </ItemTemplate>
                                            </asp:TemplateField>
                                        </Columns>
                                    </asp:GridView>
                                </asp:Panel>
                                <ajaxToolkit:CollapsiblePanelExtender ID="cpe" runat="Server" TargetControlID="pnlDetails"
                                    CollapsedSize="0" Collapsed="True" ExpandControlID="pnlMaster" CollapseControlID="pnlMaster"
                                    AutoCollapse="False" AutoExpand="False" ScrollContents="false" ImageControlID="imgCollapsible"
                                    ExpandedImage="~/images/c.gif" CollapsedImage="~/images/e.gif" ExpandDirection="Vertical" />
                            </ItemTemplate>
                        </asp:TemplateField>
                    </Columns>
                </asp:GridView>
            </asp:Panel>
        </asp:Panel>
    </div>
</asp:Content>

code Default.aspx.cs
C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;
using System.IO;
using System.Data.SqlClient;
using System.Configuration;

public partial class MunUch_Default : BasePage
{
    protected void Page_Load(object sender, EventArgs e)
    {
       if (!IsPostBack)
{
       
                bind_tUpravTMunUch();
        }
    }
    public void bind_tUpravTMunUch()
    {
        gvMaster.DataSource = GetDatatUpravTMunUch();
        gvMaster.DataBind();
    }
    public DataSet GetDatatUpravTMunUch()
    {
        SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["AAA"].ConnectionString);
        SqlCommand cmd = new SqlCommand("[tUpravTMunUch]", con);
        cmd.CommandType = CommandType.StoredProcedure;
        SqlDataAdapter adp = new SqlDataAdapter(cmd);
        DataSet ds = new DataSet();
        adp.Fill(ds);
        con.Close();
        return ds;
    }
    protected void gvMaster_OnRowDataBound(object sender, GridViewRowEventArgs e)
    {
        if (e.Row.RowType == DataControlRowType.DataRow)
        {
            Image imgC = ((Image)(e.Row.FindControl("imgCollapsible")));
            int idUp = Convert.ToInt32(gvMaster.DataKeys[e.Row.RowIndex].Value);
            GridView gvDetails = (GridView)e.Row.FindControl("gvDetails");
            gvDetails.DataSource = GetDataUpNameMunUch(idUp);
            gvDetails.DataBind();
            if (gvDetails.Rows.Count == 0)
            {
                imgC.Visible = false;
            }
        }
    }
    public DataSet GetDataUpNameMunUch(int idUp)
    {
        SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["AAA"].ConnectionString);
        SqlCommand cmd = new SqlCommand("[tUpNameMunUch]", con);
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.AddWithValue("@idUp",idUp);
        SqlDataAdapter adp = new SqlDataAdapter(cmd);
        DataSet ds = new DataSet();
        adp.Fill(ds);
        con.Close();
        return ds;
    }
}

and implemented an example - http://xn----7sbab9byagn3e.xn--p1ai/MunUch/

modified 28-May-14 0:35am.

GeneralRe: nested GridView based on stored procedures Pin
dearabi9-Jul-14 19:20
dearabi9-Jul-14 19:20 
GeneralRe: nested GridView based on stored procedures Pin
krakoss@mail.ru9-Jul-14 20:46
professionalkrakoss@mail.ru9-Jul-14 20:46 
GeneralRe: nested GridView based on stored procedures Pin
dearabi13-Jul-14 19:33
dearabi13-Jul-14 19:33 
QuestionCould not download the source code Pin
Tridip Bhattacharjee25-May-14 21:24
professionalTridip Bhattacharjee25-May-14 21:24 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.