前一个博客,介绍了依赖属性的基本定义,在定义的过程中register中的的两个参数,并没有传入参数,不知道其是用来干什么的,以下,我们将介绍这两个参数的真正用途FrameworkPropertyMetadata和ValidateValueCallback。
1、FrameworkPropertyMetadata 参数
FrameworkPropertyMetadata是一个重要的参数,其用于配置当前的依赖属性的特性,这个对象的有很多构造函数,我们使用一个比较常用的构造函数
public FrameworkPropertyMetadata( Object defaultValue, FrameworkPropertyMetadataOptions flags, PropertyChangedCallback propertyChangedCallback )
那么FrameworkPropertyMetadata 的作用是什么呢?我们看看这个FrameworkPropertyMetadata对象的几个属性:
编号 | 名称 | 说明 |
1 | AffectsArrange | 获取或设置一个值,该值指示依赖项属性是否会影响布局引擎运行期间的排列处理过程。 |
2 | AffectsMeasure | 获取或设置一个值,该值指示依赖项属性是否会影响布局引擎运行期间的测量处理过程。 |
3 | AffectsParentArrange | 获取或设置一个值,该值指示依赖项属性是否会影响布局引擎运行期间其父元素布局的排列处理过程。 |
4 | AffectsParentMeasure | 获取或设置一个值,该值指示依赖项属性是否会影响布局引擎运行期间其父元素布局的测量处理过程。 |
5 | AffectsRender | 获取或设置一个值,该值指示依赖项属性是否会以某种方式(这种方式不会具体影响排列或测量,但将请求重绘)对常规布局造成潜在影响。 |
6 | BindsTwoWayByDefault | 获取或设置一个值,该值指示默认情况下属性是否双向绑定。 |
7 | CoerceValueCallback | 获取或设置对此元数据中所指定 CoerceValueCallback 实现的引用 |
8 | DefaultUpdateSourceTrigger | 获取或设置在应用具有该元数据的属性的绑定时要使用的 UpdateSourceTrigger 的默认值,这些绑定的 UpdateSourceTrigger 设置为 Default。 |
9 | DefaultValue | 获取或设置依赖项属性的默认值.(继承自 PropertyMetadata。) |
10 | IsAnimationProhibited | 获取或设置一个值,声明是否应在应用了包含元数据实例的依赖项对象上禁用动画。(继承自 UIPropertyMetadata。) |
11 | IsDataBindingAllowed | 获取一个值,该值指示依赖项属性是否支持数据绑定。 |
12 | IsNotDataBindable | 获取或设置一个值,该值指示依赖项属性是否支持数据绑定。 |
13 | IsSealed | 获取一个值,该值确定是否已通过某种方式将元数据应用于属性,从而导致该元数据实例变为不可变状态。(继承自 PropertyMetadata。) |
14 | Journal | 获取或设置一个值,该值指示该属性是否包含应用程序可以或应该存储为日记实现一部分的日记信息。 |
15 | OverridesInheritanceBehavior | 获取或设置一个值,该值指示属性值继承计算是否应跨越元素的逻辑树中的某些内容边界。 |
16 | PropertyChangedCallback | 获取或设置对此元数据中所指定 PropertyChangedCallback 实现的引用。 (继承自 PropertyMetadata。) |
17 | SubPropertiesDoNotAffectRender | 获取或设置一个值,该值指示依赖项属性的子属性是否影响包含对象的呈现。 |
我们对几个关键属性进行分析:
AffectsArrange、AffectsMeasure、AffectsParentArrange、AffectsParentMeasure、AffectsRender。
五个属性,主要是用于定义当前依赖属性的改变,是否影响控件调整。如果设置AffectsArrange=true,属性的变化会造成控件重新排列。
BindsTwoWayByDefault: 指定属性是否是双向绑定,这个会在绑定的地方详细讲解
CoerceValueCallback:一个回调函数,用于在验证依赖属性之前尝试“纠正”属性值。我们可以简单的案例说明:
class Example:DependencyObject { static Example() { FrameworkPropertyMetadata metadata = new FrameworkPropertyMetadata(); metadata.DefaultValue = "example"; metadata.CoerceValueCallback = new CoerceValueCallback(CoerceMaxValue); NameProperty = DependencyProperty.Register("Name", typeof(string), typeof(Example), metadata); } public static DependencyProperty NameProperty; public String Name { set { SetValue(NameProperty, value); } get { return (string)GetValue(NameProperty); } } private static object CoerceMaxValue(DependencyObject d, object baseValue) { string base1 = baseValue.ToString(); if (base1.Length>10) { return "err"; } return baseValue; } }
我们使用这个依赖属性
Example e = new Example(); e.Name = "333"; MessageBox.Show(e.Name); e.Name = "3333333333333"; MessageBox.Show(e.Name);
我们可以到,第一个弹出框显示333,第二个弹出框,显示err,所以CoerceValueCallback的作用就是验证传入的依赖属性,并且可以修改属性,并且可以用来修改类型,可以把字符串red修改为color对象。
IsAnimationProhibited、IsDataBindingAllowed、IsSealed、IsSealed、SubPropertiesDoNotAffectRender:
标记依赖属性的一些特性,比如是否可以应用与动画或者数据绑定等。
PropertyChangedCallback:
属性,这个属性比较有用,代表属性发生变化的时候,调用的函数,这个函数在CoerceValueCallback函数调用之后调用,代表属性已经确定完成的最后一个步骤,我们简单案例如下:
static Example() { FrameworkPropertyMetadata metadata = new FrameworkPropertyMetadata(); metadata.DefaultValue = "example"; metadata.CoerceValueCallback = new CoerceValueCallback(CoerceMaxValue); metadata.PropertyChangedCallback = new PropertyChangedCallback(OnItemsSourceChanged); NameProperty = DependencyProperty.Register("Name", typeof(string), typeof(Example), metadata); } public static DependencyProperty NameProperty; public String Name { set { SetValue(NameProperty, value); } get { return (string)GetValue(NameProperty); } } private static object CoerceMaxValue(DependencyObject d, object baseValue) { string base1 = baseValue.ToString(); if (base1.Length>10) { return "err"; } return baseValue; } private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { MessageBox.Show("finish"); }
调用代码:
Example e = new Example(); e.Name = "333"; e.Name = "3333333333333";
我们可以看到,finish被弹出了两次,每次属性改变都会调用此函数。
2、ValidateValueCallback参数
在定义任何类型属性的时候,都需要面对错误设置属性的情况,对于传统属性来说,可以通过get/set方法中,对属性进行验证,但是wpf虽然也有get/set,但是其设置方式和传统属性完全不同,无法通过get/set中进行验证,那么wpf提供FrameworkPropertyMetadata中的回调函数进行判断,在CoerceValueCallback 中对值进行判断合法性,但在设置给对象之前,还需要调用ValidateValueCallback函数,最终确定是否修改值,ValidateValueCallback回调会返回true和false,赋值和不赋值,假如赋值发生修改,则会调用PropertyChangedCallback回调,基本案例如下:
class Example:DependencyObject { static Example() { FrameworkPropertyMetadata metadata = new FrameworkPropertyMetadata(); metadata.DefaultValue = "example"; metadata.CoerceValueCallback = new CoerceValueCallback(CoerceMaxValue); metadata.PropertyChangedCallback = new PropertyChangedCallback(OnItemsSourceChanged); NameProperty = DependencyProperty.Register("Name", typeof(string), typeof(Example), metadata,new ValidateValueCallback(ValidateValue)); } public static DependencyProperty NameProperty; public String Name { set { SetValue(NameProperty, value); } get { return (string)GetValue(NameProperty); } } private static object CoerceMaxValue(DependencyObject d, object baseValue) { string base1 = baseValue.ToString(); if (base1.Length>10) { return "err"; } return baseValue; } static bool ValidateValue(object obj) { if (obj.ToString() == "err") { return false; } return true; } private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { MessageBox.Show("finish"); } }
代码经过以上的修改,我们发现finish只会弹出一次,返回false后,则程序会抛出异常