Binding DynamicObject to a DataGrid with automatic column generation?

There is no uniform way to query dynamic properties, generally it’s expected that you know them ahead of time. With DynamicObject, implementers may override GetMemberNames and that generally gives you the properties, however it is really meant for debugging because there is no requirement that it provide all properties. Otherwise if it’s your own DynamicObject you just have to write your own method to get the properties based on your dynamic implementation. For example ExpandoObject lets you query all the properties using the IDictionary interface.

So once you have a way to get your properties you need to tell the DataGrid. Unfortunately with a DataGrid, the issue with implementing ICustomTypeDescriptor to tell the DataGrid about your properties is that DataGrid gets the TypeDescriptors using the Type not the instance, which is a problem for Dynamic objects, however implementing ITypedList on the collection of DynamicObjects will work with the very tiny gotcha of if you don’t implement the non-generic IList interface on your collection, it will be stripped out before it gets to the point where it checks for ITypeList.

So in summary, Implement a Collection with ITypedList and IList. With ITypedList return null for GetListName and just implement GetItemProperties(PropertyDescriptor[] listAccessors); Ignore listAccessors and return a PropertyDescriptorCollection of PropertyDescriptors for each member named based on the best represented Dynamic object instance in your list (most likely just the first object). You do have to implement a subclass of PropertyDescriptor, an easy and general way to the Get/Set value is to use the opensource framework Dynamitey

using System;
using System.ComponentModel;
using Dynamitey;
public class DynamicPropertyDescriptor:PropertyDescriptor
{
        public DynamicPropertyDescriptor(string name) : base(name, null)
        {
        }

        public override bool CanResetValue(object component)
        {
            return false;
        }

        public override object GetValue(object component)
        {
           return Dynamic.InvokeGet(component, Name);
        }

        public override void ResetValue(object component)
        {

        }

        public override void SetValue(object component, object value)
        {
            Dynamic.InvokeSet(component, Name, value);
        }

        public override bool ShouldSerializeValue(object component)
        {
            return false;
        }

        public override Type ComponentType
        {
            get { return typeof(object); }
        }

        public override bool IsReadOnly
        {
            get { return false; }
        }

        public override Type PropertyType
        {
            get
            {
                return typeof (object);
            }
        }
}

Leave a Comment