本章学习依赖项属性,英文原文 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. VisualStudio 自动排版等 快捷键

    VisualStudio2010自动排版快捷键:全部代码排版:1. ctrl+E,D 按住ctrl,相继按下E.D                          2. ctrl+K,F 按住ctr ...

  2. oracle_查询Oracle正在执行和执行过的SQL语句

    ---正在执行的select a.username, a.sid,b.SQL_TEXT, b.SQL_FULLTEXT  from v$session a, v$sqlarea b where a.s ...

  3. 【分享】小工具大智慧之Sql执行工具

    原文:[分享]小工具大智慧之Sql执行工具 工具概况 情况是这样的,以前我们公司有很多Sql用于完成一些很不起眼但又不得不完成的业务,出于方便就直接在Sql查询分析器里执行,按理说应该写一些专门的工具 ...

  4. hardware_hp存储映射_方案

    修改虚拟磁盘映射方式 每个刀片独立对应映射存储空间 这样就不会造成数据写入冲突, old new 步奏: 创建过程  lun号码  1-155 之间 第二步奏 最后 指定: 就ok了 2012年12月 ...

  5. 只有有lua编译能力不足200K代码吧?NO! Python 有可能。

    如今Python给人的感觉是大,东西多,在Windows上安装后竟然要占100多兆的空间. lua给人的感觉是非常小,非常轻便.Python 2.7在linux下编译出来的代码在strip之后也有3M ...

  6. HDU 4873 ZCC Loves Intersection(可能性)

    HDU 4873 ZCC Loves Intersection pid=4873" target="_blank" style="">题目链接 ...

  7. Android开展Exception:ActivityNotFoundException: Unable to find explicit activity class

    project出现在一个以上的activity,不AndroidManifest.xml配置,在阅读的时候,你需要知道的配置activity,使用时间或忘记配置.流汗!配置activity后proje ...

  8. Factorization Machines 学习笔记(二)模型方程

      近期学习了一种叫做 Factorization Machines(简称 FM)的算法,它可对随意的实值向量进行预測.其主要长处包含: 1) 可用于高度稀疏数据场景:2) 具有线性的计算复杂度.本文 ...

  9. UIImage分类:返回一个可以拉伸的图片

    // 返回一个可拉伸的图片 // UIImage的分类 + (UIImage *)resizedImage:(NSString *)name { UIImage *image = [self imag ...

  10. 移植MonkeyRunner的图片对比和获取子图功能的实现-Appium篇

    如果你的目标测试app有很多imageview组成的话,这个时候monkeyrunner的截图比较功能就体现出来了.而其他几个流行的框架如Robotium,UIAutomator以及Appium都提供 ...