Click here to Skip to main content
15,867,568 members
Articles / Web Development / ASP.NET

Convert .NET Class to a DataGrid

Rate me:
Please Sign up or sign in to vote.
4.42/5 (15 votes)
18 Jul 20053 min read 123.2K   1.4K   69   23
Create a DataGrid from an ArrayList which is a collection of a specific class type. Read all attributes of a class in a nested hierarchy and create datacolumns from that or just select a few attributes as datacolumns and ignore others. Have unique readable datacolumn names finally in the datatable.

Image 1

Introduction

Everywhere, you would see the OOPS concept and emphasizing you to work the oops, but ask anyone how to create a DataGrid from an ArrayList which is a collection of the same class type, you will find people saying go for DataSet or create DataTable rows from these ArrayList items. I too faced the same problem when I was asked to design a DataGrid and what I got from the C# team was just an ArrayList.

I'm damn sure, one of you who is reading this article would say that it is still possible in DataGrid and one can use the "." operator, but if I ask you how to do sorting and paging on them, and what if the item is inside the ArrayList, then you might not have any answer.

I am not saying this is 100% right, but this is one of the easiest ways of converting an ArrayList (which is a collection of a specific class type) to a DataTable, where you can have sorting, paging and filtering on the DataGrid. Since whatever DataTable you form finally has valid column names.

Overview

What Is With Us?

ArrayList - arrEmployees 
 Item[0] - (Type EmployeeCmpnt)
 Item[1] - (Type EmployeeCmpnt)
 Item[2] - (Type EmployeeCmpnt)
 ...

EmployeeCmpnt Structure

Image 2

What We Want?

If the first item of the ArrayList contains following
 Employeecmpnt.NameCmpnt.FirstName = "John"
 Employeecmpnt.NameCmpnt.LastName = "Abraham"
 Employeecmpnt.HomeAddress.AddressDetailsCmpnt.Address1 = 
                                      "1520 Magnolia Apts"
 ...
and the second item contains following
 Employeecmpnt.NameCmpnt.FirstName = "Peter"
 Employeecmpnt.NameCmpnt.LastName = "Paul"
 Employeecmpnt.HomeAddress.AddressDetailsCmpnt.Address1 = 
                                       "1870 Meridan Pkwy"
 ....

The Expected DataGrid Output is Shown Below

Image 3

Implementing the Approach

FYI The DataTable column names finally when it is implemented
 EmployeeCmpnt__NameCmpnt__FirstName
 EmployeeCmpnt__NameCmpnt__LastName
 EmployeeCmpnt__HomeAddress__AddressDetailCmpnt__Address1
 EmployeeCmpnt__OfficeAddress__AddressDetailCmpnt__Address1

You can see that every hierarchy is separated by double underscores "__". Please note that it is the exposed attribute name and not the type which is used. (I mean to say that it is the "HomeAddress" that is used and not the type "AddressCmpnt".)

Steps to Convert an ArrayList to a DataGrid

In .cs

C#
ArrayList arrEmployee = new ArrayList();
//Fill data in arrEmployee
C#
arrEmployee.Add(new EmployeeCmpnt("Peter",
                               "Paul","1520.."));
...
....
C#
//Create instance of grid utility class 
GridViewClass gridView = new GridViewClass();
C#
//Create specific columns (DataColumns) OR 
//create all attributes of a class 
//as column (AutoNestedColumns)
//Set all attributes as data columns //ALL OF THE ATTRIBUTES, 
                                     //MAXIMUM SIZE.
gridView.AutoNestedColumns = true;
//Create specific columns //LESS COLUMNS, LESS DATATABLE SIZE
//gridView.DataColumns  = "EmployeeCmpnt__NameCmpnt__FirstName,
                   EmployeeCmpnt__NameCmpnt__LastName,
                   EmployeeCmpnt__HomeAddress__AddressDetailCmpnt__*";
C#
//Call the CreateDataTable() method which does the conversion job.
C#
DataTable dtEmployee = gridView.CreateDataTable(arrEmployee);
dgEmployee.DataSource = dtEmployee;
dgEmployee.DataBind();

In .aspx

ASP.NET
<asp:TemplateCOLUMN HeaderText="First Name" 
    SortExpression='EmployeeCmpnt__NameCmpnt__FirstName'  >
    <ITEMTEMPLATE>
     <asp:Label id="Label8"  style="text-align:left" 
         Runat="server" Text='<%# DataBinder.Eval(Container, 
             "DataItem.EmployeeCmpnt__NameCmpnt__FirstName") %>' />
    </ITEMTEMPLATE>
</asp:TemplateCOLUMN>

How It Is Done

It is the method CreateDataTable() which through reflection finds out the type of the class, its attributes and loops through all the nested children and creates a DataTable. Click here to see the code of GridView.cs.

Can I Have Paging and Sorting?

Yeah sure! That's why all this trouble was taken, since the DataTable column names are valid names, you can straightaway use them in the "SortExpression" of DataGrid.

C#
protected void dgEmployee_Sort(Object sender, 
                   DataGridSortCommandEventArgs e)
{
  //"EmployeeCmpnt__NameCmpnt__LastName"
  dtEmployee.DefaultView.Sort = e.SortExpression; 
  dgEmployee.DataSource = dtEmployee;
  dgEmployee.DataBind();   
}

Can I Use This in My Custom ASP Grid Control and Use It the Way I Want

Definitely, you can add a method "CreateDataTable()" to your DataGrid custom control and can have two exposed attributes like "DataColumns" and "AutoNestedColumns" which can take further inputs. For example:

C#
public class MyDataGrid : System.Web.UI.WebControls.DataGrid
{
  public string DataColumns
  {
    get... set...
  }
  public bool AutoNestedColumns
  {
    get... set...
  }
  public DataTable CreateDataTable(..)
  {
     ..
  }
}

By the way, you will be happy to know that I have already done this and will soon post my custom DataGrid in my next article but only if I get a good rating for my current article :), moreover, I needed this submission to explain how a DataGrid can be created from a collection of classes.

You know the custom DataGrid control I'm talking about has features like multi column sorting, freezing headers/rows/columns, etc. and that too in a very easy way.

Courtesy

You may use the code given here by any means and in whatever way you want, but I will truly appreciate if you keep the author's name along with the code.

History

  • 19th July, 2005: Initial version

License

This article has no explicit license attached to it, but may contain usage terms in the article text or the download files themselves. If in doubt, please contact the author via the discussion board below. A list of licenses authors might use can be found here.


Written By
Team Leader Royal Bank of Scotland
India India
Total 11+ years of experience in Software Development. Expertise in .net (C#, asp.net, controls making, webservice, ado.net, xml/xsl, assemblies, rational XDE etc.) also UML, Design Patterns, ASP, Javascript, VbScript, Dhtml, CSS etc.

Member of Planet-Source-Code.com, www.brainbench.com and many other and have submitted several snippets/sample applications on the web.

Email:tittlejoseph@gmail.com

Comments and Discussions

 
GeneralUpdate Pin
e.blanchette25-Apr-08 9:20
e.blanchette25-Apr-08 9:20 
Here is what I found while playing with this gridview.cs For it to send back the table with the correct order of tables you have to loop through the columns list, or else it takes the properties of your object one after the other regardless of what you sent as columns. Just a foreach loop to add.

public DataTable CreateDataTable(object fromObj, string colPrefix, ref DataTable dtExisting)
{
if(fromObj == null) return dtExisting;
DataTable dt;

System.Type t = fromObj.GetType();

//generate column prefix
if(dtExisting == null)
{
if(t.IsArray || t == typeof(ArrayList) || t == typeof(Hashtable))
colPrefix = "";
else
colPrefix = fromObj.GetType().Name;

dt = new DataTable(colPrefix);
}
else
{
dt = dtExisting;

if ( colPrefix == "" )
colPrefix += fromObj.GetType().Name;
}

//check if need to be fetched.
if ( autoNestedColumns == false )
if ( colPrefix != "" )
if(ComponentToUse(colPrefix) == false && ComponentToFetch(colPrefix) == false ) return dtExisting;

// check whether the the type is a collection.
if(t.IsArray || t == typeof(ArrayList) || t == typeof(Hashtable))
{
ICollection arrObj = (ICollection)fromObj;
if(t == typeof(Hashtable))
{
arrObj = ((Hashtable) arrObj).Values;
}

foreach(object arrObjVal in arrObj)
{
if(arrObjVal != null)
{
//add new row to the table
DataRow dr = dt.NewRow();
dt.Rows.Add(dr);
dt = CreateDataTable(arrObjVal, colPrefix, ref dt);
}
}
}
else
{
DataRow dr;
//if row already exist then use the previous row
if(dt.Rows.Count>0)
dr = dt.Rows[dt.Rows.Count-1];
else
{
dr = dt.NewRow();
dt.Rows.Add(dr);
}



//loop through the columns list and create columns. Modification du code original pour que le programme prenne le même ordre que le csv
foreach (String sElement in columnsList)
{
//sElement va avoir l'air de ça : Client__sFirstName
//ça doit avoir l'air de : sFirstName

String sElementCurrentIteration = sElement.Remove(0, sElement.LastIndexOf("_")+1);

// Loop through all the properties and create columns and put the value in it.
foreach (PropertyInfo pi in fromObj.GetType().GetProperties())
{
if (pi.Name.IndexOf(sElementCurrentIteration) != -1)
{
if (pi.PropertyType.IsPrimitive || pi.PropertyType == typeof(string)
|| pi.PropertyType == typeof(decimal) || pi.PropertyType == typeof(DateTime))
{
// this property is a primitive type or types that can be used to fill the
// columns. Add the column to the table and set the values.
string colName = colPrefix + "__" + pi.Name;

//Only including columns in data table which are listed in aspx
if (dataColumns == "" || autoNestedColumns == true || columnsList.Contains(colName) || columnsList.Contains(colPrefix + "__*"))
{
int colIndex = 0;
if (dt.Columns.Contains(colName))
{
colIndex = dt.Columns.IndexOf(colName);
}
else
{
colIndex = dt.Columns.Count;
dt.Columns.Add(new DataColumn(colName, pi.PropertyType));
}
dr[colIndex] = pi.GetValue(fromObj, new object[] { });
}
}
else if (pi.PropertyType.IsArray || pi.PropertyType == typeof(ArrayList)
|| pi.PropertyType == typeof(Hashtable))
{
// create a data table for each object in the array/hashtable
ICollection arrObj = (ICollection)pi.GetValue(fromObj, new object[] { });
if (arrObj != null)
{
if (pi.PropertyType == typeof(Hashtable))
{
arrObj = ((Hashtable)arrObj).Values;
}

foreach (object arrObjVal in arrObj)
{
if (arrObjVal == null) continue;

//if still intrinsic type then ignore
if (arrObjVal.GetType() == typeof(string) || arrObjVal.GetType() == typeof(decimal) || arrObjVal.GetType() == typeof(DateTime))
{
continue;
}
string arrayItem = colPrefix + "__" + pi.Name + "__" + arrObjVal.GetType().Name;

if (autoNestedColumns == false)
if ((ComponentToUse(arrayItem) == false && ComponentToFetch(colPrefix) == false)) break;

CreateDataTable(arrObjVal, arrayItem, ref dt);
}
}
}
else if (pi.PropertyType.IsClass)
{
string tempColPrfx = colPrefix;

if (tempColPrfx != "")
tempColPrfx += "__" + pi.Name + "";

//Dont get into nested detail, if not part of component to use
//e.g. not get into Employee.AddressCmpnt.Phonecmpnt while reading AddressCmpnt
if (autoNestedColumns == false)
if (ComponentToFetch(tempColPrfx) == false) continue;

CreateDataTable(pi.GetValue(fromObj, new object[] { }), tempColPrfx, ref dt);
}
}
}
}
}
//return the updated datatable
return dt;
}
GeneralThanks for your work Pin
e.blanchette25-Apr-08 7:02
e.blanchette25-Apr-08 7:02 
GeneralNot recognizing tags... Pin
vdoogs12-Dec-06 8:09
vdoogs12-Dec-06 8:09 
GeneralRe: Not recognizing tags... Pin
Tittle Joseph13-Dec-06 5:00
Tittle Joseph13-Dec-06 5:00 
GeneralTrouble with DataGridTableStyle Pin
kc02er7-Apr-06 14:33
kc02er7-Apr-06 14:33 
GeneralRe: Trouble with DataGridTableStyle Pin
Tittle Joseph7-Apr-06 23:28
Tittle Joseph7-Apr-06 23:28 
QuestionHow to use it in DataGrid Custom Control !! Pin
Tittle Joseph9-Nov-05 4:50
Tittle Joseph9-Nov-05 4:50 
AnswerContinuation of above explanation Pin
Tittle Joseph9-Nov-05 4:57
Tittle Joseph9-Nov-05 4:57 
General.NET 2.0 And VS.2005 Example Pin
Derec Roofie8-Aug-05 0:54
Derec Roofie8-Aug-05 0:54 
GeneralRe: .NET 2.0 And VS.2005 Example Pin
Anonymous8-Aug-05 4:07
Anonymous8-Aug-05 4:07 
GeneralRe: .NET 2.0 And VS.2005 Example Pin
Tittle Joseph8-Aug-05 4:08
Tittle Joseph8-Aug-05 4:08 
Generalselect a row within the datagrid problem Pin
Member 1455654-Aug-05 0:57
Member 1455654-Aug-05 0:57 
GeneralRe: select a row within the datagrid problem Pin
Tittle Joseph4-Aug-05 4:11
Tittle Joseph4-Aug-05 4:11 
GeneralRe: select a row within the datagrid problem Pin
Tittle Joseph4-Aug-05 22:48
Tittle Joseph4-Aug-05 22:48 
GeneralRe: select a row within the datagrid problem Pin
Member 1455655-Aug-05 11:22
Member 1455655-Aug-05 11:22 
GeneralA Beginner's Question Pin
docrob127-Jul-05 5:16
docrob127-Jul-05 5:16 
GeneralRe: A Beginner's Question Pin
Tittle Joseph27-Jul-05 18:58
Tittle Joseph27-Jul-05 18:58 
GeneralRe: A Beginner's Question Pin
docrob128-Jul-05 3:31
docrob128-Jul-05 3:31 
GeneralRe: A Beginner's Question Pin
docrob128-Jul-05 3:55
docrob128-Jul-05 3:55 
GeneralRe: A Beginner's Question Pin
Tittle Joseph28-Jul-05 22:23
Tittle Joseph28-Jul-05 22:23 
GeneralWaiting for comment !! Pin
Tittle Joseph18-Jul-05 19:56
Tittle Joseph18-Jul-05 19:56 
GeneralRe: Waiting for comment !! Pin
Anonymous19-Jul-05 13:09
Anonymous19-Jul-05 13:09 
GeneralRe: Waiting for comment !! Pin
Tittle Joseph19-Jul-05 18:28
Tittle Joseph19-Jul-05 18:28 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.