本章学习依赖项属性,英文原文 Dependency Property,它是传统 .Net Framework 属性的扩展,是 WPF 的专属,但所幸使用起来和传统属性几乎一样。WPF 元素所提供的大多数属性都是依赖项属性。

1. 定义依赖项:只能为依赖对象添加依赖项属性,即 DependencyObject,WPF 中大部分元素都继承 DependencyObject 。属性信息应该始终可用,并可能在多个对象间共享访问,因此必须将 Dependency Property 对象设置为与之关联的类的静态字段?我也没太明白,接着往下看解释:

例如,FrameworkElement 类定义了 Margin 属性,所有(继承它的)元素都共享该属性,这意味着在 FrameworkElement 类中应该这样定义 Margin:

public class FrameworkElement:UIElement,...
{
public static readonly DependencyProperty MarginProperty;
...
}

根据约定,依赖项属性的名称在末尾加上“Property”以识别和普通属性的不同。

2. 注册依赖项:使用前先注册,这一步需要确保在任何使用属性的代码前完成,因此必须在与之关联的静态构造函数中完成(readonly 关键字定义了该字段只能在其静态构造中被修改)。WPF 确保 DP 对象不能被直接实例化, 因为 DP 类没有公共构造函数,反而只能使用 DependencyProperty.Register() 方法创建,WPF 还确保其创建之后不能被修改,因为属性的值要作为 Register 方法的参数在静态构造中被设置。

先创建一个 FrameworkPropertyMetadata(该值表示希望通过依赖项属性使用什么服务,如支持数据绑定、动画或日志),然后,再用 DependencyProperty.Register() 注册

3. 像原来一样使用依赖项属性:注册后,使用传统的 .Net 包装一下,WPF 是使用 DependencyObject 基类中定义的 SetValue 和 GetValue 方法,如下:

public Thickness Margin{
set{ SetValue(MarginProperty,value); }
get{ return (Thickness)GetValue(MarginProperty); }
}

提示,在创建属性包装器是,应该只包含对 SetValue 和 GetValue 两个方法的操作,不要额外假如数据验证、事件操作等,因为这有可能会导致这些元素忽略正常的 Set 和 Get。清除属性值有特定的方法,继承自 DependencyObject 的 ClearValue 方法:myElement.ClearValue(FrameworkElement.MarginProperty)

4. 检索属性值:因为依赖项属性依赖于多个属性提供者,每个提供者都有自己的优先级,所以 WPF 以一种逐级检索的方式确定使用哪个值,其层级顺序(从低到高):

(1) 默认值,由 FrameworkPropertyMetadata 设置的值

(2) 通过继承,如果设置了 FrameworkPropertyMetadata.Inherits 标志,并且为包含层次中的某一个元素提供一个值(说实话,这句话没明白)

(3) 来自主题样式的值

(4) 来自项目样式的值

(5) 本地值,即使用代码或XAML直接设置的值

如上所示,可以通过直接应用一个值而覆盖掉整个层次,否则将由列表中前一个可用项确定。

5. 共享依赖项属性:一些类会共享同一个依赖项属性,比如 TextBlock 和 Control 都有 FontFamily 属性,他们指向同一个静态的依赖项属性,该属性实际上是在 TextElement 类中定义的 TextElement.FontFamilyProperty,由 TextElement 的静态构造函数注册,那两个类通过在其静态构造函数中嗲用 DependencyProperty.AddOwner() 方法重用该属性:

TextBlock.FontFamily = TextElement.FontFamilyProperty.AddOwner( typeof( TextBlock ) )

6. 属性验证:不要把验证属性值的代码像原来一样放到设置属性的逻辑中去,因为可能通过 WPF 的属性设置系统直接使用 SetValue 方法设置,从而使验证部分失灵(被绕过了),WPF 提供两种回调方法实现:

(1) ValidateValueCallback 可以接受或拒绝新值,通用用于捕捉违背属性约束的明显错误,可作为 DependencyProperty.Register() 的一个参数提供

(2) CoerceValueCallback 将新值修改为更能被接受的值,通常用于处理本身合法但与原值或某些层级默认值相冲突的新值,该方法作为构造 FrameworkPropertyMetadata 的一个参数提供

当应用程序设置一个依赖项属性时,它们的作用过程是:

(1) CoerceValueCallback 先有机会修改提供的值,或返回 DependencyProperty.UnserValue ,这会完全拒绝修改

(2) 激活 ValidateValueCallback,该方法返回 true 表示接受修改,返回 false 表示拒绝值。方法不能访问为之设置属性的实际对象,意味着,不能检查其它属性值。

(3) 以上两个方法都成功了,触发 PropertyChangedCallback 方法,这是如果希望通知其它类,可以在此触发事件

7. 验证回调:依赖项属性在注册时,Register 方法其中有一个可选参数,就是设置验证回调方法,写法如下

MarginProperty = DependencyProperty.Register("Margin",
typeof(Thickness),typeof(FrameworkElement),metadata,
new ValidateValueCallback(FrameworkElement.IsMarginValid))

最后一句就是验证回调,回调方法必须指向一个接受 object 参数并返回 bool 的方法,也就是说语句中的 IsMarginValid 方法必须是

private static bool IsMarginValid(object value){ }

对于验证回调,有一个限制,就是必须是静态方法且无权访问正在被验证的对象。所能够获得的信息就只是刚被传进来的 value,比如某元素有 Maximum 和 Minimum 两个属性,设置 Maximum 时候应判断不能小于 Minimum,但这在验证回调函数中是不能实现的,因为它不能访问 Minimum 。解决这种情况,可以使用 6 中提到的 CoerceValueCallback,即强制回调。

8. 强制回调:通过 FrameworkPropertyCallback 使用 CoerceValueCallback,如

FrameworkPropertyMetadata metadata = new FrameworkPropertyMetadata();
metadata.CoerceValueCallback = new CoerceValueCallback( CoerceMaximum ); DependencyProperty.Register( "Maximum",typeof(double),typeof(Rangebase),metadata);

通过 CoerceValueCallback 可以处理互相关联的属性。对于强制回调的应用,在书中有一大段实例说明,忘记的话还是回去翻翻书吧。

迟到的 WPF 学习 —— 依赖项属性的更多相关文章

  1. WPF的依赖项属性

    WPF的依赖项属性 属性与事件是.NET抽象模型的核心部分.WPF使用了更高级的依赖项属性(Dependency Property)功能来替换原来.NET的属性,实现了更高效率的保存机制,还添加了附加 ...

  2. 学习WPF——初识依赖项属性

    入门 首先创建一个依赖项属性 然后绑定父容器的DataContext到这个依赖项的实例 接着绑定子元素的属性到依赖项属性(注意Button的Content属性) 程序最终的运行结果:   说明 首先是 ...

  3. [转]WPF 依赖项属性

    from:http://blog.csdn.net/datoumimi/article/details/8033682 ps:环境限制,发的东西一长就会被拦截,所以删了一部分 UI软件中经常会用到大量 ...

  4. 浅谈WPF依赖项属性

    浅谈WPF依赖项属性 0. 引言 依赖项属性虽然在使用上和CLR属性一样,但是它是WPF特有的,不同于CLR属性.只是封装为我们常用CLR的属性,在语法使用上和CLR属性一样.WPF中一些功能:动画, ...

  5. 如何在 WPF 中获取所有已经显式赋过值的依赖项属性

    原文:如何在 WPF 中获取所有已经显式赋过值的依赖项属性 获取 WPF 的依赖项属性的值时,会依照优先级去各个级别获取.这样,无论你什么时候去获取依赖项属性,都至少是有一个有效值的.有什么方法可以获 ...

  6. WPF学习系列之二 (依赖项属性)

    依赖属性;(dependency property)  它是专门针对WPF创建的,但是WPF库中的依赖项属性都使用普通的.NET属性过程进行了包装.从而可能通过常规的方式使用它们,即使使用他们的代码不 ...

  7. WPF中的依赖项属性

    Form cnblogs 桂素伟 随着WPF的推广,不得不重新拾起WPF来,因为这块的产品越来越多. 只能跟着MSDN来学了,所以想是在这里记录下学习的过程和对知识的理解. 先从最基本的吧,依赖项属性 ...

  8. WPF中的依赖项属性(转)

    出处:https://www.cnblogs.com/axzxs2001/archive/2010/04/25/1719857.html 随着WPF的推广,不得不重新拾起WPF来,因为这块的产品越来越 ...

  9. WPF教程四:字段、属性、依赖项属性的演变过程

    这个章节主要讲解属性是什么,为什么会演变出依赖项属性,依赖属性的优势是什么.以及如何更好的使用属性和依赖项属性. 一.属性 属性是什么. 翻了好几本C#的书和微软的文档,我觉得对属性讲解比较好理解的就 ...

随机推荐

  1. 【C语言的日常实践(十六)】字符串输出功能puts、fputs和printf

    C有三个标准库函数的输出字符串puts().fputs()和printf(). 1.puts()函数仅仅须要给出字符串參数的地址. #include <stdio.h> int puts( ...

  2. Group and sum array of hashes by date

    I have an array of hashes like this: [{:created=>Fri, 22 Jan 2014 13:02:13 UTC +00:00, :amount=&g ...

  3. C#中对值类型和引用类型的一点认识

    区别值类型和引用类型的重要一点就是值类型赋值的时候是给出一块内存空间,空间里放下要赋给值类型的值.而引用类型是开辟一块内存空间,空间里放下的是要赋给引用类型值的指向地址. 就像一个是复制了银行卡里的现 ...

  4. Access to the temp directory is denied. Identity 'NT AUTHORITY\NETWORK SERVICE' under which XmlSerializer is running does not have sufficient permiss

    造成错误的原因是用bat代码清理系统垃圾时造成的权限丢失而引起的 错误描述 1.An error occurred creating the configuration section handler ...

  5. Swift入门教程:基本语法(一)

          简介:                                                                                       什么是S ...

  6. HDU 4324 Triangle LOVE 拓扑排序

    Problem Description Recently, scientists find that there is love between any of two people. For exam ...

  7. WPF应用程序支持多国语言解决方案

    原文:WPF应用程序支持多国语言解决方案 促使程序赢得更多客户的最好.最经济的方法是使之支持多国语言,而不是将潜在的客户群限制为全球近70亿人口中的一小部分.本文介绍四种实现WPF应用程序支持多国语言 ...

  8. webBrowser 参数设置

    //禁用脚本错误等类似的窗口信息 this.webBrowser1.ScriptErrorsSuppressed = true; //禁用右键菜单 this.webBrowser1.IsWebBrow ...

  9. 在ubuntu纯字符gdb界面下来开发调试嵌入式ARM

    前面一个帖子介绍了使用eclipse来开发STM32的固件,但有的时候使用Eclipse的GDB调试器会崩溃掉,反复这样造成我们开发的效率降低,信心也会受一打击. 最近接触到的许多源码,就是在linu ...

  10. AjaxPro使用说明文档

    ajaxpro下载地址 AjaxPro使用说明     1 目录     2 修改历史纪录     3 1.什么是Ajax     4 2.为什么使用Ajax     4 3.Ajax应用场景     ...