Wednesday 7 January 2015

Nested GridView in ASP.NET ,C# (GridView Inside a GridView)

Nested GridView in ASP.NET ,C# (GridView Inside a GridView) :

In Master GridView (GV_Master) I’ll show you the Customer’s details i.e.,CustomerId, CustomerName and CustomerAddress from ‘Customer_Details’ table.

Then in the Child GridView(GV_Child) I’ll show you Order details of corresponding to the Customers i.e. CustomerID.

In Master GridView (GV_Master) I’ll show you the Customer’s details i.e., CustomerName and CustomerAddress from ‘Customer_Details’ table. Then in the Child GridView(GV_Child) I’ll show you Order details of corresponding Customers i.e. CustomerIDand.

Creating Master GridView (GV_Master):
<asp:GridView ID="GV_Master" runat="server"
          AutoGenerateColumns="false" DataKeyNames="CustomerId"
          OnRowDataBound="GV_Master_OnRowDataBound" CssClass="Grid">
    <columns>
        <asp:BoundField ItemStyle-Width="150px" DataField="CustomerName " HeaderText="Customer Name" />
        <asp:BoundField ItemStyle-Width="150px" DataField="CustomerAddress " HeaderText="Customer Address " />
    </columns>
  </asp:GridView>

So, now it shows only two column i.e. CustomerName and CustomerAddress . Now, I’ll insert ‘plus sign image’ to the First Column of every row. As because, when I’ll click this ‘plus sign image’ then the Child GridView will displayed and the ‘plus sign image’ will be the ‘minus sign image’. And when I’ll 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

Please See The Code:
<asp:GridView ID="GV_Master" runat="server" AutoGenerateColumns="false" DataKeyNames="CustomerId"
    OnRowDataBound="GV_Master_OnRowDataBound" CssClass="Grid">
    <columns>
        <asp:TemplateField ItemStyle-Width="20px">
            <itemtemplate>
                <a href="java<!-- no -->script:divexpandcollapse('div<%# Eval(">
                    <img id="imgdiv<%# Eval(" alt="Details" src="images/plus.png" />
                </a>
       
               <asp:BoundField ItemStyle-Width="150px" DataField="CustomerName "    HeaderText="Customer Name" />
        <asp:BoundField ItemStyle-Width="150px" DataField="CustomerAddress " HeaderText="Customer Address " />
            </itemtemplate>
    </columns>
</asp:GridView>


Now, you see that I’ve linked a JavaScript function to the ‘plus sign image’ which does the all functionality what 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 lets add the Div just after the link of the ‘plus sign image’ and implement Child GridView under that Div:

<asp:GridView ID="GV_Master" runat="server"
           AutoGenerateColumns="false" DataKeyNames="CustomerId"
    OnRowDataBound="GV_Master_OnRowDataBound" CssClass="Grid">
    <columns>
        <asp:TemplateField ItemStyle-Width="20px">
            <itemtemplate>
                <a href="java<!-- no -->script:divexpandcollapse('div<%# Eval(">
                    <img id="imgdiv<%# Eval(" alt="Details" src="images/plus.png" />
                </a>               
                 <div id='div<%# Eval("CustomerId")%>' style="display: none; left: 5px; overflow: auto;">
                    <asp:GridView ID="GV_Child"
                            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>
                   
                </div>
            </itemtemplate>
       
      <asp:BoundField ItemStyle-Width="150px" DataField="CustomerName "    HeaderText="Customer Name" />
        <asp:BoundField ItemStyle-Width="150px" DataField="CustomerAddress " HeaderText="Customer Address " />
    </columns>
</asp:GridView>

Lets 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 said functionality accordingly:


function divexpandcollapse(divname) {
    var img = "img" + divname;
    if ($("#" + img).attr("src") == "images/plus.png") {
        $("#" + img)
    .closest("tr")
    .after("" + $("#" + divname)
    .html() + "")
        $("#" + 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: GV_Master_OnRowDataBound. And we also fill the Master GridView in the Page_Load() event. So lets implement:

Code Behind(C#):
protected void Page_Load(object sender, EventArgs e)
{
    GV_Master.DataSource =
      SelectData("SELECT  CustomerId, ContactName, CustomerAddress FROM Customers_Details");
    grdViewCustomers.DataBind();
}

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

protected void GV_Master_OnRowDataBound(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        string customerId = grdViewCustomers.DataKeys[e.Row.RowIndex].Value.ToString();
        GridView gvChild= (GridView)e.Row.FindControl("GV_Child");
        grdViewOrdersOfCustomer.DataSource = SelectData(
          "SELECT CustomerId, OrderId, OrderDate FROM Orders_Details WHERE CustomerId='" +
          customerId + "'");
        gvChild.DataBind();
    }
}


1 comment: