依赖属性 提供一种全局内部属性存储来在运行时支持应用内的所有依赖属性,从而扩展基本的 Windows 运行时属性功能 。这种方法可以替代为具有专用字段的属性(在属性定义类中为专用)提供支持的标准模式。你可以将此内部属性存储视为任何特定对象的一组属性标识符和值(只要该对象是 DependencyObject 即可)。属性存储中的每个属性均通过 DependencyProperty 实例(而不是通过名称)进行标识。但是,大多数情况下,属性系统会隐藏该实现详细信息:你可以使用简单名称频繁访问依赖属性 。
1 public static DependencyProperty Register (string name, Type propertyType, Type ownerType, PropertyMetadata typeMetadata, ValidateValueCallback validateValueCallback) ;
Register重载方法最多提供了三种回调:
类 型
说 明
ValidateValueCallback
验证回调
PropertyChangedCallback
值改变回调
CoerceValueCallback
强制转化回调
下面我们来研究一下这三种回调的优先级和作用:
首先写一个父类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class TestDe : DependencyObject { public int TestInt { get { return (int )GetValue(TestInt_Property); } set { SetValue(TestInt_Property, value); } } public static readonly DependencyProperty TestInt_Property = DependencyProperty.Register ("TestInt" , typeof(int ), typeof(TestDe), new PropertyMetadata(100 , PropertyChanged, Coerce) , Validate); static void PropertyChanged (DependencyObject dobj, DependencyPropertyChangedEventArgs e) { Console.WriteLine(String.Format("PropertyChanged:{0} NewValue:{1} OldValue:{2}" , e.Property.Name, e.NewValue, e.OldValue)); } static object Coerce (DependencyObject dobj, object newValue) { Console.WriteLine(String.Format("Coerce - {0}" , newValue)); return newValue; } static bool Validate (object obj) { Console.WriteLine(String.Format("Validate - {0}" , obj)); return true ; } }
然后实例化这个类:
1 2 3 4 5 static void Main (string [] args) { TestDe Anti = new TestDe(); Console.ReadLine(); }
我们会发现,验证回调事件被执行了两遍,这是因为 实例化TestDe这个类的时候(因为int初始值为0),被验证了一次了,然后我们的注册函数给初始值的100的时候又验证了一次。
继续探索,我们开始修改这个对象的属性:
1 2 3 4 5 6 static void Main (string [] args) { TestDe Anti = new TestDe(); Anti.TestInt = 300 ; Console.ReadLine(); }
这次一共输出了5个条目,前两条前面已经说过了,我们开始解释后面。
▲Validate - 300 这个是我们实例化之后修改属性值触发的验证回调事件 ▲Coerce - 300 这个是强制转化的回调触发事件,为什么要一定要触发这个事件呢?查询MSDN发现:
img 因为属性值在赋值的时候,可能是通过一些函数方法触发的,比如Parse之类的,他们的类型是一个string,所以依赖属性会触发这个强制转换。
▲PropertyChanged: TestInt NewValue : 300 OldaValue:100
这个就不用说了,核心部分,就是当属性值改变的时候会触发的回调方法。
那么这个触发链可以看成是
验证 —》 强制转换 —》属性值改变回调
下面我研究的就是属性值的改变,验证回调的触发和规则:、 首先我们更改一下验证回调:
我们发现会触发ArgumentException异常,提示300不是TestInt的有效值,因为我们在回调验证函数里面写了 如果大于 300 则 返回 false
接下来我们研究一下子类重写父类的这些回调会发生什么:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class TestChild : TestDe { static TestChild () { TestDe.TestInt_Property.OverrideMetadata(typeof(TestChild), new PropertyMetadata(99 , PropertyChanged, Coerce)); } static void PropertyChanged (DependencyObject dobj, DependencyPropertyChangedEventArgs e) { Console.WriteLine(String.Format("TestChild Class - PropertyChanged:{0} NewValue:{1} OldValue:{2}" , e.Property.Name, e.NewValue, e.OldValue)); } static object Coerce (DependencyObject dobj, object newValue) { Console.WriteLine(String.Format("TestChild Class - Coerce - {0}" , newValue)); return newValue; } }
实例化:
我们会发现,父类,子类验证都会触发
我们更改子类的依赖属性值试试:
子类和父类的验证和属性改变回调都会依次被调用,但是强制转换只调用子类的。