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