的DependencyProperty:审定,胁迫及变化处理(第一部分:WPF中)
介绍
依赖项属性是WPF的一个重大创新。 一个依赖项属性作为一个CLR属性相同的简单和熟悉的编程接口,但允许其值可动态决定/其他属性,样式,模板,数据绑定,动画,元素组成,类的继承等一样,受多种因素的改变,可以实现提供自足默认值,验证,胁迫和事件逻辑。 Silverlight的实现WPF属性系统功能的一个子集,因此,WPF和Silverlight之间有显着性差异。 WPF和Silverlight之间的直线移植可能是不可能的,主要的源代码的变化,可能需要。 这三部分后系列将使用一个简单的例子来演示WPF和Silverlight相依性属性,两个属性系统,以及如何从一个到另一个港口之间的差异,实现共同的模式,然后使用我写的NumericUpDown控制Silverlight工具包演示了如何复杂和棘手的依赖项属性可以在Silverlight。 我只会集中审定,胁迫和变化,在这一系列处理。 当我发现的时候,我可能会写上依赖项属性的其他方面。
WPF依赖属性概述
MSDN有良好的依赖项属性概述 ,所以我将只调用了三个核心类和两个重要的WPF属性系统的编程接口的方法:
- DependencyProperty的 ,它提供了属性,如名称,OwnerType,PropertyType,如注册,RegisterAttached,RegiterReadOnly,RegisterAttachedReadOnly方法:
(DependencyPropertyValueSerializer))] [TypeConverter的(“System.Windows.Markup.DependencyPropertyConverter,PresentationFramework,版本= 4.0.0.0,文化=中立,PublicKeyToken =列出,自空 ”),ValueSerializer(typeof运算 (DependencyPropertyValueSerializer))]
公共密封类的DependencyProperty
{
/ /字段
公共静态只读对象 UnsetValue的;
/ /方法
公众的DependencyProperty AddOwner(类型ownerType);
“公共 DependencyProperty的AddOwner”(类型ownerType,PropertyMetadata typeMetadata);
公共重写 GetHashCode()方法;
公共 PropertyMetadata可用getMetaData(类型forType);
公共 PropertyMetadata可用getMetaData(DependencyObject的DependencyObject的);
公共 PropertyMetadata可用getMetaData(DependencyObjectType dependencyObjectType);
); 公共的布尔 IsValidType( 对象值 );
); 公共,BOOL IsValidValue( 对象值 );
公共无效 OverrideMetadata(类型forType,PropertyMetadata typeMetadata);
公共无效 OverrideMetadata(类型forType,PropertyMetadata typeMetadata,关键的DependencyPropertyKey);
name, Type propertyType, Type ownerType); 公共静态的DependencyProperty注册( 字符串名称,类型propertyType,ownerType型);
name, Type propertyType, Type ownerType, PropertyMetadata typeMetadata); 公共静态的DependencyProperty注册( 字符串名称,类型propertyType,键入ownerType,PropertyMetadata typeMetadata);
name, Type propertyType, Type ownerType, PropertyMetadata typeMetadata, ValidateValueCallback validateValueCallback); 公共静态的DependencyProperty注册( 字符串名称,类型propertyType,类型ownerType,PropertyMetadata typeMetadata,ValidateValueCallback validateValueCallback;);
name, Type propertyType, Type ownerType); 公共静态的DependencyProperty RegisterAttached( 字符串名称,的类型propertyType,类型ownerType);
name, Type propertyType, Type ownerType, PropertyMetadata defaultMetadata); 公共静态的DependencyProperty RegisterAttached( 字符串名称,的类型propertyType,类型ownerType,defaultMetadata PropertyMetadata);
name, Type propertyType, Type ownerType, PropertyMetadata defaultMetadata, ValidateValueCallback validateValueCallback); 公共静态的DependencyProperty RegisterAttached( 字符串名称,的类型propertyType,类型ownerType PropertyMetadata defaultMetadata,ValidateValueCallback validateValueCallback)的;
name, Type propertyType, Type ownerType, PropertyMetadata defaultMetadata); 公共静态的DependencyPropertyKey RegisterAttachedReadOnly(类型ownerType, 字符串名称,类型propertyType,PropertyMetadata defaultMetadata);
name, Type propertyType, Type ownerType, PropertyMetadata defaultMetadata, ValidateValueCallback validateValueCallback); 公共静态的DependencyPropertyKey RegisterAttachedReadOnly( 字符串名称,的类型propertyType,类型ownerType,PropertyMetadata defaultMetadata,ValidateValueCallback的validateValueCallback);
name, Type propertyType, Type ownerType, PropertyMetadata typeMetadata); 公共静态的DependencyPropertyKey RegisterReadOnly(类型ownerType, 字符串名称,类型propertyType,PropertyMetadata typeMetadata);
name, Type propertyType, Type ownerType, PropertyMetadata typeMetadata, ValidateValueCallback validateValueCallback); 公共静态的DependencyPropertyKey RegisterReadOnly( 字符串名称,的类型propertyType,类型ownerType,PropertyMetadata typeMetadata,ValidateValueCallback的validateValueCallback);
覆盖公共字符串的ToString();
/ /属性
公共 PropertyMetadata DefaultMetadata {获取;}
公共诠释 GlobalIndex的{得到;}
公共字符串名称{获取;}
公共的类型OwnerType {获得;}
公共的类型PropertyType {获得;}
公共BOOL只读{获取;}
公共 ValidateValueCallback ValidateValueCallback的{获取;}
} - DependencyObject的 ,它提供了类似的GetValue,SetValue的,ReadLocalValue,CoerceValue,ClearValue访问/修改一个依赖项属性的值的方法:
, typeof (NameScope))] [TypeDescriptionProvider(typeof运算 (DependencyObjectProvider)),NameScopeProperty(“名称范围 ”,typeof运算 (名称范围))]
公共类 DependencyObject的:DispatcherObject的
{
/ /方法
公共 DependencyObject的();
公共无效 ClearValue(DependencyProperty的DP);
公共无效 ClearValue(关键的DependencyPropertyKey);
公共的无效 CoerceValue(DependencyProperty的DP);
obj); 公共密封覆盖布尔等于( 对象obj);
公共密封覆盖的GetHashCode();
“的公共 LocalValueEnumerator GetLocalValueEnumerator();
公共对象的GetValue(DependencyProperty的DP);
公共的无效 InvalidateProperty(DependencyProperty的DP);
保护虚拟无效 OnPropertyChanged(DependencyPropertyChangedEventArgs E);
公共,对象 ReadLocalValue(DependencyProperty的DP);
); 公共无效 SetCurrentValue(DP的DependencyProperty 对象的值 );
); 公共无效的SetValue(DependencyProperty的DP, 对象的值 );
); 公共无效的SetValue(关键的DependencyPropertyKey, 对象的值 );
/ /属性
公共 DependencyObjectType DependencyObjectType的{获取;}
set; } 内部,UINT EffectiveValuesCount {[FriendAccessAllowed]; 私人集;}
公共BOOL的 IsSealed {获取;}
} - PropertyMetadata,这使得依赖产权登记过程中指定的默认值,胁迫和改变处理逻辑:
公共类 PropertyMetadata
{
/ /方法
公共 PropertyMetadata();
defaultValue); 公共 PropertyMetadata( 对象的DefaultValue);
公共 PropertyMetadata(propertyChangedCallback PropertyChangedCallback);
defaultValue, PropertyChangedCallback propertyChangedCallback); 公共 PropertyMetadata( 对象的DefaultValue,PropertyChangedCallback propertyChangedCallback);
defaultValue, PropertyChangedCallback propertyChangedCallback, CoerceValueCallback coerceValueCallback); 公共 PropertyMetadata( 对象的DefaultValue,PropertyChangedCallback propertyChangedCallback,CoerceValueCallback coerceValueCallback;;);
保护虚拟无效合并(PropertyMetadata baseMetadata,DependencyProperty的DP);
保护的虚拟的无效 OnApply(DP的DependencyProperty,TARGETTYPE型);
/ /属性
公共 CoerceValueCallback的CoerceValueCallback {获取;设置;}
公共对象的DefaultValue {;}
保护BOOL的 IsSealed {获取;}
公共 PropertyChangedCallback PropertyChangedCallback {;}
} - DependencyProperty.Register的*方法和他们的重载
- PropertyMetadata构造
例子
下面的例子中有一个简单的类MyButton的,从Button类继承并实现一个依赖项属性MyValue。 MyValue属性的值必须介于0到10强制执行,其验证的逻辑IsValidMyValue()。 MyValue财产的有效价值取决于它的默认值(0),用户输入(一组请求参数),从基类继承其IsEnabled属性值。 最后的依赖,实施强制的逻辑CoerceMyValue和依赖改变的事件的句柄OnIsEnabledChanged()。 整体MyValue执行演示在WPF依赖属性的共同模式:
- CLR包装:{公众诠释MyValue获得;设置;}
- 依赖属性标识符: 公共静态只读DependencyProeprty MyValueProperty
- 产权制度登记:DependencyProperty.Register的 ()
- 验证逻辑:IsValidMyValue静态方法
- 胁迫逻辑:CoerceMyValue的静态方法
这是常见的,并建议也实现改变处理逻辑通过:
- PropertyChangedCallback OnMyValueChanged静态方法
- 保护虚拟无效OnMyValueChanged的(oldValue,newValue)以提高Changed事件,子类重写
- 公共静态只读RoutedEvent的MyValueChangedEvent路由事件标识符和事件登记
- 公共的事件RoutedPropertyChangedEventHandler <int>的MyValueChanged客户端的事件
下面是示例的源代码:
- Window1.xaml中:
x:Class ="WpfApp1.Window1" < 窗口的X: 类 =“WpfApp1.Window1” XMLNS =“http://schemas.microsoft.com/winfx/2006/xaml/presentation” 的xmlns:X =“http://schemas.microsoft.com/winfx/2006/xaml” 的xmlns:我的 “CLR命名空间:WpfApp1” Height ="300" Width ="300" > 标题 =“Window1的” 高度 =“300” 宽度 =“300”> > < 的StackPanel> x:Name ="mybtn" Content ="MyButton" < 我:MyButton的 x:名称 =“mybtn” 内容 =“MyButton的” Click ="mybtn_Click" /> MyValueChanged =“mybtn_MyValueChanged的” 点击 =的的“mybtn_Click”/> > </ StackPanel中 > > </ 窗口 “>”
- window1.xaml.cs:
使用系统; 使用 System.Windows; 使用 System.Windows.Controls的; 命名空间 WpfApp1 { / /示例类来演示如何实现一个DependencyProperty 公共类 MyButton的按钮 { / / DP:CLR包装 公众诠释 MyValue { )GetValue(MyValueProperty); }获取回报(INT)的GetValue(MyValueProperty);} 设置{SetValue的(MyValueProperty, 值 );} } / / DP:依赖属性标识符及登记 公共静态只读的DependencyProperty MyValueProperty = DependencyProperty.Register的( ( int ), typeof (MyButton), “MyValue”,typeof运算(INT),typeof运算 (MyButton的), 新 PropertyMetadata(0, 新 PropertyChangedCallback(OnMyValueChanged) 新 CoerceValueCallback(CoerceMyValue)), 新 ValidateValueCallback(IsValidMyValue)); / / DP:验证回调 ) 私有静态,BOOL IsValidMyValue( 对象的值 ) { ) value ; newValue =(int)的值 ; 返回 newValue> = 0 && newValue <= 10; } / / DP:强制回调 ) 私有静态的对象 CoerceMyValue(DependencyObject的对象的值 D,) { MyButton的CTRL =(MyButton的)D; ) value ; newValue =(int)的值 ; 返回 ctrl.IsEnabled? (5 newValue)以Math.Min Math.Max(newValue)以6; } / / DP:改变的回调 私人静态无效 OnMyValueChanged的(DependencyObject的D,DependencyPropertyChangedEventArgsé) { MyButton的CTRL =(MyButton的)D; )e.OldValue; oldValue =(INT)e.OldValue; )e.NewValue; newValue =(INT)e.NewValue; ctrl.OnMyValueChanged(oldValue,newValue)以; } / /重新:更改事件标识及登记 公共静态只读 RoutedEvent的MyValueChangedEvent = EventManager.RegisterRoutedEvent(“MyValueChanged”,RoutingStrategy.Bubble >), typeof (MyButton)); typeof运算 (RoutedPropertyChangedEventHandler < 整数>),typeof运算 (MyButton的)); / /重新更改事件 > MyValueChanged; 公共事件 RoutedPropertyChangedEventHandler <> MyValueChanged; / /:使用受保护的虚拟提高事件 oldValue, int newValue) (oldValue,int newValue)在保护虚拟无效 OnMyValueChanged { RoutedPropertyChangedEventArgs <> E = >(oldValue, newValue); 新 RoutedPropertyChangedEventArgs <>(oldValue,newValue)以; e.RoutedEvent = MyValueChangedEvent; 的RaiseEvent(E); } / / DP:事件处理程序引发的MyValue重新计算,因为变化的依赖 sender, DependencyPropertyChangedEventArgs e) 私有静态无效 OnIsEnabledChanged( 对象发件人,DependencyPropertyChangedEventArgs北京时间) { MyButton的CTRL =(MyButton的)发件人; ctrl.CoerceValue(MyButton.MyValueProperty); } 公共 MyButton的() { IsEnabledChanged + = OnIsEnabledChanged; } } / / / <summary> / / /为Window1.xaml中的互动逻辑 / / / </摘要> 公共部分类 Window1的:窗口 { 公共 Window1的() { 的InitializeComponent(); } sender, RoutedEventArgs e) 私人无效 mybtn_Click( 对象发件人,RoutedEventArgs北京时间) { } sender, RoutedPropertyChangedEventArgs< int > e) 私人无效 mybtn_MyValueChanged的( 对象发件人,RoutedPropertyChangedEventArgs <> E) { oldValue = e.OldValue; newValue = e.NewValue; } } }
如何依赖于WPF知识产权工作
为了演示如何在WPF依赖属性,我设置了一个破发点的大部分功能,使用即时调试窗口,检查的价值观和改变状态。
注册
有效的价值
在MyButton的实例,点击触发破发点上mybtn_Click事件处理程序,然后使用“即时”窗口中,检查MyValue财产。 如下所示:
- 即使mybtn.MyValue没有分配任何价值,它有一个有效的价值为0,这依赖项属性的默认值,如显示通过的mybtn.MyValue mybtn.GetValue的结果。
- 重要的是,CLR包装和GetValue / SetValue调用应始终具有相同的效果。 这是由CLR包装只是一个暂时的GetValue / SetValue和没有更多的包装。
- mybtn.ReadLocalValue(MyButton.MyValueProperty)结果显示,有没有MyValue财产mybtn实例的本地存储。
- 当mybtn.MyValue初始值,没有任何变化通知,作为OnMyValueChanged是不是在程序开始调用。
验证
在“即时”窗口,设置命令“mybtn.MyValue = -1”输入mybtn.MyValue到一个无效的值-1:
- 被称为CLR的包装,这反过来又调用SetValue的,这会触发验证新值-1。
- IsValidMyValue新值-1返回false,WPF属性系统,然后抛出ArgumentException:
- 通过三种方式检查的价值MyValue:CLR包装的GetValue,ReadLocalValue:什么都没有改变。 这是重要的,因为在Silverlight状态变化,甚至无效的设置操作,所以我们不得不编写代码来恢复状态,我会出现在两个系列的一部分。
强迫
再次在“即时”窗口,尝试设置mybtn.MyValue至8日,这是有效的,但由于mybtn.IsEnabled是真实的,有效的值必须小于或等于5:
- 首先,验证被称为新的价值8,通过CLR包装和SetValue:
- IsValidMyValue(8)返回true,所以被称为强制逻辑CoerceMyValue,通过CLR包装的SetValue,UpdateEffectiveValue,ProcessCoerceValue:
- CoerceMyValue(8)返回一个不同的值5,所以WPF属性系统调用IsValidMyvalue受胁迫的有效值为5:
- IsValidMyValue(5)返回true,所以WPF属性系统调用改变逻辑OnMyValueChanged oldValue和newValue为0,为5。 这两个值的值是有效的,因为有老没有在mybtn实例值,新的价值实际上是8。 OnMyValueChanged轮流致电其proctected的虚拟版本,提高MyValueChanged路由事件,并执行MyValueChanged事件处理程序,如果有任何。
- 检查MyValue财产的价值:两个CLR包装和GetValue返回新的有效值为5,但GetLocalValue返回8,记住原来的用户请求。 这是非常重要的,我们将看到未来。
动态重新计算的依赖性变动
现在让我们设置mybtn.IsEnabled为false,在“即时”窗口。 这变化之一MyValue的依赖关系,这应该引起MyValue财产的有效价值的重新计算,如果我有编码是正确的(我做了,当然
:
- 首先,请注意,IsEnabled的变化处理是同步的,也就是说,被称为OnIsEnabledChanged前“mybtn.IsEnabled的假”的回报。 这是很重要的,因为IsEnabled的变化处理上的Silverlight异步。
- 我们要触发重新计算,因为产权制度不知道MyValue取决于对IsEnabled的。 这是通过处理IsEnabledChanged事件(IsEnabledChanged + = OnIsEnabledChanged MyButton的()),并呼吁从内OnIsEnabledChanged事件处理程序CoerceValue的。
- 在页转到CoerceValue调用UpdateEffectiveValue,ProcessCoerceValue,那么我们的强制逻辑CoerceMyValue。 请注意,CoerceMyValue被称为newValue 8,而不是目前的有效值为5。 原设置请求参数8记住mybtn本地实例,ReadLocalValue结果之前所示。 这一点很重要,因为Silverlight不这样做,这使得实施强制非常棘手,将在Silverlight RangeBase和它的子类的错误,如Slider和ScrollBar的博客系列的第3部分所示。
- 由于mybtn.IsEnabled现在是假的,最初请求的值变为有效,所以CoerceMyValue回报8。
- 8从以前的5有效价值是不同的,,,所以UpdateEffectieValue呼吁NotifyPropertyChange,最终要求我们改变的逻辑oldValue和newValue 5 8 OnMyValueChanged。 发生这种情况即使没有MyValue财产的一套新的操作。 这是IsEnabled的依赖关系变化造成MyValue有效的值的变化,在变成触发器MyValue属性更改通知和事件处理,以及这一切发生的同步。
- 胁迫,变更通知和事件处理结束后,检查MyValue财产的价值:现在所有这三种方法,(mybtn.MyValue mybtn.GetValue,mybtn.ReadLocalValue)返回相同的结果。
- 最后一个实验:的类型mybtn.ClearValue在立即窗口中清除依赖项属性的本地值(8),这反过来又触发改变处理逻辑OnMyValueChanged,0 newValue(MyButton.MyValueProperty),新的有效的价值来自MyValue的默认属性。
结论
正如我们可以看到从上面的例子和实验,WPF有一个强大的知识产权制度,这使得实施和使用依赖属性很容易。 这是一个很大的Silverlight虽然棘手,因为Silverlight实现的WPF功能的一个子集。 在后系列的第二部分,我将重新在Silverlight实现上面的例子,并展示WPF和Silverlight之间的差异。 在第三部分,我将使用RangeBase的NumericUpDown来展示Silverlight中,这是这系列的原始动机上的疑难杂症。 敬请期待!
PS系列的第一篇文章,结束了很多时间,耗费更多的时间比我预想的,所以我会停在这里。 如果有足够的兴趣,我可以上传你的项目实验,并规定执行WPF依赖属性大部分管道的代码片段。 谢谢!








最新评论