2012-02-24 82 views
3

我在我的应用程序中实现了ICustomTypeDescriptor,以便能够在运行时定义自定义属性。我的基本实现看起来像:ICustomTypeDescriptor包装对象

public class DynamicClass <T> : ICustomTypeDescriptor 
{ 
    private readonly T _object; 

    public DynamicClass(T trackedObject) 
    { 
     _object = trackedObject; 
    } 

    // Collection to code add dynamic properties 
    public KeyedCollection<string, DynamicProperty> Properties 
    { 
     get; 
     private set; 
    } 

    // ICustomTypeDescriptor implementation 
    public AttributeCollection GetAttributes() 
    { 
     return TypeDescriptor.GetAttributes(_object, true); 
    } 

    public string GetClassName() 
    { 
     return TypeDescriptor.GetClassName(_object, true); 
    } 

    public string GetComponentName() 
    { 
     return TypeDescriptor.GetComponentName(_object, true); 
    } 

    public TypeConverter GetConverter() 
    { 
     return TypeDescriptor.GetConverter(_object, true); 
    } 

    public EventDescriptor GetDefaultEvent() 
    { 
     return TypeDescriptor.GetDefaultEvent(_object, true); 
    } 

    public PropertyDescriptor GetDefaultProperty() 
    { 
     return TypeDescriptor.GetDefaultProperty(_object, true); 
    } 

    public object GetEditor(Type editorBaseType) 
    { 
     throw new NotImplementedException(); 
    } 

    public EventDescriptorCollection GetEvents() 
    { 
     return TypeDescriptor.GetEvents(_object, true); 
    } 

    public EventDescriptorCollection GetEvents(Attribute[] attributes) 
    { 
     return TypeDescriptor.GetEvents(_object, attributes, true); 
    } 

    PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties() 
    { 
     return TypeDescriptor.GetProperties(_object, true); 
    } 

    public PropertyDescriptorCollection GetProperties(Attribute[] attributes) 
    { 
     return TypeDescriptor.GetProperties(_object, attributes, true); 
    } 

    public object GetPropertyOwner(PropertyDescriptor pd) 
    { 
     return _object; 
    } 
} 

的问题是,现在,当我的对象绑定到使用DynamicClass粘合剂的文本框它不工作了。

我用这样的:

DynamicClass<ExtensionModel> binder = new DynamicClass<ExtensionModel>(ext); 
_versionLabel.DataBindings.Add("Text", binder, "SelectedVersion", false, DataSourceUpdateMode.OnPropertyChanged); 

,我得到异常:“对象不匹配目标类型”

对象与目标类型不匹配。

在System.Reflection.RuntimeMethodInfo.CheckConsistency(对象 靶)在System.Reflection.RuntimeMethodInfo.Invoke在 (对象OBJ, 的BindingFlags invokeAttr,粘结剂粘结剂,对象[]参数, CultureInfo的文化,布尔skipVisibilityChecks) System.Reflection.RuntimeMethodInfo.Invoke在 System.ComponentModel(对象OBJ,的BindingFlags invokeAttr,粘结剂粘结剂,对象[]参数,CultureInfo的培养物)
在System.ComponentModel.ReflectEventDescriptor.AddEventHandler(对象 成分,代表值)。 ReflectPropertyDescriptor.AddValueChanged(Object componen吨,事件处理程序的处理程序)处 System.Windows.Forms.ListManagerBindingsCollection.AddCore在 System.Windows.Forms.Binding.SetListManager(BindingManagerBase bindingManagerBase System.Windows.Forms.BindToObject.CheckBinding())(绑定 数据绑定)在System.Windows.Forms.BindingsCollection.Add在 System.Windows.Forms.Control.UpdateBindings()

(绑定 结合)在 System.Windows.Forms.BindingContext.UpdateBinding(的BindingContext newBindingContext,装订装订)

该绑定工作,如果不是活页夹,我使用ext对象。我在ICustomTypeDescriptor实现中遗漏了什么?

+0

SelectedVersion属性返回并位于DynamicClass类中的是什么?你有没有设法解决这个问题? – Martin 2012-03-29 21:08:44

回答

0

我已经设法在我的测试代码中重现您的问题。我可以看到,如果你没有在ExtensionModel上实现INotifyPropertyChanged,那么它的工作原理!

所以你的ICustomTypeDescriptor的实现有些东西不能与实现INotifyPropertyChanged的属性类一起工作。

这会起作用,但如果您取消注释INotifyPropertyChange,它将会中断。

public class BindingExample 
{ 
    public void Shows_Binding_To_A_Label_With_DynamicClass() 
    { 
     Form frm = new Form(); 
     Label _versionLabel = new Label(); 
     frm.Controls.Add(_versionLabel); 

     ExtensionModel ext = new ExtensionModel() { SelectedVersion = "DynamicClass Example" }; 
     DynamicClass<ExtensionModel> binder = new DynamicClass<ExtensionModel>(ext); 

     _versionLabel.DataBindings.Add("Text", binder, "SelectedVersion", false, DataSourceUpdateMode.OnPropertyChanged); 

     frm.ShowDialog(); 
    } 
} 

public class ExtensionModel// : INotifyPropertyChanged 
{ 
    string selectedVersion; 
    public string SelectedVersion 
    { 
     get { return selectedVersion; } 
     set 
     { 
      selectedVersion = value; 
      onPropertyChanged("SelectedVersion"); 
     } 
    } 

    void onPropertyChanged(string propertyName) 
    { 
     if (PropertyChanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
    public event PropertyChangedEventHandler PropertyChanged; 
} 

我想要这样做,所以我会继续玩它。

0

你必须用自定义的包装原始描述符。以下是代码:

#region IBindingProxy 

public interface IBindingProxy 
{ 
    void CheckAndNotify(); 
} 

#endregion 

public class BindingProxy : CustomTypeDescriptor, INotifyPropertyChanged, IBindingProxy 
{ 
    #region Static Constructor 

    private static readonly IDictionary<Type, PropertyDescriptorCollection> propertyCache; 

    static BindingProxy() 
    { 
     propertyCache = new Dictionary<Type, PropertyDescriptorCollection>(); 
    } 

    private static PropertyDescriptorCollection GetTypeProperties(Type type) 
    { 
     lock (propertyCache) 
     { 
      PropertyDescriptorCollection properties; 
      if (!propertyCache.TryGetValue(type, out properties)) 
      { 
       var list = new List<PropertyDescriptor>(); 
       GetTypeProperties(list, type); 
       properties = new PropertyDescriptorCollection(list.ToArray()); 
       propertyCache.Add(type, properties); 
      } 
      return properties; 
     } 
    } 

    private static void GetTypeProperties(ICollection<PropertyDescriptor> list, Type type) 
    { 
     foreach (var @interface in type.GetInterfaces()) 
     { 
      GetTypeProperties(list, @interface); 
     } 
     foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(type)) 
     { 
      list.Add(new ProxyPropertyDescriptor(property)); 
     } 
    } 

    #endregion 

    private readonly PropertyDescriptorCollection properties; 
    private readonly object instance; 

    public event PropertyChangedEventHandler PropertyChanged; 

    public BindingProxy(object instance) 
    { 
     this.instance = instance; 

     properties = instance == null 
      ? PropertyDescriptorCollection .Empty 
      : GetTypeProperties(instance.GetType()); 
    } 

    public void CheckAndNotify() 
    { 
     OnPropertyChanged(null); 
    } 

    protected virtual void OnPropertyChanged(string propertyName) 
    { 
     var handler = PropertyChanged; 
     if (handler != null) 
     { 
      handler(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 

    public object Instance 
    { 
     get { return instance; } 
    } 

    public override PropertyDescriptorCollection GetProperties() 
    { 
     return GetProperties(null); 
    } 

    public override PropertyDescriptorCollection GetProperties(Attribute[] attributes) 
    { 
     return properties; 
    } 

    public override Object GetPropertyOwner(PropertyDescriptor property) 
    { 
     return this; 
    } 

    #region ProxyPropertyDescriptor 

    private class ProxyPropertyDescriptor : PropertyDescriptor 
    { 
     private readonly PropertyDescriptor property; 

     public ProxyPropertyDescriptor(PropertyDescriptor property) : base(property) 
     { 
      this.property = property; 
     } 

     //public override string DisplayName 
     //{ 
     // get { return property.DisplayName; } 
     //} 

     //public override string Description 
     //{ 
     // get { return property.Description; } 
     //} 

     //public override string Category 
     //{ 
     // get { return property.Category; } 
     //} 

     //public override TypeConverter Converter 
     //{ 
     // get { return converter; } 
     //} 

     public override bool IsReadOnly 
     { 
      get { return property.IsReadOnly; } 
     } 

     public override void ResetValue(object component) 
     { 
     } 

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

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

     public override Type ComponentType 
     { 
      get { return property.ComponentType; } 
     } 

     public override Type PropertyType 
     { 
      get { return property.PropertyType; } 
     } 

     public override object GetValue(object component) 
     { 
      return property.GetValue(((BindingProxy)component).instance); 
     } 

     public override void SetValue(object component, object value) 
     { 
      var instance = ((BindingProxy)component).instance; 
      property.SetValue(instance, value); 
      OnValueChanged(instance, EventArgs.Empty); 
     } 
    } 

    #endregion 
}