WPF数据绑定 – “自定义类型描述符”的示例

我看到有几个人说WPF可以使用“自定义类型描述符”来表示“更改通知”。

我知道如何做变更通知的方式是:

object.GetBindingExpression(Bound.property).UpdateTarget(); 

或者让我的对象实现INotifiyPropertyChanged

我看到评论说自定义类型描述符也可以工作,但没有人给出一个很好的例子。 我现在要求这个例子(IE是WPF数据绑定和通过自定义类型描述符更新的一个很好的例子。)

这是一个非常简单的例子。

Window1.xaml

            Name:  Age:            

Window1.xaml.cs

 using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Windows; namespace CTDExample { public partial class Window1 : Window { public Window1() { InitializeComponent(); var ctd = new CTD(); ctd.AddProperty("Name"); ctd.AddProperty("Age"); DataContext = ctd; } } public class CTD : CustomTypeDescriptor { private static readonly ICollection _propertyDescriptors = new List(); public void AddProperty(string name) { _propertyDescriptors.Add(new MyPropertyDescriptor(name)); } public override PropertyDescriptorCollection GetProperties() { return new PropertyDescriptorCollection(_propertyDescriptors.ToArray()); } public override PropertyDescriptorCollection GetProperties(Attribute[] attributes) { return GetProperties(); } public override EventDescriptorCollection GetEvents() { return null; } public override EventDescriptorCollection GetEvents(Attribute[] attributes) { return null; } } public class MyPropertyDescriptor : PropertyDescriptor { private readonly IDictionary _values; public MyPropertyDescriptor(string name) : base(name, null) { _values = new Dictionary(); } public override bool CanResetValue(object component) { throw new NotImplementedException(); } public override Type ComponentType { get { throw new NotImplementedException(); } } public override object GetValue(object component) { object value = null; _values.TryGetValue(component, out value); return value; } public override bool IsReadOnly { get { return false; } } public override Type PropertyType { get { return typeof(object); } } public override void ResetValue(object component) { throw new NotImplementedException(); } public override void SetValue(object component, object value) { var oldValue = GetValue(component); if (oldValue != value) { _values[component] = value; OnValueChanged(component, new PropertyChangedEventArgs(base.Name)); } } public override bool ShouldSerializeValue(object component) { throw new NotImplementedException(); } public override void AddValueChanged(object component, EventHandler handler) { // set a breakpoint here to see WPF attaching a value changed handler base.AddValueChanged(component, handler); } } } 

我使用Kent Boogart的优秀且非常清晰的示例作为我的自定义类型的基础。

我认为应该对示例程序进行一些小的更改,以阐明CustomTypeDescriptorPropertyDescriptor之间的关系。

  1. 我相信数据应该存储在类型对象的实例上,而不是属性描述符。
  2. 通常我希望每个自定义类型实例保留它自己的属性描述符集合,而不是静态。 为了澄清这一点,我在类型属性描述符中添加了一些更多信息( Type )。

第二点实际上是域问题,但我希望更典型的用法需要实例属性数据,因为在编译时不知道属性时会使用这种类型。

MainWindow.xaml

            Name:  Age:            

MainWindow.xaml.cs

 using System.Windows; namespace CTDExample { public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); var ctd = new MyCustomType(); ctd.AddProperty("Name", typeof(string)); // Now takes a Type argument. ctd.AddProperty("Age", typeof(int)); DataContext = ctd; } } } 

MyCustomType.cs

 using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; namespace CTDExample { public class MyCustomType : CustomTypeDescriptor { // This is instance data. private readonly ICollection _propertyDescriptors = new List(); // The data is stored on the type instance. private readonly IDictionary _propertyValues = new Dictionary(); // The property descriptor now takes an extra argument. public void AddProperty(string name, Type type) { _propertyDescriptors.Add(new MyPropertyDescriptor(name, type)); } public override PropertyDescriptorCollection GetProperties() { return new PropertyDescriptorCollection(_propertyDescriptors.ToArray()); } public override PropertyDescriptorCollection GetProperties(Attribute[] attributes) { return GetProperties(); } public override EventDescriptorCollection GetEvents() { return null; } public override EventDescriptorCollection GetEvents(Attribute[] attributes) { return null; } private class MyPropertyDescriptor : PropertyDescriptor { // This data is here to indicate that different instances of the type // object may have properties of the same name, but with different // characteristics. private readonly Type _type; public MyPropertyDescriptor(string name, Type type) : base(name, null) { _type = type; } public override bool CanResetValue(object component) { throw new NotImplementedException(); } public override Type ComponentType { get { throw new NotImplementedException(); } } public override object GetValue(object component) { MyCustomType obj = (MyCustomType)component; object value = null; obj._propertyValues.TryGetValue(Name, out value); return value; } public override bool IsReadOnly { get { return false; } } public override Type PropertyType { get { return _type; } } public override void ResetValue(object component) { throw new NotImplementedException(); } public override void SetValue(object component, object value) { var oldValue = GetValue(component); if (oldValue != value) { MyCustomType obj = (MyCustomType)component; obj._propertyValues[Name] = value; OnValueChanged(component, new PropertyChangedEventArgs(Name)); } } public override bool ShouldSerializeValue(object component) { throw new NotImplementedException(); } public override void AddValueChanged(object component, EventHandler handler) { // set a breakpoint here to see WPF attaching a value changed handler base.AddValueChanged(component, handler); } } } } 

我希望我没有做任何吼叫,因为这是我的第一篇文章!