Is it possible to bind Eto controls to a dynamic object viewmodel?

Hello everyone,

I am able to succesfully bind an Eto Control to a regular ViewModel, with a known set of properties, using

Control.Bind<T>(controlProperty, ViewModel, viewmodelProperty, DualBindingMode.TwoWay);

However, I am dealing with a scenario where the number of properties in the viewmodel varies based on a selected object. The solution to this was to implement the ViewModel as a dynamic object which implements ICustomTypeDescriptor and INotifyPropertyChanged , basically acting as a dictionary which raises the OnPropertyChanged event whenever a key is modified. The problem with this is that Eto Control binds don’t seem to work with it. The code for the dynamic object viewmodel is available below.

Am I missing something here? Is it possible to bind to a dynamic object? Any help is appreciated, thank you.

public class DynamicViewModel : DynamicObject, ICustomTypeDescriptor, INotifyPropertyChanged
    {
        private readonly Object thisLock = new Object();

        public event PropertyChangedEventHandler PropertyChanged;

        private Dictionary<string, object> dictionary = new Dictionary<string, object>();
        ISynchronizeInvoke syncronzeInvoke;
        public DynamicViewModel(ISynchronizeInvoke value = null)
        {
            syncronzeInvoke = value;
        }
        public object this[string name]
        {
            get
            {
                lock (thisLock) { return dictionary[name]; }
            }
            set
            {
                object oldValue = null;
                lock (thisLock)
                {
                    if (dictionary.ContainsKey(name))
                        oldValue = dictionary[name];
                    dictionary[name] = value;
                }
                if (oldValue != value)
                    OnPropertyChanged(name);
            }
        }
        private void OnPropertyChanged(string name)
        {
            var handler = PropertyChanged;
            if (handler != null)
            {
                if (syncronzeInvoke != null && syncronzeInvoke.InvokeRequired)
                    syncronzeInvoke.Invoke(handler, new object[] { this, new PropertyChangedEventArgs(name) });
                else
                    handler(this, new PropertyChangedEventArgs(name));
            }
        }
        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            result = this[binder.Name];
            return true;
        }
        public override bool TrySetMember(SetMemberBinder binder, object value)
        {
            this[binder.Name] = value;
            return true;
        }
        public string GetComponentName()
        {
            return TypeDescriptor.GetComponentName(this, true);
        }
        public EventDescriptor GetDefaultEvent()
        {
            return TypeDescriptor.GetDefaultEvent(this, true);
        }
        public string GetClassName()
        {
            return TypeDescriptor.GetClassName(this, true);
        }
        public EventDescriptorCollection GetEvents(Attribute[] attributes)
        {
            return TypeDescriptor.GetEvents(this, attributes, true);
        }
        EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
        {
            return TypeDescriptor.GetEvents(this, true);
        }
        public TypeConverter GetConverter()
        {
            return TypeDescriptor.GetConverter(this, true);
        }
        public object GetPropertyOwner(PropertyDescriptor pd)
        {
            return dictionary;
        }
        public AttributeCollection GetAttributes()
        {
            return TypeDescriptor.GetAttributes(this, true);
        }
        public object GetEditor(Type editorBaseType)
        {
            return TypeDescriptor.GetEditor(this, editorBaseType, true);
        }
        public PropertyDescriptor GetDefaultProperty()
        {
            return null;
        }
        PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
        {
            return this.GetProperties(new Attribute[] { });
        }
        public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
        {
            var properties = new List<MyCustomPropertyDescriptor>();
            foreach (var e in dictionary)
                properties.Add(new MyCustomPropertyDescriptor(e.Key, (e.Value?.GetType()) ?? typeof(object)));
            return new PropertyDescriptorCollection(properties.ToArray());
        }

        public void ResetPropertyChangedEvent()
        {
            PropertyChanged = null;
        }
    }
    public class MyCustomPropertyDescriptor : PropertyDescriptor
    {
        Type type;
        string key;
        public MyCustomPropertyDescriptor(string key, Type type)
            : base(key, null)
        {
            this.type = type;
            this.key = key;
        }
        void PropertyChanged(object sender, EventArgs e)
        {
            OnValueChanged(sender, e);
        }
        public override void AddValueChanged(object component, EventHandler handler)
        {
            base.AddValueChanged(component, handler);
            ((INotifyPropertyChanged)component).PropertyChanged += PropertyChanged;
        }
        public override void RemoveValueChanged(object component, EventHandler handler)
        {
            base.RemoveValueChanged(component, handler);
            ((INotifyPropertyChanged)component).PropertyChanged -= PropertyChanged;
        }
        public override Type PropertyType
        {
            get { return type; }
        }
        public override void SetValue(object component, object value)
        {
            ((DynamicViewModel)component)[key] = value;
        }
        public override object GetValue(object component)
        {
            return ((DynamicViewModel)component)[key];
        }
        public override bool IsReadOnly
        {
            get { return false; }
        }
        public override Type ComponentType
        {
            get { return null; }
        }
        public override bool CanResetValue(object component)
        {
            return false;
        }
        public override void ResetValue(object component)
        {
        }
        public override bool ShouldSerializeValue(object component)
        {
            return false;
        }
    }
    public sealed class VMSingleton : DynamicViewModel
    {
        private VMSingleton() { }

        private static VMSingleton _instance;

        public static VMSingleton GetInstance()
        {
            if (_instance == null)
            {
                _instance = new VMSingleton();
            }
            return _instance;
        }

        public static void SetNull()
        {
            _instance = null;
        }
    }