2012-09-01 10 views
19

Estoy experimentando con la interfaz ICustomTypeDescriptor y la clase PropertyDescriptor para crear propiedades dinámicas en los objetos. Estoy teniendo mucho éxito con los objetos simples, pero no puedo obtener objetos anidados para crear sus propiedades dinámicas?'Binding Builder' no interroga al ICustomTypeDescriptor anidado (ruta vacía)?

Por ejemplo, en el cuadro de diálogo de enlace de datos a continuación, estoy añadiendo mi clase de persona como un StaticResource, a continuación, tratando de obligar a la técnica de Person.Child.Name a una caja de ensayo:

Para el Person.Child I Espero ver mis propiedades creadas dinámicamente (Name y Age), pero como puede ver, ¿no funciona como se esperaba? Es casi como si el diálogo de enlace de datos no estuviera interrogando a la interfaz ICustomTypeDescriptor en el Person.Child?

¿Alguna orientación sobre cómo hacer que estas propiedades anidadas sean 'visibles'?

clase exterior

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); 
    } 
} 

clase interna

[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); 
    } 
} 

propiedad de descriptor

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

Veo tu etiqueta para VS2010, lo que parece implicar .NET 4.0? Verá aquí que el soporte de enlace para ICustomTypeDescriptor no se agregó hasta .NET 4.5: http://msdn.microsoft.com/en-us/library/bb613588%28v=vs.110%29.aspx – Brannon

Respuesta

1

I t Creo que configuró incorrectamente la propiedad ComponentType.

  1. Propiedad: Person.Child debe tener el ComponentType establecido en typeof (Person) no typeof (Child). Al igual que la propiedad: Person.Name.
  2. Propiedad: Child.Name debe tener el ComponentType configurado en typeof (Child).

ComponentType se utiliza para definir el tipo de propietario.