Binding Dynamic Properties in XAML, ASP.NET…

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

  1. 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.

    Reply

  2. 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 ?

    Reply

  3. 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?

    Reply

    1. 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…

      Reply

  4. 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.

    Reply

    1. 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!

      Reply

Leave a comment