Display inline Master Detail data in a Asp.Net Gridview C# VB.Net

Most of our web application needs to implement one-to-many relationships. So when we want to design such type of relationships in UI, at first we want to show the list of parents then show its corresponding child records. For example a company wants to see a list of suppliers as well as in one time also wants to see the product list that the supplier responsible to supply. For simplicity here i use datatable(one can fill datatable from database easily) to keep my example as simple as possible. Here i want to develop the below UI to display Master Detail record:

Display inline Master Detail data in a Asp.Net Gridview Csharp VB.Net

Here the main task is to design the GridViews. To do that here i am considering one master GridView & then i want to put another GridView in a template column to represent child records. Initially i will hide all corresponding child records by using javascript method & show a collapse icon in the detail column. So user can show hide the child records based on a master record. The aspx page HTML code is given below:

<asp:GridView runat="server" ID="gvMasterDetail" Width="600px" DataKeyNames="ID" OnRowDataBound="gvMasterDetail_RowDataBound" AutoGenerateColumns="false" HeaderStyle-BackColor="CornflowerBlue" HeaderStyle-Font-Bold="true" HeaderStyle-ForeColor="White" CellPadding="5">

        <asp:BoundField DataField="Code" HeaderText="Code"></asp:BoundField>
        <asp:BoundField DataField="Name" HeaderText="Name"></asp:BoundField>
        <asp:BoundField DataField="Address" HeaderText="Address"></asp:BoundField>
        <asp:BoundField DataField="Contact" HeaderText="Contact no"> </asp:BoundField>

        <asp:TemplateField HeaderText="Details" ItemStyle-Width="50%">

        <img src="Images/Expand.jpg" onclick="ChildBlock(this,document.getElementById('<%#Eval("ID") %>'));" />

        <div id='<%#Eval("ID") %>' style="display:none">
        <asp:GridView runat="server" ID="gvChild" DataKeyNames="ID" AutoGenerateColumns="false" Width="100%" HeaderStyle-BackColor="CornflowerBlue" HeaderStyle-Font-Bold="true" HeaderStyle-ForeColor="White" CellPadding="5">
        <asp:BoundField DataField="Code" HeaderText="Code"></asp:BoundField>
        <asp:BoundField DataField="Product Name" HeaderText="Product Name"></asp:BoundField>
        <asp:BoundField DataField="Unit" HeaderText="Unit">



To show & hide child div records i am using a javascript method which is given below. You can also use this javascript method to show & hide a div for different purpose:

<script type="text/javascript">
    function ChildBlock(img, obj) {
        if (obj.style.display == 'none') {
            obj.style.display = '';
            img.src = "Images/Collapse.jpg";
        else {
            obj.style.display = 'none';
            img.src = "Images/Expand.jpg";

Now we need to populate relational data. For simplicity i am using DataTable. One can change this code to fit database data. The code under page load event is:

C# Code:

    protected void Page_Load(object sender, EventArgs e)
        if (!IsPostBack)
            DataTable dtSupplier = new DataTable("Supplier");
            dtSupplier.Columns.Add(new DataColumn("ID", System.Type.GetType("System.UInt64")));
            dtSupplier.Columns.Add(new DataColumn("Code"));
            dtSupplier.Columns.Add(new DataColumn("Name"));
            dtSupplier.Columns.Add(new DataColumn("Address"));
            dtSupplier.Columns.Add(new DataColumn("Contact"));

            dtSupplier.Rows.Add(1, "st0001", "S.R. Steel", "Uttara, Dhaka", "01711xxxxxx");
            dtSupplier.Rows.Add(2, "ir0039", "Shadesh builders", "Rampura, Dhaka", "01711yyyyyy");
            dtSupplier.Rows.Add(3, "cr0042", "Orchard confec.", "Shahabag, Dhaka", "01711zzzzzz");
            dtSupplier.Rows.Add(4, "er0078", "Windblow", "Mirpur, Dhaka", "01711qqqqqq");
            dtSupplier.Rows.Add(5, "bd0301", "Rahimkarim", "Badda, Dhaka", "01711oooooo");

            //Read Child Data Here
            DataTable dtProducts = new DataTable("Products");
            dtProducts.Columns.Add(new DataColumn("ID", System.Type.GetType("System.UInt64")));
            dtProducts.Columns.Add(new DataColumn("Code"));
            dtProducts.Columns.Add(new DataColumn("Product Name"));
            dtProducts.Columns.Add(new DataColumn("Unit"));
            dtProducts.Columns.Add(new DataColumn("SupplierID", System.Type.GetType("System.UInt64")));

            dtProducts.Rows.Add(1, "PR0022", "Ring", "Dozen", 1);
            dtProducts.Rows.Add(2, "PR0033", "Band", "Qty", 1);
            dtProducts.Rows.Add(3, "PR0044", "Tape", "Cartoon", 1);

            dtProducts.Rows.Add(4, "PR0001", "AXE", "Dozen", 2);
            dtProducts.Rows.Add(5, "PR0039", "LUX", "Qty", 2);
            dtProducts.Rows.Add(6, "PR0001", "Dove", "Cartoon", 2);

            dtProducts.Rows.Add(7, "PR0055", "Pen", "Dozen", 3);
            dtProducts.Rows.Add(8, "PR0066", "Toothbrash", "Qty", 3);
            dtProducts.Rows.Add(9, "PR0077", "Carbon", "Cartoon", 3);

            Session["Products"] = dtProducts;

            gvMasterDetail.DataSource = dtSupplier;

VB.Net Code:

    Protected Sub Page_Load(sender As Object, e As System.EventArgs) Handles Me.Load
            If Not IsPostBack Then
                Dim dtSupplier As New DataTable("Supplier")
                dtSupplier.Columns.Add(New DataColumn("ID", System.Type.[GetType]("System.UInt64")))
                dtSupplier.Columns.Add(New DataColumn("Code"))
                dtSupplier.Columns.Add(New DataColumn("Name"))
                dtSupplier.Columns.Add(New DataColumn("Address"))
                dtSupplier.Columns.Add(New DataColumn("Contact"))

                dtSupplier.Rows.Add(1, "st0001", "S.R. Steel", "Uttara, Dhaka", "01711xxxxxx")
                dtSupplier.Rows.Add(2, "ir0039", "Shadesh builders", "Rampura, Dhaka", "01711yyyyyy")
                dtSupplier.Rows.Add(3, "cr0042", "Orchard confec.", "Shahabag, Dhaka", "01711zzzzzz")
                dtSupplier.Rows.Add(4, "er0078", "Windblow", "Mirpur, Dhaka", "01711qqqqqq")
                dtSupplier.Rows.Add(5, "bd0301", "Rahimkarim", "Badda, Dhaka", "01711oooooo")

                'Read Child Data Here
                Dim dtProducts As New DataTable("Products")
                dtProducts.Columns.Add(New DataColumn("ID", System.Type.[GetType]("System.UInt64")))
                dtProducts.Columns.Add(New DataColumn("Code"))
                dtProducts.Columns.Add(New DataColumn("Product Name"))
                dtProducts.Columns.Add(New DataColumn("Unit"))
                dtProducts.Columns.Add(New DataColumn("SupplierID", System.Type.[GetType]("System.UInt64")))

                dtProducts.Rows.Add(1, "PR0022", "Ring", "Dozen", 1)
                dtProducts.Rows.Add(2, "PR0033", "Band", "Qty", 1)
                dtProducts.Rows.Add(3, "PR0044", "Tape", "Cartoon", 1)

                dtProducts.Rows.Add(4, "PR0001", "AXE", "Dozen", 2)
                dtProducts.Rows.Add(5, "PR0039", "LUX", "Qty", 2)
                dtProducts.Rows.Add(6, "PR0001", "Dove", "Cartoon", 2)

                dtProducts.Rows.Add(7, "PR0055", "Pen", "Dozen", 3)
                dtProducts.Rows.Add(8, "PR0066", "Toothbrash", "Qty", 3)
                dtProducts.Rows.Add(9, "PR0077", "Carbon", "Cartoon", 3)

                Session("Products") = dtProducts

                gvMasterDetail.DataSource = dtSupplier
            End If
    End Sub

Now to bind child gridview i am implementing RowDataBound method of the master gridview. The code like:

C# Code:

    protected void gvMasterDetail_RowDataBound(object sender, GridViewRowEventArgs e)
        if (e.Row.RowType == DataControlRowType.DataRow)
            DataTable dtProducts = GetProducts(Convert.ToUInt64(((DataRowView)e.Row.DataItem)["ID"]));
            ((GridView)e.Row.FindControl("gvChild")).DataSource = dtProducts;

VB.Net Code:

    Protected Sub gvMasterDetail_RowDataBound(sender As Object, e As GridViewRowEventArgs)
        If e.Row.RowType = DataControlRowType.DataRow Then
            Dim dtProducts As DataTable = GetProducts(Convert.ToUInt64(DirectCast(e.Row.DataItem, DataRowView)("ID")))
            DirectCast(e.Row.FindControl("gvChild"), GridView).DataSource = dtProducts
            DirectCast(e.Row.FindControl("gvChild"), GridView).DataBind()
        End If
    End Sub

In the above code segment i used a fuction named GetProducts. When gridview bind one master data then RowDataBound event will fire & call this method by master data id to populate child record. Here you can return a datasource to the child gridview based on master gridview Row DataItem ID value. Here i am showing how i filtered my child data:

C# Code:

    private DataTable GetProducts(UInt64 nSupplierID)
        DataTable dtProducts = (DataTable)Session["Products"];
        DataTable dtClone = dtProducts.Clone();
        foreach (DataRow oItem in dtProducts.Rows)
            if (Convert.ToUInt64(oItem["SupplierID"]) == nSupplierID)
        return dtClone;

VB.Net Code:

    Private Function GetProducts(nSupplierID As UInt64) As DataTable
        Dim dtProducts As DataTable = DirectCast(Session("Products"), DataTable)
        Dim dtClone As DataTable = dtProducts.Clone()
        For Each oItem As DataRow In dtProducts.Rows
            If Convert.ToUInt64(oItem("SupplierID")) = nSupplierID Then
            End If
        Return dtClone
    End Function

Hope this example will help you. If you need more complex structure to design then read:

Download Code Example C#        Download Code Example VB.Net

Posted in .Net, Asp.net, C#, Gridview, VB.Net

Leave a Reply

Your email address will not be published. Required fields are marked *