Here’s a useful helper to build a dynamic wrapper / facade class from an arbitrary collection of properties. The wrapper implements INotifiyPropertyChanged so can be used with two-way databinding in WPF, Silverlight and ASP.NET (probably other places too):
/// <summary> /// IDynamicPropertyProvider interface /// </summary> public interface IDynamicPropertyProvider { object GetPropertyValue( string name ); void SetPropertyValue( string name, object value ); event PropertyChangedEventHandler ValueChanged; } /// <summary> /// DynamicTypeFactory class /// </summary> public class DynamicTypeFactory { #region DynamicBase class /// <summary> /// Base for dynamic class /// </summary> public class DynamicBase : INotifyPropertyChanged, IDisposable { private IDynamicPropertyProvider provider; public DynamicBase( IDynamicPropertyProvider provider ) { this.provider = provider; if ( provider != null ) provider.ValueChanged += OnPropertyChanged; } protected object GetValue( string name ) { return provider.GetPropertyValue( name ); } protected void SetValue( string name, object value ) { provider.SetPropertyValue( name, value ); } private void OnPropertyChanged( object sender, PropertyChangedEventArgs e ) { if ( PropertyChanged != null ) PropertyChanged( this, e ); } #region INotifyPropertyChanged Members public event PropertyChangedEventHandler PropertyChanged; #endregion #region IDisposable Members public void Dispose() { if ( provider != null ) provider.ValueChanged -= OnPropertyChanged; } #endregion } #endregion /// <summary> /// Creates the type. /// </summary> /// <param name="name">The name.</param> /// <param name="properties">The properties.</param> /// <returns></returns> public static Type CreateType( string name, IEnumerable<string> properties ) { // Define dynamic assembly var assemblyName = new AssemblyName( "DynamicAssembly" ); var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly( assemblyName, AssemblyBuilderAccess.Run ); var module = assemblyBuilder.DefineDynamicModule( "DynamicModule" ); // Define type var typeBuilder = module.DefineType( name, TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.AutoClass | TypeAttributes.AnsiClass | TypeAttributes.BeforeFieldInit | TypeAttributes.AutoLayout, typeof( DynamicBase ) ); var baseConstructor = typeof( DynamicBase ).GetConstructor( new[] { typeof( IDynamicPropertyProvider ) } ); // Define constructor var constructor = typeBuilder.DefineConstructor( MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, CallingConventions.Standard, new[] { typeof( IDynamicPropertyProvider ) } ); var ilGen = constructor.GetILGenerator(); ilGen.Emit( OpCodes.Ldarg_0 ); ilGen.Emit( OpCodes.Ldarg_1 ); ilGen.Emit( OpCodes.Call, baseConstructor ); ilGen.Emit( OpCodes.Ret ); // Prepare to define properties var getSetAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig; var getMethodInfo = typeof( DynamicBase ).GetMethod( "GetValue", BindingFlags.NonPublic | BindingFlags.Instance ); var setMethodInfo = typeof( DynamicBase ).GetMethod( "SetValue", BindingFlags.NonPublic | BindingFlags.Instance ); foreach ( var property in properties ) { // Define property get method var getMethod = typeBuilder.DefineMethod( "get_" + property, getSetAttr, typeof( object ), Type.EmptyTypes ); ilGen = getMethod.GetILGenerator(); ilGen.Emit( OpCodes.Ldarg_0 ); ilGen.Emit( OpCodes.Ldstr, property ); ilGen.Emit( OpCodes.Callvirt, getMethodInfo ); ilGen.Emit( OpCodes.Ret ); // Define property set method var setMethod = typeBuilder.DefineMethod( "set_" + property, getSetAttr, null, new[] { typeof( object ) } ); ilGen = setMethod.GetILGenerator(); ilGen.Emit( OpCodes.Ldarg_0 ); ilGen.Emit( OpCodes.Ldstr, property ); ilGen.Emit( OpCodes.Ldarg_1 ); ilGen.Emit( OpCodes.Callvirt, setMethodInfo ); ilGen.Emit( OpCodes.Ret ); // Define property var propertyBuilder = typeBuilder.DefineProperty( property, PropertyAttributes.HasDefault, typeof( object ), Type.EmptyTypes ); propertyBuilder.SetGetMethod( getMethod ); propertyBuilder.SetSetMethod( setMethod ); } // Materialize type return typeBuilder.CreateType(); } }
To use it you’ll need to implement the IDynamicPropertyProvider interface on your own “provider” class. Its job is to get and set a property value and raise “ValueChanged” events when values are changed (externally or by SetPropertyValue).
A basic provider could look something like this (see CreateDynamicWrapper for usage details):
public class MyDynamicProvider : IDynamicPropertyProvider { public Dictionary<string, object> MyValues { get; private set; } public MyDynamicProvider() { MyValues = new Dictionary<string, object>(); } public object CreateDynamicWrapper() { var type = DynamicTypeFactory.CreateType( "MyWrapper", MyValues.Keys.ToArray() ); return Activator.CreateInstance( type, this ); } public object GetPropertyValue( string name ) { return MyValues[ name ]; } public void SetPropertyValue( string name, object value ) { MyValues[ name ] = value; if ( ValueChanged != null ) ValueChanged( this, new PropertyChangedEventArgs( name ) ); } public event PropertyChangedEventHandler ValueChanged; }
From there of course you can bind directly to the wrapper in XAML, ASP.NET or whatever and maybe avoid some typing


10 comments
Comments feed for this article
April 7, 2009 at 6:38 am
Dew Drop - April 7, 2009 | Alvin Ashcraft's Morning Dew
[...] Binding Dynamic Properties in XAML, ASP.NET… (Chris Cavanagh) [...]
April 9, 2009 at 4:46 pm
Kevin
Thanks for your article. It’s very useful.
There is a datagrid in my project. I’d like to bind column header from database. So I have to create dynamic column for datagrid.
Do you have any idea for binding column header of datagrid?
Thanks.
April 27, 2009 at 4:22 pm
Jones
Nice post…
May 2, 2009 at 2:23 pm
Andrus
http://silverlight.net/forums/p/66364/214522.aspx#214522
is better: implements typed properties
May 2, 2009 at 4:06 pm
Chris Cavanagh
Andrus – Thanks for the feedback!
May 3, 2009 at 5:48 am
Andrus
I found the following issues:
1. How to add new empty rows to DataGrid? I tried
list.Add(Activator.CreateInstance(t));
but got exception
No parameterless constructor defined for this object.
My entity base class has public parameterless constructor. Generated type does not inherit it.
2. There may be a list of known property types. How to force to use pre-defined property type instead of object?
3. For some columns, System.Security.VerificationException occurs with additional information:
Operation could destabilize the runtime.
How to fix them ?
April 22, 2010 at 12:16 pm
Ken
I just stumbled across this post today.
Being a complete newbie to xaml and wpf, I only understand some of this. However, I know that I’ll have to do something like this (support a dynamic list of properties) in an upcoming project. The part that I don’t have a handle on yet is how the above sample code actually hooks into the xaml/UI part. Do you have a complete example that shows how it all fits together?
April 22, 2010 at 12:25 pm
Chris Cavanagh
Ken – The idea is you can use regular XAML data binding with the dynamic class. You’d be able to put something like “{Binding MyDynamicProperty1, Mode=TwoWay}”. I haven’t put together any samples of this, but it’s a great suggestion so I’ll do that asap.
How dynamic do you need the property list to be? Will it vary at runtime, or is it something you could handle at compile time? If the latter, a better option might be to use a T4 template to generate a class file for you…
April 23, 2010 at 6:51 am
Ken
Thanks for responding!
My application consists of various types of objects, each with their own set of properties. Each object’s properties are (or can be) unique to the object’s type. We build the objects, so we could determine their properties when building the UI…but in our thick client we determine them at runtime so there’s less maintenance and fewer updates if new properties are added to any specific object type.
I’m not familiar with a T4 template…I’ll have to look into that.
Thanks.
April 23, 2010 at 9:04 am
Chris Cavanagh
Ken – T4′s are a good option if you know the class properties at compile time. Because you can include code (any .NET language) as part of the template, you can build code from pretty much any source you’d like. Also, if you use one of the available T4 editors (Tangible, Clarius, maybe others) you can get intellisense too (in both the “generating” and “generated” code if the editor supports it).
Hope this helps!