19
我正在尝试使用ICustomTypeDescriptor
接口和PropertyDescriptor
类来创建对象的动态属性。我对简单对象有很多成功,但我无法获得嵌套对象来创建其动态属性?在Person.Child.Name
'绑定生成器'不询问嵌套的ICustomTypeDescriptor(路径为空)?
例如下面的数据绑定对话框中,我加入我的Person类作为StaticResource
,然后试图数据绑定到TESTBOX:
对于Person.Child
我我期待看到我的动态创建的属性(Name
和Age
),但正如你所看到的,它不能按预期工作? 这几乎就好像数据绑定对话框不在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));
}
}
}
我看到你的标签为VS2010,这似乎暗示.NET 4.0?你会在这里看到ICustomTypeDescriptor的绑定支持直到.NET 4.5才被添加:http://msdn.microsoft.com/en-us/library/bb613588%28v=vs.110%29.aspx – Brannon