Binding Silverlight DataGrid Control to a Dynamically-Created Data Object


[tweetmeme source=”jojitsoriano” only_single=false]

As a backgrounder, data can be bound to a Silverlight DataGrid control by setting the ItemsSource property to a collection of objects. The object class should have been defined so that each column in the data grid can be bound to a property of the data object. Does it mean that you have to create a class during coding time so that you can bind the instance of that class to the DataGrid? What if you do not know what the field names are and you will just get it from a web service exposed by an existing application?

Sample code in MSDN and some .NET websites shows how to bind the DataGrid to a collection of data objects. This post aims to discuss binding the DataGrid to a collection of “dynamically-created” data objects. Thanks to WJamesLord of the Silverlight.Net forum for the code because of which I was able to solve my problem with the DataGrid binding. Honestly, this was only the second time that I made use of Reflection in my project that I practically copied his code and modified it a little to suit my requirement.

Creating the Class Containing the Fields of the Data Object

Step 1: Create the Class Using Reflection.

AssemblyName an = new
AssemblyName(“Result” + this.GetHashCode());


AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);

ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(“MainModule”);

    TypeBuilder tb = moduleBuilder.DefineType(<<Name of the Class>>,

    TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.AutoClass |


TypeAttributes.AnsiClass | TypeAttributes.BeforeFieldInit | TypeAttributes.AutoLayout,


typeof(object));

ConstructorBuilder constructor = tb.DefineDefaultConstructor(

    MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);

Step 2: Add the Properties by calling this AddProperty method.

AddProperty(“RowNumber”, typeof(int), ref tb);

AddProperty(“FirstName”, typeof(string), ref tb);


private
void AddProperty(string pstrColName,


Type p_ColType


ref
TypeBuilder r_TypeBuilder)

{


string strFieldName = “m_” + pstrColName;


FieldBuilder field = r_TypeBuilder.DefineField(strFieldName, p_ColType, FieldAttributes.Private);


PropertyBuilder propBldr = r_TypeBuilder.DefineProperty(pstrColName,


PropertyAttributes.HasDefault, p_ColType, new
Type[] { p_ColType });


// The property set and property get methods require a special


// set of attributes.


MethodAttributes getSetAttr = MethodAttributes.Public;


// Define the “get” accessor method for CustomerName.


MethodBuilder getPropMthdBldr = r_TypeBuilder.DefineMethod(“get_” + pstrColName,

getSetAttr, p_ColType, new
Type[] { });


ILGenerator custNameGetIL = getPropMthdBldr.GetILGenerator();

custNameGetIL.Emit(OpCodes.Ldarg_0);

custNameGetIL.Emit(OpCodes.Ldfld, field);

custNameGetIL.Emit(OpCodes.Ret);


// Define the “set” accessor method for CustomerName.


MethodBuilder setPropMthdBldr = r_TypeBuilder.DefineMethod(“set_” + pstrColName,

getSetAttr, null, new
Type[] { p_ColType });


ILGenerator custNameSetIL = setPropMthdBldr.GetILGenerator();

custNameSetIL.Emit(OpCodes.Ldarg_0);

custNameSetIL.Emit(OpCodes.Ldarg_1);

custNameSetIL.Emit(OpCodes.Stfld, field);

custNameSetIL.Emit(OpCodes.Ret);


// Last, we must map the two methods created above to our PropertyBuilder to


// their corresponding behaviors, “get” and “set” respectively.

propBldr.SetGetMethod(getPropMthdBldr);

propBldr.SetSetMethod(setPropMthdBldr);

}

Step 3: Create the Type.

    Assign the created type to a module-level variable e.g. _RowClass because you will need to refer to this everytime you need access to the object.

_RowClass = tb.CreateType();

Step 4: Create the data grid column and bind a data field to it.

You can use this method to create the data grid column. Add the created column to the grid by calling DataGrid.Columns.Add method.


private
DataGridBoundColumn CreateDataGridColumn(string pstrHeader,


string pstrBoundColumn,


Type p_DataType,


bool pbIsReadOnly)

{


DataGridBoundColumn col = null;


if (p_DataType == typeof(bool))

{

col = new
DataGridCheckBoxColumn();

}


else

{

col = new
DataGridTextColumn();

}

col.Header = pstrHeader;

col.Binding = new System.Windows.Data.Binding(pstrBoundColumn);

col.Width = DataGridLength.Auto;

col.IsReadOnly = pbIsReadOnly;


return col;

}

Step 5: Populate the collection of data or an array of data.

object[] itemsSource = new
object[<<Number of Rows>>];

You can repeat this part depending on the number of rows you’ll be adding.

object row = Activator.CreateInstance(_RowClass);


PropertyInfo propRowNumber = _RowClass.GetProperty(<<Field Name>>);

propRowNumber.SetValue(row, Convert.ChangeType(<<Data Value>>, <<Data Type>>, CultureInfo.CurrentCulture), null);

Insert the created row to your collection.

itemsSource[<<Row Index>>] = row;

Step 6: Set the ItemsSource property of the DataGrid.

grid.ItemsSource = itemsSource;

Retrieving Data from the Dynamic Data Object

To retrieve data from the dynamic data object, you can use the same code when setting the value of a row but using the GetValue method instead of the SetValue. The next code snippet shows how to get the value of a field of the selected row in a DataGrid:

protected
void grid_SelectionChanged(object sender, SelectionChangedEventArgs e)

{


if (e.AddedItems.Count > 0)

{


object obj = Activator.CreateInstance(_RowClass);

obj = e.AddedItems[0];


PropertyInfo propInfo = _RowClass.GetProperty(<<Field Name>>);


int intRowNumber = (int)propInfo.GetValue(obj, null);

}

}

Advertisements
This entry was posted in Silverlight and tagged , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s