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?
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);
}
}
}