Binding DynamicObject to a DataGrid with automatic column generation?
c#-4.0, data-binding, datagrid, dynamicobject, wpf
Solution
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);
}
}
}
Problem
I'm still experimenting with DynamicObjects. Now I need some information: I'm trying to bind an object inheriting from DynamicObject to a WPF DataGrid (not Silverlight). How do I get the DataGrid to automatically create its columns from the available public properties of the object that are typically generated at runtime? Is that possible actually?