DataGrid - Master/Child/Slave Details in ASP.NET, C# - Expand/Collapse Rows (Master/Detail View)
DataGrid for Master/Child (Master/Slave) Details Using
ASP.NET, C#, and JavaScript (Expand / Collapse Rows) Version 1
-------------------------------------------------------------------------
Version 2 exists for this article:
http://www.progtalk.com/ViewArticle.aspx?ArticleID=16
Looking for this code in VB.NET?
VB.NET Version
This grid will allow users to view master/child or master/slave details of records from a SQL database. It will allow them to view the details through the client side script, and will maintain the state of expanded rows during any postback. Here is sample screen shot of how the grid will look:
Before Expanding Rows: The grid will load with a + next to all grouped items.

After Expanding Rows: The selected rows will expand, and the + will change to a - on client side using javascript.

What Happens if you change the page? The new page is loaded with everthing collapsed.

Expanding Rows on new page: The new page will expand the selected rows, and the + will change to a - client side using javascript.

What happens if a non grid event is fired? This will not effect how the grid is being viewed by the user, as it maintains the expansion/collapse state.

--------------------------------------------------------------------------------------------------------------------
Background
This is a custom grid which can be made into a control. For now it was done with Northwind and an asp.net page. In the future I will most likely make this into a custom control.
--------------------------------------------------------------------------------------------------------------------
Using the code
The following code is very basic, and will allow a user to view a grid in a master/child manner. Most of the code has notes, and is pretty easy to understand. The trick is to add a new row below the row the grid generates. Inside that row we create
a div section of the details. Then we bind it with the javascript to show and hide the div sections. This will allow client side viewing of the details giving a more rich feel.
To use the code, all you have to do is set your connection string in the default.aspx page and run it. If you wish to use it with your own database, change the query in the following methods:
1. BindData(); //For the Master view section
2. DataGrid1_ItemDataBound(); //For the Child view section.
Good Luck!!!
Note: The javascript code functions are on a js file which can be found once you download the full source code. If you guys find any bugs, please feel free to let me know, so I can modify the code for others.
* I do not hold any responsibility for the use of this code. Please use at your own risk *
--------------------------------------------------------------------------------------------------------------------
private string connectionstring = "server=SERVERNAME;database=Northwind;uid=USERNAME;password=PASSWORD;";
private void Page_Load(object sender, System.EventArgs e)
{
this.LabelPostBack.Text = "";
if ( !Page.IsPostBack )
{
BindData();
}
else
{
if ( Request["__EVENTTARGET"] != null)
{
string strEventTarget = Request["__EVENTTARGET"].ToString().ToLower();
if ( strEventTarget.IndexOf("datagrid1") == -1)
{
ViewState["Mode"] = "ShowDetails";
BindData();
}
else
{
ViewState["Mode"] = null;
}
}
}
}
private void ButtonSample_Click(object sender, System.EventArgs e)
{
LabelPostBack.Text = "A Postback has occurred. txtExpandedFields has contents: <BR/><B>" +
txtExpandedFields.Text + "</B>";
}
private void BindData()
{
string QueryString = "SELECT OrderID, CustomerID, EmployeeID, ShipName, " +
"ShipAddress, ShipCity, ShipRegion, ShipPostalCode, ShipCountry FROM Orders";
System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection();
try
{
conn.ConnectionString = connectionstring;
if ( conn.State == System.Data.ConnectionState.Closed )
{
conn.Open();
}
System.Data.SqlClient.SqlDataAdapter adapter =
new System.Data.SqlClient.SqlDataAdapter( QueryString, conn);
DataSet ds = new DataSet();
adapter.Fill( ds );
DataGrid1.DataSource = ds;
DataGrid1.DataBind();
}
catch (Exception ex1)
{
Response.Write("An Error has occurred. <BR/>");
Response.Write(ex1.Message.ToString());
Response.End();
}
finally
{
if ( conn.State == System.Data.ConnectionState.Open )
{
conn.Close();
}
}
}
private DataSet RunQuery(string QueryString)
{
System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection();
try
{
conn.ConnectionString = connectionstring;
if ( conn.State == System.Data.ConnectionState.Closed )
{
conn.Open();
}
System.Data.SqlClient.SqlDataAdapter adapter =
new System.Data.SqlClient.SqlDataAdapter( QueryString, conn);
DataSet ds = new DataSet();
adapter.Fill( ds );
return ds;
}
catch (Exception ex1)
{
Response.Write("An Error has occurred. <BR/>");
Response.Write(ex1.Message.ToString());
Response.End();
return null;
}
finally
{
if ( conn.State == System.Data.ConnectionState.Open )
{
conn.Close();
}
}
}
private void DataGrid1_ItemDataBound(object sender, System.Web.UI.WebControls.DataGridItemEventArgs e)
{
if ( e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem )
{
string DetailsQuery = "SELECT C.CompanyName, OD.UnitPrice, " +
"OD.Quantity, OD.Discount, E.FirstName, E.LastName " +
"FROM [Order Details] as OD, [Customers] as C, [Orders] as O," +
"[Employees] as E " +
"where OD.OrderID = O.OrderID and O.CustomerID = C.CustomerID " +
"and O.EmployeeID = E.EmployeeID and " +
"O.OrderID = '" + e.Item.Cells[1].Text + "' and " +
"C.CustomerID = '" + e.Item.Cells[2].Text + "' and " +
"E.EmployeeID = '" + e.Item.Cells[3].Text + "'";
DataSet ds = this.RunQuery(DetailsQuery);
DataGrid NewDg = new DataGrid();
NewDg.AutoGenerateColumns = true;
NewDg.Width = Unit.Percentage(100.00);
NewDg.DataSource = ds;
NewDg.DataBind();
SetProps(NewDg);
System.IO.StringWriter sw = new System.IO.StringWriter();
System.Web.UI.HtmlTextWriter htw = new System.Web.UI.HtmlTextWriter(sw);
NewDg.RenderControl( htw );
string DivStart = "<DIV id='uniquename" + e.Item.ItemIndex.ToString() +"' style='DISPLAY: none; HEIGHT: 1px;'>";
string DivBody = sw.ToString();
string DivEnd = "</DIV>";
string FullDIV = DivStart + DivBody + DivEnd;
int LastCellPosition = e.Item.Cells.Count - 1;
int NewCellPosition = e.Item.Cells.Count - 2;
e.Item.Cells[0].ID = "CellInfo" + e.Item.ItemIndex.ToString();
if ( ViewState["Mode"] != null && ViewState["Mode"].ToString() == "ShowDetails")
{
if ( this.txtExpandedFields.Text.IndexOf(e.Item.Cells[0].ClientID) != -1 )
{
FullDIV = FullDIV.Replace("DISPLAY: none","DISPLAY: block");
e.Item.Cells[0].Text = "<A>-</A>";
}
}
if (e.Item.ItemType == ListItemType.Item)
{
e.Item.Cells[LastCellPosition].Text = e.Item.Cells[LastCellPosition].Text +
"</td><tr><td bgcolor='f5f5f5'></td><td colspan='" +
NewCellPosition +"'>" + FullDIV;
}
else
{
e.Item.Cells[LastCellPosition].Text = e.Item.Cells[LastCellPosition].Text +
"</td><tr><td bgcolor='d3d3d3'></td><td colspan='" +
NewCellPosition +"'>" + FullDIV;
}
e.Item.Cells[0].Attributes["onclick"] = "HideShowPanel('uniquename" +
e.Item.ItemIndex.ToString() + "'); ChangeHLText('" +
e.Item.Cells[0].ClientID + "'); SetExpanded('" +
e.Item.Cells[0].ClientID + "','" +
txtExpandedFields.ClientID + "');";
e.Item.Cells[0].Attributes["onmouseover"] = "this.style.cursor='hand'";
e.Item.Cells[0].Attributes["onmouseout"] = "this.style.cursor='hand'";
}
}
private void DataGrid1_PageIndexChanged(object source, System.Web.UI.WebControls.DataGridPageChangedEventArgs e)
{
txtExpandedFields.Text = "";
DataGrid1.CurrentPageIndex = e.NewPageIndex;
BindData();
}
public void SetProps(System.Web.UI.WebControls.DataGrid DG)
{
DG.Font.Size = 8;
DG.Font.Bold = false;
DG.Font.Name = "tahoma";
/*******************Professional 2********************
DG.GridLines = GridLines.Both;
DG.CellPadding = 3;
DG.CellSpacing = 0;
DG.BorderColor = System.Drawing.Color.FromName("#CCCCCC");
DG.BorderWidth = System.Web.UI.WebControls.Unit.Pixel(1);
DG.HeaderStyle.BackColor = System.Drawing.Color.SteelBlue;
DG.HeaderStyle.ForeColor = System.Drawing.Color.White;
DG.HeaderStyle.Font.Bold = true;
DG.HeaderStyle.Font.Size = 8;
DG.HeaderStyle.Font.Name = "tahoma";
DG.ItemStyle.BackColor = System.Drawing.Color.LightSteelBlue;
}
------------------------------------------------------------------------
This article exposes the ease of implenting div in the code, and using client side
script to show/hide information. It is more simpler to do then most would think.
The key point is that once a datagrid is generated, each column endswith the td tag.
You can force html after the td tag to create a new row holding the div with your
detailed information. This can be seen in the Item Databound method.
The code was done in VS2003 with Framework 1.1. I did not use VS2005 with GridView, though it can be easily modified.
Was this article helpful? Don't forget to rate it. Ratings helps community members identify top & useful articles.