依赖属性详解
简介:当你开始用WPF编程的时候,很快就会碰到“依赖属性 ”。它们和一般的.Net属性看起来很相似,但简单概念之后则是更复杂和更强大。 主要的区别在于:平常的.NET属性的值直接读取 于类的一个私有属性,而依赖属性的值则是通过调用继承自DependencyObject的GetValue()方法动态赋值 的。 当你给一个依赖属性赋值时,它不是存储在对象的字段 中,而是在存储在基类DependencyObject提供的一个键-值配对的字典 中。一条记录中的键(Key)就是该属性的名称,而值(Value)则是想要设置的值。 依赖属性的优点:
值访问策略每次访问一个依赖属性,它内部会按照下列的顺序由高到底处理该值。它首先确认自身的值是否可用,如果不可用,则会触发一个自定义的样式触发器……继续直到它找到一个值。最后默认值经常是可用的。
背后的秘密每一个WPF控件注册了一系列的依赖属性在静态的DependencyProperty类中。他们由一个键值(对每个类都是唯一的)和包含默认值和回调函数的原数据组成。 所有要使用依赖属性(DependecyProperties)的类型都必须由DependencyObject来驱动。这个基类定义了一个键值字典来存储依赖属性的所有值。记录中的键则是依赖属性主要申明的。 当你通过.Net属性包装器访问依赖属性的时候,它在内部会调用一个方法GetValue(DependencyProperty)来访问值。下图详细的解释了该方法使用的值解决策略。 如果当前值是可用的,那么就直接从字典(Dictionary)里读出该值。如果没有值被设定,它将上升到整个逻辑树,寻找一个可继承的值。如果没有找到可继承的值,它将被设置为在属性原数据中定义好的默认值。下面的序列有点简化,但它显示了主要的思想。
创建依赖属性创建一个依赖属性,需添加一个DepdencyProperty类型的静态字段,并调用DependencyProperty.Register()来创建一个依赖属性的实例。依赖属性一般需要以…Property结尾。这样符合PWF的命名规范。 为了使依赖属性像一般的.Net属性一样被访问,则需要添加一个属性包装器。该包装器除了通过继承自DependencyObject的GetValue()和SetValue()方法,以DependencyProperty作为键值来设置和读取它的值外不做任何事情。 强调:不要在这些属性中添加任何逻辑,因为它们仅仅当在代码中赋值的时候才被调用。而在XAML中可直接调用SetValue方法设定属性 。 如果你使用的是Visual Studio,你可以输入propdp在敲两次tab键来自动创建一个依赖属性。
代码
每一个依赖属性都提供为修改通知,值的强制转换和验证提供了一些回调函数,这些函数须在依赖属性中注册。
值的修改回调: 修改回调是一个静态方法,任何时候,只要TimeProperty的值改变了,它都会被调用。新的值会在EventArgs参数传输,此次改变的对象则在source里传输。
代码
值的限制回调: 限制制回调函数允许调整一个值,如果出界,将会抛出一个异常。一个好的例子就是在进度条中设置一个最大上限值或者最小下限值。这种情况下我们可以限定值在允许的范围内。下面的例子我们排出了已经过去了的时间。
值的验证回调:验证回调用来检验要设置的值是否有效。如果返回无效的(False),则抛出一个ArgmentException的异常。我们例子的要求是数值必须是DataTime的实例.
只读的依赖属性:
一些WPF控件的依赖属性是只读的。它们经常用于报告控件的状态, 像IsMouSEOver属性。 为它提供赋值是没有意思的。
或许你会问自己,为什么不使用一般的.Net属性?一个重要的原因就是一般的.Net属性不能设置触发器(Trigger)。
创建一个只读的属性跟创建一个平常的属性一样。仅仅用DependencyProperty.RegisterReadonly()替换了 DependencyProperty()。它将返回一个DependencyPropertyKey。这个键值可以保存在类的私有或者保护的静态只读字 段里。该键值在类的内部提供了一个赋值的入口,便可以像一般属性一样使用了。
紧接着第二件事就是注册一个公开的依赖属性指向DependencyPropertyKey.DependencyProperty。这个属性对外部的访问便是只读的。
代码
附加属性:
附加属性是一种特殊的依赖属性。他允许给一个对象添加一个值,而该对象可能对此值一无所知。
本节最好的例子就是布局面板。每一个布局面板都需要不同的数据来组织它的子元素。如Canvas需要Top和left,DockPanel需要 Dock。此外你也可以写自己的布局面板,所以这个系列将是无限制的.所以你很清楚的明白,在WPF控件中有所有的属性是不可能的.
这个问题的解决方案就是附加属性.它们被定义在一个需要从其他控件的指定内容中获取的数据的控件中.比如一个元素由它的父布局面板布置. 给附加属性赋值,需在XAML中添加一个以该元素开头的属性.如在画布面板中设置Canvas.Top和Canvas.Left来部署一个按钮,你可以这样写:
代码
监视依赖属性的改变:
代码
变清除当前值: 因为null也是一个有效的设定值,所以就用DependencyProperty.UnsetValue来表示一个为设定的值。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |