【转】【WPF】关于依赖属性的ValidateValueCallback,PropertyChangedCallback和CoerceValueCallback的执行顺序
三个回调对应依赖属性的验证过程,改变过程和强制转换过程。
class Dobj : DependencyObject { //依赖属性包装 public int MyProperty { get { return (int)GetValue(MyPropertyProperty); } set { SetValue(MyPropertyProperty, value); } } //注册依赖属性 //注意依赖属性默认值是:71 public static readonly DependencyProperty MyPropertyProperty = DependencyProperty.Register("MyProperty", typeof(int), typeof(Dobj), new PropertyMetadata(71, PropertyChanged, CoerceValue), ValidateValue); //属性改变 static void PropertyChanged(DependencyObject dobj, DependencyPropertyChangedEventArgs e) { Debug.WriteLine(String.Format("PropertyChanged - 属性:{0} 新值:{1} 旧值:{2}", e.Property.Name, e.NewValue, e.OldValue)); } //强制转换 static object CoerceValue(DependencyObject dobj, object newValue) { Debug.WriteLine(String.Format("CoerceValue - {0}", newValue)); return newValue; } //验证 static bool ValidateValue(object obj) { Debug.WriteLine(String.Format("ValidateValue - {0}", obj)); return true; } }
当仅仅定义一个新对象时:
var dobj = new Dobj();
调试下输出:
ValidateValue - 71 ValidateValue - 71
验证过程被执行了两次,我不知道为什么这样。
接着修改这个对象的属性。
var dobj = new Dobj(); dobj.MyProperty = 999;
输出:
ValidateValue - 71 ValidateValue - 71 ValidateValue - 999 CoerceValue - 999 PropertyChanged - 属性:MyProperty 新值:999 旧值:71
默认值被验证了两遍,接着验证新值,强制转换,最后属性改变回调。
接下来修改一下验证回调,把返回值改为false。
//验证 static bool ValidateValue(object obj) { Debug.WriteLine(String.Format("ValidateValue - {0}", obj)); if ((int)obj == 999) return false; return true; }
赋值语句(SetValue方法)会抛出ArgumentException异常,消息:’999′ is not a valid value for property ‘MyProperty’.(999并不是MyProperty属性的合法值)。
下面要做到内容是创建一个当前依赖对象的继承类,并改写父类依赖属性的元数据。
代码:
//继承原来的依赖对象 class SuperDobj : Dobj { static SuperDobj() { //改写父类依赖属性的元数据,默认值改成81 Dobj.MyPropertyProperty.OverrideMetadata(typeof(SuperDobj), new PropertyMetadata(81, PropertyChanged, CoerceValue)); } //属性改变 static void PropertyChanged(DependencyObject dobj, DependencyPropertyChangedEventArgs e) { Debug.WriteLine(String.Format("SuperDobj.PropertyChanged - 属性:{0} 新值:{1} 旧值:{2}", e.Property.Name, e.NewValue, e.OldValue)); } //强制转换 static object CoerceValue(DependencyObject dobj, object newValue) { Debug.WriteLine(String.Format("SuperDobj.CoerceValue - {0}", newValue)); if ((int)newValue == 999) throw new Exception("test"); return newValue; } }
还是像刚才,先定义一个对象:
var superdobj = new SuperDobj();
输出:
ValidateValue - 71 ValidateValue - 71 ValidateValue – 81
父类和子类的验证都要执行一遍。
接着设置子类的依赖属性:
var superdobj = new SuperDobj(); superdobj.MyProperty = 999;
输出:
ValidateValue - 71 ValidateValue - 71 ValidateValue - 81 ValidateValue - 999 SuperDobj.CoerceValue - 999 PropertyChanged - 属性:MyProperty 新值:999 旧值:81 SuperDobj.PropertyChanged - 属性:MyProperty 新值:999 旧值:81
这个结果很有意思。
看来子类和父类的验证和属性改变回调都会依次被调用,但是强制转换只调用子类的。
事实上属性元数据此时会调用PropertyMetadata.Merge方法来合并多个属性元数据。可以参考MSDN:http://msdn.microsoft.com/zh-cn/library/system.windows.propertymetadata.merge.aspx