2012-09-01 67 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用於定義屬性所有者類型。