![]() |
Web Development »
ASP.NET »
General
Intermediate
License: The Code Project Open License (CPOL)
Creating a DataGrid that expands and collapses like a tree controlBy Ahmed AbdelgawadA Custom DataGrid Paging Techniuque |
Windows, .NET, ASP.NET, Visual Studio, Dev
|
||||||||
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||

The TreeGridDemo demonstrates a custom method for DataGrid paging. The DataGrid behaves much like a tree control, which collapses or expands sections of the grid rows. This way of paging is useful when the grid contains too many records and you have to render all the records in on page because ,for example, you need to display a summary underneath the grid like total or average or etc. By this way the user will be able to either see the summary or even open all or part of the sections of the grid.
I use both server sdie and client side script to do this functionality.The client side script is responsible for showing and hiding a number of grid rows according to the number of rows per section. Also, the script sets the current state of the section in hidden fields for server side state presesrvation. This is important beacause when the grid is bound to its datasource it loses its client state as a result of being rerendered. This is the key method of the client script:
//******************************************************************************************************** //CALLED EVERY TIME YOU COLLAPSE OR EXPAND THE GRID ITEMS //********************************************************************************************************
function ExpandCollapse(sender,gridClientID,rowIndex,numItemsPerPage) { var grid=document.getElementById(gridClientID); for(i=rowIndex+1;i<(rowIndex+numItemsPerPage+1);i++) { try { //SHOW OR HIDE THE ROW ACCORDING TO CURRENTSTATEgrid.rows[i].style.display=sender.value=='-'?'none':'block'; //SET THE HIDDEN VALUE FOR SERVER SIDE STATE PRSERVATION hiddenShowHideStatus=grid.rows[i].cells[0].children[0]; if(hiddenShowHideStatus&&hiddenShowHideStatus.type=='hidden') { hiddenShowHideStatus.value=sender.value=='-'?'none':'block'; } } catch(ex) { break; } } //CONVERT THE TEXT OF THE BUTTON CONTROL FROM + TO - ANDVICEVERSA sender.value=(sender.value=='-')?'+':'-'; }
In the server side I render separator rows in the PreRender event of the DataGrid. The separator rows contains two cells. One cell for rendering the button control that fires client side event for collapsing or expanding the grid sections, and the other cell is for section numbering ;"From x to y". The key method on the server side is below:
private void treeGridToManage_PreRender(object sender, EventArgs e) { PopulateGridSeparators((DataGrid)sender); } private void PopulateGridSeparators(DataGrid treeGridToManage) { int pagerCellColSpan=0; int numItemsPPage=int.Parse(treeGridToManage.Attributes["NumItemsPPage"]); if(treeGridToManage.Items.Count>0) { pagerCellColSpan=treeGridToManage.Items[0].Cells.Count; int numSeparatorsCreated=0; for(int index=1;index<treeGridToManage.Items.Count+numSeparatorsCreated;index+=(numItemsPPage+1),numSeparatorsCreated++) { string clientText=""; clientText+="<INPUT TYPE =BUTTON ID=BTN"+index+" "; clientText+="VALUE=\"-\" "; clientText+="ONCLICK=\"javascript:ExpandCollapse(this,'"+treeGridToManage.ClientID+"',"+index+","+numItemsPPage+")\" "; clientText+="STYLE=\"BORDER-RIGHT: gray thin solid; BORDER-TOP: gray thin solid; BORDER-LEFT: gray thin solid; WIDTH: 25px; BORDER-BOTTOM: gray thin solid; HEIGHT: 28px\""; clientText+=">"; TableCell cell=new TableCell(); cell.Text=clientText; cell.Width=30; cell.BorderStyle=BorderStyle.Dotted; TableCell cell2=new TableCell(); cell2.ColumnSpan=pagerCellColSpan; cell2.HorizontalAlign=HorizontalAlign.Center; cell2.Text="From "+(index-numSeparatorsCreated)+" To "+(((index-numSeparatorsCreated)+numItemsPPage-1)); cell2.BorderStyle=BorderStyle.Dotted; DataGridItem item=new DataGridItem(0,0,ListItemType.Separator); item.BackColor=Color.LightGray; item.Cells.Add(cell); item.Cells.Add(cell2); treeGridToManage.Controls[0].Controls.AddAt(index,item); } } }
I have spoken about state preservation between the client and the server. I do this by holding hidden fields within the grid, these hidden fields holds the last state of every section on the client (wherther it is Collapsed or Expanded). I read the values of these hidden fields in an ArrayList before binding to the grid, after binding I set the formerly read values againg in the newly rendered hidden fields. When the page is loaded on the client side I read the values of the hidden fields and set the state of the different sections of the grid according to hidden fields. In brief I do three action for state preservation:
class DataGridTemplate : System.Web.UI.ITemplate { ListItemType templateType; string columnName; public DataGridTemplate(ListItemType type, string colname) { templateType = type; columnName = colname; } public void InstantiateIn(System.Web.UI.Control container) { // The Hidden Field Built Dynamically HtmlInputHidden hiddenShowHideStatus=new HtmlInputHidden(); hiddenShowHideStatus.Value="none"; hiddenShowHideStatus.ID="hiddenShowHideStatus"; switch(templateType) { case ListItemType.Item: case ListItemType.EditItem: container.Controls.Add(hiddenShowHideStatus); break; } } }
public void ManageGridBinding() { treeGridToManage.PreRender+=new EventHandler(treeGridToManage_PreRender); ArrayList stateList=new ArrayList(); for(int i=0;i<treeGridToManage.Items.Count;i++) { HtmlInputHidden hiddenTreeGridState=(HtmlInputHidden)treeGridToManage.Items[i].Cells[0].FindControl("hiddenShowHideStatus"); if(hiddenTreeGridState!=null) { stateList.Add(hiddenTreeGridState.Value); } } treeGridToManage.DataBind(); if(stateList.Count>0) { for(int i=0;i<stateList.Count;i++) { HtmlInputHidden hiddenTreeGridState=(HtmlInputHidden)treeGridToManage.Items[i].Cells[0].FindControl("hiddenShowHideStatus"); if(hiddenTreeGridState!=null) { hiddenTreeGridState.Value=stateList[i].ToString(); } } } }
this.onload=function() { grids=new Array('DataGrid1','DataGrid2'); for(j=0;j<grids.length;j++) { var grid=document.getElementById(grids[j]); if(grid) { for(i=0;i<grid.rows.length;i++) { hiddenShowHideStatus=grid.rows[i].cells[0].children[0]; if(hiddenShowHideStatus) { if(hiddenShowHideStatus.type=='hidden') { grid.rows[i].style.display=hiddenShowHideStatus.value=='none'?'none':'block'; } } } SetButtonState(grid); } } };
You donot have to worry about all of that code, all you have to do to get a grid behaving this way is just include TreeGridUIManager.cs in your project and this file contains all code required for the following tasks:
The DataGridTemplate class is Responsible for
The TreeGridScriptRenderer class is responsible for creating dynamic client side script
To get one or more DataGrids behaving this way on your page do the following:
sqlDataAdapter1.Fill(dataSet11); sqlDataAdapter2.Fill(dataSet11); //Don't call datagrid.DataBind do the following: //Create Instance TreeGridUIManager _TreeGridUIManager=new TreeGridUIManager(); //Define Grids To Behave Like Tree passing section rowcount for every grid _TreeGridUIManager.AddGridToManage(DataGrid1,5); _TreeGridUIManager.AddGridToManage(DataGrid2,7); //Call _TreeGridUIManager.DataBind();
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 10 Apr 2006 Editor: |
Copyright 2006 by Ahmed Abdelgawad Everything else Copyright © CodeProject, 1999-2009 Web20 | Advertise on the Code Project |