2012-09-01 38 views
19

我正在尝试使用ICustomTypeDescriptor接口和PropertyDescriptor类来创建对象的动态属性。我对简单对象有很多成功,但我无法获得嵌套对象来创建其动态属性?在Person.Child.Name'绑定生成器'不询问嵌套的ICustomTypeDescriptor(路径为空)?

例如下面的数据绑定对话框中,我加入我的Person类作为StaticResource,然后试图数据绑定到TESTBOX:

对于Person.Child我我期待看到我的动态创建的属性(NameAge),但正如你所看到的,它不能按预期工作? 这几乎就好像数据绑定对话框不在Person.Child上询问ICustomTypeDescriptor接口?

有关如何使这些嵌套属性“可见”的任何指导?

外部类

public class Person : ICustomTypeDescriptor, INotifyPropertyChanged 
{ 
    private readonly List<CustomPropertyDescriptor> propertyDescriptors = new List<CustomPropertyDescriptor>(); 
    private readonly Dictionary<string, object> properties = new Dictionary<string, object>(); 

    public Person() 
    { 
     // 'Dynamic' Property 
     string name = "Name"; 
     object value = "Person's Name"; 
     this.properties.Add(name, value); 
     var propertyDescriptor = new CustomPropertyDescriptor(
      typeof(Person), 
      name, 
      value, 
      value.GetType().GetCustomAttributes(true).Cast<Attribute>().ToArray()); 
     this.propertyDescriptors.Add(propertyDescriptor); 

     // 'Dynamic' Property 
     name = "Child"; 
     value = new Child(); 
     this.properties.Add(name, value); 
     propertyDescriptor = new CustomPropertyDescriptor(
      typeof(Child), 
      name, 
      value, 
      value.GetType().GetCustomAttributes(true).Cast<Attribute>().ToArray()); 
     this.propertyDescriptors.Add(propertyDescriptor); 

     propertyDescriptor.PropertyChanged += this.PropertyDescriptorPropertyChanged; 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    // Test Property (shouldn't be visible) 
    public string NotDynamic { get; set; } 

    public override string ToString() 
    { 
     return string.Format("{0} ({1})", this.properties["Name"], this.properties["Age"]); 
    } 

    public AttributeCollection GetAttributes() 
    { 
     return TypeDescriptor.GetAttributes(this, true); 
    } 

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

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

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

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

    public PropertyDescriptor GetDefaultProperty() 
    { 
     try 
     { 
      return this.propertyDescriptors.First(); 
     } 
     catch (InvalidOperationException) 
     { 
      return null; 
     } 
    } 

    public object GetEditor(Type editorBaseType) 
    { 
     return TypeDescriptor.GetEditor(this, editorBaseType, true); 
    } 

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

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

    public PropertyDescriptorCollection GetProperties(Attribute[] attributes) 
    { 
     return new PropertyDescriptorCollection(this.propertyDescriptors.ToArray()); 
    } 

    public PropertyDescriptorCollection GetProperties() 
    { 
     return this.GetProperties(null); 
    } 

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

    protected void OnPropertyChanged(string name) 
    { 
     if (this.PropertyChanged != null) 
     { 
      this.PropertyChanged(this, new PropertyChangedEventArgs(name)); 
     } 
    } 

    private void PropertyDescriptorPropertyChanged(object sender, PropertyChangedEventArgs e) 
    { 
     this.OnPropertyChanged(e.PropertyName); 
    } 
} 

内部类

[TypeConverter(typeof(ExpandableObjectConverter))] 
public class Child : ICustomTypeDescriptor, INotifyPropertyChanged 
{ 
    private readonly List<CustomPropertyDescriptor> propertyDescriptors = new List<CustomPropertyDescriptor>(); 
    private readonly Dictionary<string, object> properties = new Dictionary<string, object>(); 

    public Child() 
    { 
     // 'Dynamic' Property 
     string name = "Name"; 
     object value = "Person's Child"; 
     this.properties.Add(name, value); 
     var propertyDescriptor = new CustomPropertyDescriptor(
      typeof(Person), 
      name, 
      value, 
      value.GetType().GetCustomAttributes(true).Cast<Attribute>().ToArray()); 
     propertyDescriptor.PropertyChanged += this.PropertyDescriptorPropertyChanged; 
     this.propertyDescriptors.Add(propertyDescriptor); 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    // Test Property (shouldn't be visible) 
    public string NotDynamic { get; set; } 

    public override string ToString() 
    { 
     return string.Format("{0} ({1})", this.properties["Name"], this.properties["Age"]); 
    } 

    public AttributeCollection GetAttributes() 
    { 
     return TypeDescriptor.GetAttributes(this, true); 
    } 

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

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

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

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

    public PropertyDescriptor GetDefaultProperty() 
    { 
     try 
     { 
      return this.propertyDescriptors.First(); 
     } 
     catch (InvalidOperationException) 
     { 
      return null; 
     } 
    } 

    public object GetEditor(Type editorBaseType) 
    { 
     return TypeDescriptor.GetEditor(this, editorBaseType, true); 
    } 

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

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

    public PropertyDescriptorCollection GetProperties(Attribute[] attributes) 
    { 
     return new PropertyDescriptorCollection(this.propertyDescriptors.ToArray());  
    } 

    public PropertyDescriptorCollection GetProperties() 
    { 
     return this.GetProperties(null); 
    } 

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

    protected void OnPropertyChanged(string name) 
    { 
     if (this.PropertyChanged != null) 
     { 
      this.PropertyChanged(this, new PropertyChangedEventArgs(name)); 
     } 
    } 

    private void PropertyDescriptorPropertyChanged(object sender, PropertyChangedEventArgs e) 
    { 
     this.OnPropertyChanged(e.PropertyName); 
    } 
} 

属性描述

public class CustomPropertyDescriptor : PropertyDescriptor, INotifyPropertyChanged 
{ 
    private readonly Type componentType; 
    private string name; 
    private object value; 

    public CustomPropertyDescriptor(Type componentType, string name, object value, Attribute[] attributes) 
     : base(name, attributes) 
    { 
     this.componentType = componentType; 
     this.name = name; 
     this.value = value; 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    public override bool IsBrowsable 
    { 
     get 
     { 
      return true; 
     } 
    } 

    public override Type ComponentType 
    { 
     get { return this.componentType; } 
    } 

    public override bool IsReadOnly 
    { 
     get { return false; } 
    } 

    public override Type PropertyType 
    { 
     get { return this.value.GetType(); } 
    } 

    public override object GetValue(object component) 
    { 
     return this.value; 
    } 

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

    public override void ResetValue(object component) 
    { 
    } 

    public override void SetValue(object component, object value) 
    { 
     this.value = value; 
     this.OnPropertyChanged(this.Name); 
    } 

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

    private void OnPropertyChanged(string name) 
    { 
     if (this.PropertyChanged != null) 
     { 
      this.PropertyChanged(this, new PropertyChangedEventArgs(name)); 
     } 
    } 
} 
+6

我看到你的标签为VS2010,这似乎暗示.NET 4.0?你会在这里看到ICustomTypeDescriptor的绑定支持直到.NET 4.5才被添加:http://msdn.microsoft.com/en-us/library/bb613588%28v=vs.110%29.aspx – Brannon

回答

1

余吨哼你错误地设置ComponentType属性。

  1. Property:Person.Child应该将ComponentType设置为typeof(Person)而不是typeof(Child)。就像属性:Person.Name。
  2. Property:Child.Name应该将ComponentType设置为typeof(Child)。

ComponentType用于定义属性所有者类型。