I just ran into an issue where DataBinder.Eval was exploding with an exception like this:

'System.Dynamic.ExpandoObject' does not contain a definition for 'Id'.

The problem here is that DataBinder.Eval uses either reflection and type descriptors to bind to properties. ExpandoObject (and dynamic types) don't support reflection. ExpandoObject doesn't implement ICustomTypeDescriptor either, leading to an exception when attempting to bind to an ExpandoObject.

After half an hour of googling, I found Bertrand Le Roy's excellent example of building custom type descriptors: Fun with C# 4.0's dynamic. I'm not sure why it took me so long to find it, so I figure I'll give him a bit of google juice and add some more keywords.

Also, that sample is rather out of date, so you'll have to do a couple of tweaks to make it work in .NET 4/4.5 (see below). Once that's done, you will have a bindable wrapper object that takes an ExpandoObject and can be directly bound to. Given and ExpandoObject "dyn" with a property named "Id", you can do this:

var bindableObj = new DynamicTypeDescriptorWrapper(dyn);

var value = DataBinder.Eval(bindableObj, "Id");

Changes required

First, change DynamicHelper.cs to the following:

public static class DynamicHelper {
    public static object GetValue(object dyn, string propName) {
        // Warning: this is rather expensive, and should be cached in a real app
        var GetterSite = CallSite<Func<CallSite, object, object>>.Create(
                Binder.GetMember(CSharpBinderFlags.None,
                    propName, 
                    dyn.GetType(),
                    new [] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) }
                    ));

        return GetterSite.Target(GetterSite, dyn);
    }

    public static void SetValue(object dyn, string propName, object val) {
        // Warning: this is rather expensive, and should be cached in a real app
        var SetterSite = CallSite<Func<CallSite, object, object, object>>.Create(
                Binder.SetMember(CSharpBinderFlags.None,
                    propName, 
                    dyn.GetType(),
                    new [] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
                                CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.Constant |
                                            CSharpArgumentInfoFlags.UseCompileTimeType, null) }
                    ));

        SetterSite.Target(SetterSite, dyn, val);
    }
}

Then, change GetValue and SetValue in DynamicPropertyDescriptor as follows:

public override object GetValue(object component) {
    if (component is DynamicTypeDescriptorWrapper)
        component = ((DynamicTypeDescriptorWrapper)component).GetPropertyOwner(this);

    if (_owner != component) throw new InvalidOperationException("GetValue can only be used with the descriptor's owner.");
            
    return DynamicHelper.GetValue(component, _propertyName);
}

public override void SetValue(object component, object value) {
    if (component is DynamicTypeDescriptorWrapper)
        component = ((DynamicTypeDescriptorWrapper)component).GetPropertyOwner(this);

    if (_owner != component) throw new InvalidOperationException("SetValue can only be used with the descriptor's owner.");
            
    OnValueChanged(component, EventArgs.Empty);

    DynamicHelper.SetValue(component, _propertyName, value);
}