A master detail is a common scenario in data driven applications and developers often ask  how it can done with C1GridView.  This can be handled with C1GridView in multiple ways; we could use two different panels and on selection in master grid show the detail grid in second panel. Apart from this we could also have a nested view with the help of little JQuery.  Here I will show how we can create a nested C1GridView as depicted in the below snapshot:


nestedgrid


To accomplish the above we would need to use C1GridView template fields. The JavaScript function would be attached to the up-down arrow buttons inside the template column. Whenever the user clicks on the arrow button the detail grid is shown inside a div. The detail grid is populated in “RowDataBound” event of the master grid.

Let’s get started:

Create a new website and drop a ScriptManager and C1gridView on the default.aspx page. I am using NWind access data to bind the grid and omitting the adding and connection part here.

Create bound columns for “CustomerID”, “ContactName” and “City” inside C1GridView.

Here is the markup of the grid:
<wijmo:C1GridView ID="C1GridView1" runat="server" OnRowDataBound="C1GridView1_RowDataBound" AutoGenerateColumns="false" DataKeyNames="CustomerID" AllowColSizing="True" >
            <Columns>
        C1BoundField Width="100px" DataField="CustomerID" HeaderText="CustomerID" />
                <wijmo:C1BoundField  DataField="ContactName" HeaderText="Name" />
                <wijmo:C1BoundField  DataField="City" HeaderText="City" />
            </Columns>
</wijmo:C1GridView>

Next we add the template field with toggle image and div to show the detail grid.
<wijmo:C1GridView ID="C1GridView1" runat="server" OnRowDataBound="C1GridView1_RowDataBound" AutoGenerateColumns="false" DataKeyNames="CustomerID" AllowColSizing="True" >
            <Columns>
                <wijmo:C1TemplateField  Width="20">
                    <ItemTemplate>
                        <a href="JavaScript:toggleDetail('div<%# Eval("CustomerID") %>');">
                            <img alt="Details" id="imgdiv<%# Eval("CustomerID") %>" src="images/arrow_down.png"  />
                        </a>
                        <div id="div<%# Eval("CustomerID") %>" style="display: none;">
                            <wijmo:C1GridView ID="detailGrid" runat="server" AutoGenerateColumns="false"
                                DataKeyNames="CustomerID" >
                                <Columns>
                                    <wijmo:C1BoundField Width="100px" DataField="CustomerID" HeaderText="Order ID" />
                                    <wijmo:C1BoundField Width="100px" DataField="OrderID" HeaderText="Order ID" />
                                    <wijmo:C1BoundField Width="150px" DataField="OrderDate" HeaderText="Order Date" />
                                    <wijmo:C1BoundField Width="100px" DataField="ShipCity" HeaderText="Ship City" />
                                    <wijmo:C1BoundField Width="150px" DataField="ShipCountry" HeaderText="Ship Country" />
                                </Columns>
                            </wijmo:C1GridView>
                        </div>
                    </ItemTemplate>
                </wijmo:C1TemplateField>
                <wijmo:C1BoundField Width="100px" DataField="CustomerID" HeaderText="CustomerID" />
                <wijmo:C1BoundField  DataField="ContactName" HeaderText="Name" />
                <wijmo:C1BoundField  DataField="City" HeaderText="City" />
            </Columns>
</wijmo:C1GridView>

Here is the “toggleDetail” function:
function toggleDetail(divname) {
            var img = "img" + divname;
            if ($("#" + img).attr("src") == "images/arrow_down.png") {
                $("#" + img)
                .closest("tr")
                .after("<tr><td></td><td colspan = '100%'>" + $("#" + divname)
                .html() + "</td></tr>");
                $("#" + img).attr("src", "images/arrow_up.png");
            } else {
                $("#" + img).closest("tr").next().remove();
                $("#" + img).attr("src", "images/arrow_down.png");
            }
        }

We bind the master grid in the page load as below:
this.C1GridView1.DataSource = GetData("SELECT top 20 CustomerID, ContactName, City FROM Customers");
this.C1GridView1.DataBind();

Here is the “GetData” method:
private DataTable GetData(string sqlQuery)
    {
        string connectionString = System.Web.Configuration.WebConfigurationManager.ConnectionStrings["con"].ConnectionString;
        using (OleDbDataAdapter sqlDataAdapter = new OleDbDataAdapter(sqlQuery, connectionString))
        {
            DataTable dt = new DataTable("Customers");
            sqlDataAdapter.Fill(dt);
            return dt;
        }
    }

The “RowDataBound” event of the C1GridView provides us “C1GridViewRowEventArgs” argument, this we can use to get the value of the primary key in master grid. Once we have the key it is very simple to get the related detail data and populate the child grid.

Here is how the detail grid should be bound:
protected void C1GridView1_RowDataBound(object sender, C1.Web.Wijmo.Controls.C1GridView.C1GridViewRowEventArgs e)
    {
        if (e.Row.RowType == C1.Web.Wijmo.Controls.C1GridView.C1GridViewRowType.DataRow)
        {
            string customerID = this.C1GridView1.DataKeys[e.Row.RowIndex].Value.ToString();
            C1GridView detailGrid = (C1GridView)e.Row.FindControl("detailGrid");
            detailGrid.DataSource = GetData("SELECT top 15 CustomerID, OrderID, OrderDate, ShipCity,ShipCountry FROM Orders WHERE CustomerID='" + customerID + "'");
            detailGrid.DataBind();
        }
    }

Now run the application to see the nested grid in action.

Attached is the complete sample with paging enabled using C1Pager.

Download Sample