Working With Nested Grid Views in ASP.NET


While working with relational data, you would like to show the data in such a way that it should make sense to the user and have good user experience. In this article I will go over how to use the Nested Grid Views with Expand and collapsed functionality to show the data.

Objective



While working with relational data, you would like to show the data in such a way that it should make sense to the user and have good user experience. In this article I will go over how to use the Nested Grid Views with Expand and collapsed functionality to show the data.

There are numerous scenarios where we want to show data in Nested Grid Views like Parent & Child. Parent Grid View shows the main information and Child show the relevant information of Parent. Let take an example of showing the Order and Order Details Information.

I have taken the data from North wind database, but I will use that in XML for the simplicity of this article. Below is the data for Order and Order Details

Order Table



Order ID Customer ID Employee ID Order Date Required Date Shipped Date Ship Via Freight Ship Country
10248 VINET 5 7/4/96 8/1/96 7/16/96 3 32.38 France
10249 TOMSP 6 7/5/96 8/16/96 7/10/96 1 11.61 Germany
10250 HANAR 4 7/8/96 8/5/96 7/12/96 2 65.83 Brazil
10251 VICTE 3 7/8/96 8/5/96 7/15/96 1 41.34 France
10252 SUPRD 4 7/9/96 8/6/96 7/11/96 2 51.3 Belgium


Order Details Table



Order ID ProductID UnitPrice Quantity Discount
10248 11 14 12 0
10248 42 9.8 10 0
10248 72 34.8 5 0
10249 14 18.6 9 0
10249 51 42.4 40 0
10250 41 7.7 10 0
10250 51 42.4 35 0.15
10250 65 16.8 15 0.15

Order Id is the relational Key for Parent and Child. We would like to show the Order and once you click the Order Id you will see the details for that Order.
Let's put that together in XML Structure with relationship. I have nested the Order Details data inside the Order data.

XML Data (OrderDetailsData.xml)





<?xml version="1.0" encoding="utf-8"?>
<ArrayOfOrderData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<OrderData>
<Order ID>10248</Order ID>
<Customer ID>VINET</Customer ID>
<EmployeeID>5</EmployeeID>
<Order Date>7/4/96</Order Date>
<Freight>32.38</Freight>
<Ship Country>France</Ship Country>
<OrderDetailsData>
<OrderDetails>
<Order ID>10248</Order ID>
<ProductID>11</ProductID>
<UnitPrice>14</UnitPrice>
<Quantity>12</Quantity>
<Discount>0</Discount>
</OrderDetails>
<OrderDetails>
<Order ID>10248</Order ID>
<ProductID>42</ProductID>
<UnitPrice>9.8</UnitPrice>
<Quantity>10</Quantity>
<Discount>0</Discount>
</OrderDetails>
<OrderDetails>
<Order ID>10248</Order ID>
<ProductID>72</ProductID>
<UnitPrice>34.8</UnitPrice>
<Quantity>5</Quantity>
<Discount>0</Discount>
</OrderDetails>
</OrderDetailsData>
</OrderData>
<OrderData>
<Order ID>10249</Order ID>
<Customer ID>TOMSP</Customer ID>
<EmployeeID>6</EmployeeID>
<Order Date>7/5/96</Order Date>
<Freight>11.61</Freight>
<Ship Country>Germany</Ship Country>
<OrderDetailsData>
<OrderDetails>
<Order ID>10249</Order ID>
<ProductID>14</ProductID>
<UnitPrice>18.6</UnitPrice>
<Quantity>9</Quantity>
<Discount>0</Discount>
</OrderDetails>
<OrderDetails>
<Order ID>10249</Order ID>
<ProductID>51</ProductID>
<UnitPrice>42.4</UnitPrice>
<Quantity>40</Quantity>
<Discount>0</Discount>
</OrderDetails>
</OrderDetailsData>
</OrderData>
</ArrayOfOrderData>


Final Application Look



Working With Nested Grid Views

Figure 1

Working With Nested Grid Views

Figure 2

Let's start joining the pieces to accomplish this. I have shown the final look and feel of our application in Figure 1 and Figure 2.

Data Model



XML has the two pieces of data i.e. Order and OrderDetails which we will be showing in the two Grid Views. So I took a path to create two data models for each object. I have created OrderModel and OrderDetailsModel class to old those values for us.

OrderModel.cs





using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace OrderDetailsXMLGridView.BAL
{
public class OrderModel
{
public string OrderID { get; set; }
public string CustomerID { get; set; }
public string EmployeeID { get; set; }
public string OrderDate { get; set; }
public string Freight { get; set; }
public string ShipCountry { get; set; }

public OrderDetailsModel OrderDetail { get; set; }
}

public class OrderDetailsModel {
public string OrderID { get; set; }
public string ProductID { get; set; }
public string UnitPrice { get; set; }
public string Quantity { get; set; }
public string Discount { get; set; }
}
}



Data models are self-explanatory as they work as Data value objects.

Implementation



Now we have our data store ready and data models ready, let's have the implementation to load the data from XML to values objects as mentioned above. I am using LINQ here to load and query the XML but if you want to use traditional way of getting data from XML feel free to use that.

OrderDetailsImpl.cs





using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Xml.Linq;

namespace OrderDetailsXMLGridView.BAL
{
public class OrderDetailImpl
{

private string xml;
public OrderDetailImpl()
{

xml = HttpContext.Current.Server.MapPath("~/App_data/OrderDetailsData.xml");
}

public List getOrderInfo()
{
List orders = new List();

XElement ele = XElement.Load(xml);
orders = (from order in ele.Descendants("OrderData")
select new OrderModel()
{
OrderID = order.Element("OrderID").Value,
CustomerID = order.Element("CustomerID").Value,
EmployeeID = order.Element("EmployeeID").Value,
OrderDate = order.Element("OrderDate").Value,
Freight = order.Element("Freight").Value,
ShipCountry = order.Element("ShipCountry").Value
}).ToList();

return orders;
}

public List getOrderDetails(string orderId)
{
List orderdetails = new List();

XElement ele = XElement.Load(xml);

orderdetails = (from order in ele.Descendants("OrderData").Elements("OrderDetailsData").Elements("OrderDetails")
where order.Element("OrderID").Value == orderId
select new OrderDetailsModel()
{
OrderID = order.Element("OrderID").Value,
ProductID = order.Element("ProductID").Value,
UnitPrice = order.Element("UnitPrice").Value,
Quantity = order.Element("Quantity").Value,
Discount = order.Element("Discount").Value,

}).ToList();
return orderdetails;
}
}
}



I have two methods as shown above to load and query the data from XML. getOrderInfo() is to load the data from XML to OrderModel object for Order which is our parent data as shown in figure 1.

getOrderDetails(string orderId) is to load the data from XML to OrderDetailsModel object for Order details which is our child data as shown in figure 2.

Both the methods return the IEnumerable data (List) which we can bind with our grid views. Now we have our objects ready to retrieve the data from XML, let's look into the UI with nested grid view.

Default.aspx Design



Before looking into the design and source of our aspx, let's take a look into the ObjectDataSource Data control. I have decided to use the ObjectDataSource as our objects methods are ready and we can go ahead and tie them together instead of binding our gridview by yourself.

Design



Working With Nested Grid Views

Figure 3

In figure 3 you will notice the Grid View and ObjectDataSource control. I have bound the Grid View using the ObjectDataSource using the Smart tag of Grid View control. When you choose the new data source from Smart tag it will prompt you to choose the Data source type as show below.

Working With Nested Grid Views

Figure 4

When you choose and configure the ObjectDataSource it will open the Wizard to choose the business object which will return you the data in form on Object value (OrderModel) in our case. It will prompt you to choose the Data Methods type from that object, we have getOrderInfo() methods which is our SELECT data method as show in below figures.

Working With Nested Grid Views


Working With Nested Grid Views

Your parent Grid View is bounded with the Data source and it will show the Order Data from the XML.

Nested Grid View



We need to place the second grid view as Itemtemplate of the first gird view. You can do either from design or you can write in the source of aspx page. Let me put Default.aspx source code here and go over piece by piece.

Default.aspx Source




<%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true"
CodeBehind="Default.aspx.cs" Inherits="OrderDetailsXMLGridView._Default" %>

<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
<script language="javascript" type="text/javascript">

function switchViews(obj, row) {
var div = document.getElementById(obj);
var img = document.getElementById('img' + obj);

if (div.style.display == "none") {
div.style.display = "inline";
if (row == 'alt') {
img.src = "Images/expand_button_white_alt_down.jpg";
}
else {
img.src = "Images/Expand_Button_white_Down.jpg";
}
img.alt = "Close to view other Details";
}
else {
div.style.display = "none";
if (row == 'alt') {
img.src = "Images/Expand_button_white_alt.jpg";
}
else {
img.src = "Images/Expand_button_white.jpg";
}
img.alt = "Expand to show Order Details";
}
}
</script>
</asp:Content>
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
<h2>
Welcome to Nested Grid View Tutorial
</h2>
<p>
<asp:GridView ID="GridView1" runat="server" DataSourceID="ObjectDataSource1"
AutoGenerateColumns="False" CellPadding="4" ForeColor="#333333"
GridLines="None" Width="753px" DataKeyNames="OrderID"
OnRowDataBound="GridView1_RowDataBound">
<AlternatingRowStyle BackColor="White" ForeColor="#284775" />
<Columns>
<asp:TemplateField HeaderText="Order Details">
<ItemTemplate>
<a href="javascript:switchViews('div<%# Eval("OrderID") %>', 'one');">
<img id="imgdiv<%# Eval("OrderID") %>" alt="Click to show/hide Details" border="0"
src="Images/expand_button_white.jpg" />
</a>
</ItemTemplate>
<AlternatingItemTemplate>
<a href="javascript:switchViews('div<%# Eval("OrderID") %>', 'alt');">
<img id="imgdiv<%# Eval("OrderID") %>" alt="Click to show/hide Details" border="0"
src="Images/expand_button_white_alt.jpg" />
</a>
</AlternatingItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="OrderID" HeaderText="Order ID"
SortExpression="OrderID">
</asp:BoundField>
<asp:BoundField DataField="CustomerID" HeaderText="Customer ID"
SortExpression="CustomerID" />
<asp:BoundField DataField="EmployeeID" HeaderText="Employee ID"
SortExpression="EmployeeID" />
<asp:BoundField DataField="OrderDate" HeaderText="Order Date"
SortExpression="OrderDate" />
<asp:BoundField DataField="Freight" HeaderText="Freight"
SortExpression="Freight" />
<asp:BoundField DataField="ShipCountry" HeaderText="Ship Country"
SortExpression="ShipCountry" />
<asp:TemplateField>
<ItemTemplate>
<tr>
<td colspan="100%">
<div id="div<%# Eval("OrderID") %>" style="display: none; position: relative; left: 25px;">
<asp:GridView ID="GridView2" runat="server" Width="80%" AutoGenerateColumns="false"
EmptyDataText="No Order Details.">
<EditRowStyle BackColor="#999999" />
<FooterStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
<HeaderStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
<PagerStyle BackColor="#284775" ForeColor="White" HorizontalAlign="Center" />
<RowStyle BackColor="#F7F6F3" ForeColor="#333333" HorizontalAlign="Center" />
<SelectedRowStyle BackColor="#E2DED6" Font-Bold="True" ForeColor="#333333" />
<SortedAscendingCellStyle BackColor="#E9E7E2" />
<SortedAscendingHeaderStyle BackColor="#506C8C" />
<SortedDescendingCellStyle BackColor="#FFFDF8" />
<SortedDescendingHeaderStyle BackColor="#6F8DAE" />
<Columns>
<asp:BoundField ShowHeader="true" HeaderText="Order ID" DataField="OrderID" />
<asp:BoundField ShowHeader="true" HeaderText="Product ID" DataField="ProductID" />
<asp:BoundField ShowHeader="true" HeaderText="Unit Price" DataField="UnitPrice" />
<asp:BoundField ShowHeader="true" HeaderText="Quantity" DataField="Quantity" />
<asp:BoundField ShowHeader="true" HeaderText="Discount" DataField="Discount" />
</Columns>
</asp:GridView>
</div>
</td>
</tr>
</ItemTemplate>
</asp:TemplateField>
</Columns>
<EditRowStyle BackColor="#999999" />
<FooterStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
<HeaderStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
<PagerStyle BackColor="#284775" ForeColor="White" HorizontalAlign="Center" />
<RowStyle BackColor="#F7F6F3" ForeColor="#333333" HorizontalAlign="Center" />
<SelectedRowStyle BackColor="#E2DED6" Font-Bold="True" ForeColor="#333333" />
<SortedAscendingCellStyle BackColor="#E9E7E2" />
<SortedAscendingHeaderStyle BackColor="#506C8C" />
<SortedDescendingCellStyle BackColor="#FFFDF8" />
<SortedDescendingHeaderStyle BackColor="#6F8DAE" />
</asp:GridView>
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
SelectMethod="getOrderInfo"
TypeName="OrderDetailsXMLGridView.BAL.OrderDetailImpl">
</asp:ObjectDataSource>
</p>
</asp:Content>



Parent and Child Grid has the relationship key i.e. OrderID. If you look into the source you will see the child grid is wrapped with Div tag which has the Unique Id based on the OrderID Key from the ObjectDataSource. We will be hiding and showing the nested grid data with the help of the Div tag.

I am expanding and collapsing the Div using the Java Script. Java script is just using the Div tag style and setting its property to hide or show.

We have our layout ready to show the parent and child data with Expanding and Collapsing features. But still the nested grid is not bound with any DataSource then how it will fill up with the child data (Order Details).

When we click on the GridView it calls the GridView1_RowDataBound event which we will be using to bind the child grid with OrderDetails data.

Default.aspx.cs Code behind





using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using OrderDetailsXMLGridView.BAL;

namespace OrderDetailsXMLGridView
{
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
OrderDetailImpl impl = new OrderDetailImpl();
impl.getOrderInfo();
}

protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{

if (e.Row.RowType == DataControlRowType.DataRow)
{
GridView gv = (GridView)e.Row.FindControl("GridView2");
OrderDetailImpl objData = new OrderDetailImpl();
ObjectDataSource objDataSrc;
objDataSrc = new ObjectDataSource();
objDataSrc.TypeName = objData.GetType().FullName;
OrderModel rowView = (OrderModel)e.Row.DataItem;

string dataItem = rowView.OrderID;
objDataSrc.SelectMethod = "getOrderDetails";
objDataSrc.SelectParameters.Add("OrderId", dataItem);
objDataSrc.DataBind();
gv.DataSource = objDataSrc;
gv.DataBind();
}
}
}
}


On page load we are loading the XML data into our Models so that ObjectDataSource Datasource will have data to show on the grid. RowDataBound event is called when we click on the first column which is ItemTemplate and it is bound with OrderID column.

When the event is called it pass the OrderId value as event argument which we will pass to our second methods as shown above to get the child data from XML i.e. OrderDetails.


Comments

Author: abhishek saxena01 May 2013 Member Level: Silver   Points : 0

Dear Kapil

Thanks for such a wonderful code.

Please guide me how can we put a delete function in the same code.

Thanks in Advance.

Author: Kapil01 May 2013 Member Level: Gold   Points : 2

Hi Sudeep,

I have implemented the delete function also in grid and i think you are looking for the same.

You can create one grid column with button or image and need to wire it up with back end code.

send me your email id will send you code snippet.

-Kapil

Author: abhishek saxena01 May 2013 Member Level: Silver   Points : 2

Dear Kapil Thanks alot for your support and help
my id is sudeep.nigam@hotmail.com

I am facing an issue also as I'll get your mail I'll attach the error file also inthat as in reply. Kindly help me.

Thanks & Regards

Author: abhishek saxena02 May 2013 Member Level: Silver   Points : 0

Dear Kapil

The XML that you are using is different from what I am using please share your email id with me so that I can send you the xml format.

Please guide me further.

Thanks



  • Do not include your name, "with regards" etc in the comment. Write detailed comment, relevant to the topic.
  • No HTML formatting and links to other web sites are allowed.
  • This is a strictly moderated site. Absolutely no spam allowed.
  • Name:
    Email: