4 WPF依赖属性

理解依赖属性

依赖属性支持的特征包括:动画、数据绑定、样式。由WPF元素暴露的属性大部分都是依赖属性。依赖属性和常规属性的使用方法相同。

WPF设计了依赖属性支持其特有的动态特性,并且不干扰其他系统的.net代码。

定义依赖属性

创造一个依赖属性的语法完全不同于创造一个普通的.NET属性。

第一步是定义一个代表属性的对象。这是DependencyProperty类的一个实例。关于你属性的信息需要一直是可用的,甚至可能在类之间共享(常见在WPF元素中)。因此,你的DependencyProperty对象必须被定义为相关类的一个静态字段。

例如,FrameworkElement类定义了一个Margin属性。Margin被所有元素共享,是一个依赖属性:

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

根据命名约定,定义依赖属性的字段名字是正常属性加上单词Property后缀。那样,你能区分依赖属性定义和实际属性的名字。字段使用readonly关键字,这意味着它只能在FrameworkElement类的静态构造函数中设置,如何设置见下节。

注册依赖属性

下一步是注册你的依赖属性。因为要在使用属性之前完成注册,必须在相关类的一个静态构造函数中执行它。

不能直接实例化DependencyProperty对象,因为DependencyProperty类没有公开的构造函数。代替,一个DependencyObject实例只能使用静态的DependencyProperty.Register()方法被创造。DependencyProperty对象被创造之后不能再修改,因为所有的DependencyProperty成员是只读的。代替,它们的值必须作为Register()方法的参数被提供。

下面例子显示FrameworkElement类的Margin属性是如何被注册的:

static FrameworkElement()
{var metadata = new FrameworkPropertyMetadata(new Thickness(), FrameworkPropertyMetadataOptions.AffectsMeasure);MarginProperty = DependencyProperty.Register("Margin",typeof(Thickness), typeof(FrameworkElement), metadata,new ValidateValueCallback(FrameworkElement.IsMarginValid));...
}

注册一个依赖属性包括二步。首先,你创造一个FrameworkPropertyMetadata对象,指明希望使用依赖属性的什么服务(诸如支持数据绑定,动画,和日志)。其次,依靠调用DependencyProperty.Register()静态方法注册属性。这时,你负责提供一些关键成分:

  • 属性名称
  • 属性的数据类型
  • 属性所在类的类型
  • 可选,附带有属性设置的FrameworkPropertyMetadata对象
  • 可选,执行属性验证的回调

两个可选属性值得研究。FrameworkPropertyMetadata的详细描述见95页。

包装依赖属性

创造依赖属性的最后一步是用一个传统.NET属性包装它。WPF属性使用的是定义在DependencyObject基类的GetValue()和SetValue()方法。

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

当你创造属性包装时,你应该仅调用SetValue()和GetValue(),如在前例中。你不应该添加任何额外的代码验证值,引起事件,等等。那是因为另外的特征可能旁路属性包装,直接调用SetValue()和GetValue()。(一个例子是在运行时当一个编译XAML文件被解析时。)SetValue()和GetValue()都是公开的。

验证输入值应使用DependencyProperty.ValidateValueCallback。

引发事件应使用FrameworkPropertyMetadata.PropertyChangedCallback 。

现在可以使用属性了:

myElement.Margin = new Thickness(5);

之后,可能希望移除局部值设置,仿佛你从未设置它。依靠从DependencyObject继承的ClearValue()方法。

myElement.ClearValue(FrameworkElement.MarginProperty);

使用依赖属性

依赖属性支持两个关键的行为:改变通知和动态值求解。

改变通知

如果你希望对一个属性的改变作出反应,你有二个选择—创造一个绑定,或写一个触发器。但是,依赖属性没有提供响应属性值改变的事件。

动态值求解

依赖属性因动态值求解的行为而得名。一个依赖属性依赖于多个属性提供者,每个提供者带有它自己的优先级。当你从一个属性值取回一个值时,WPF属性系统经历一系列步骤求得最终值。首先,它通过考虑下列因素决定属性的基值。优先级从最低的到最高排列(最下面的赢):

  1. 默认值(由FrameworkPropertyMetadata对象设置)
  2. 继承的值(如果FrameworkPropertyMetadata.Inherits标记被设置,并且一个值已经应用到某个祖先元素)
  3. 主题样式值
  4. 工程样式值
  5. 本地值(使用代码或标记直接设置的值)

基值不一定是最终的属性值,WPF通过4个步骤求得属性值:

  1. 基值
  2. 表达式(数据绑定和资源)
  3. 动画
  4. 通过CoerceValueCallback修正值

共享依赖属性

一些类共享依赖属性,即使他们有独立的类层次结构。例如,TextBlock.FontFamily和Control.FontFamily都指向同一个依赖属性,它实际上被定义在TextElement类中以及TextElement.FontFamilyProperty。TextElement类的静态构造函数注册属性,但是TextBlock和Control类的静态构造函数简单地调用DependencyProperty.AddOwner()方法重用它:

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

自定义类

副作用

附加依赖属性

附加属性是依赖属性,并且它被WPF属性系统管理。区别是应用附加属性的类不是定义它的类。

为定义一个附加属性,你使用RegisterAttached()方法而不是Register()。这是一个注册Grid.Row属性的例子:

var metadata = new FrameworkPropertyMetadata(0, new PropertyChangedCallback(Grid.OnCellAttachedPropertyChanged));Grid.RowProperty = DependencyProperty.RegisterAttached("Row", typeof(int),typeof(Grid), metadata, new ValidateValueCallback(Grid.IsIntValueNotNegative));

就像一个普通的依赖属性,你能提供一个FrameworkPropertyMetadata对象和一个ValidateValueCallback。

当创造附加属性时,你没有定义.NET属性包装。那是因为附加属性能被设置在任何依赖对象上。例如,Grid.Row属性可能被设置在一个Grid对象上(如果你有一内部嵌套另一个Grid的Grid)或在另外的一些元素上。事实上,即使元素不在一个Grid内,和即使在你的元素树上不存在Grid对象,Grid.Row属性也能被设置在那个元素上。

代替使用一个.NET属性包装,附加属性要求能调用的一对静态方法去设置和获得属性值。这些方法使用熟悉的SetValue()和GetValue()方法(从DependencyObject类继承)。静态的方法应该被命名SetPropertyName()和GetPropertyName()。

这里是实现Grid.Row附加属性的静态方法:

public static int GetRow(UIElement element)
{if (element == null){throw new ArgumentNullException("");}return (int)element.GetValue(Grid.RowProperty);
}
public static void SetRow(UIElement element, int value)
{if (element == null){throw new ArgumentNullException("");}element.SetValue(Grid.RowProperty, value);
}

使用代码设置一个元素位于网格的第一行:

Grid.SetRow(txtElement, 0);

可选地,你能直接调用SetValue()或GetValue()方法,旁路掉静态方法:

txtElement.SetValue(Grid.RowProperty, 0);

属性验证

WPF提供两种方法阻止无效值:

  • ValidateValueCallback:这回调能接受或拒绝新值。通常,这回调被用来捕获违反属性的约束明显错误。提供它作为DependencyProperty.Register()方法的参数。
  • CoerceValueCallback:这回调能修改新值为更可接受的值。通常,这回调被用来处理被设置在同一对象的依赖属性值之间的冲突。这些值可能单独是有效的,但是当应用在一起时不一致。为使用这回调,当创造FrameworkPropertyMetadata对象时,提供它作为构造函数的参数,此对象随后被传递到DependencyProperty.Register()方法。

这里是当应用程序试图设置一个依赖属性时:所有的部件如何起作用:

  1. 首先,CoerceValueCallback方法有机会修改提供值(通常,为使它与其它属性一致)或返回DependencyProperty.UnsetValue,这完全拒绝改变。
  2. 其次,ValidateValueCallback被引发。这方法返回真接受一个值作为有效,或返回假拒绝它。不同于CoerceValueCallback,ValidateValueCallback不访问设置属性的实际对象,这意味着你不能检查其它的属性值。
  3. 最后,如果先前两个阶段都成功了,PropertyChangedCallback被触发。这时,你能引发事件去通知其它类。

Validation回调

相当于正常属性的set部分中的验证。

其签名为接受一个object输入参数,返回布尔值。返回值为真表示接受,为假表示拒绝。

private static bool IsMarginValid(object value)
{Thickness thickness1 = (Thickness) value;return thickness1.IsValid(true, false, true, false);
}

有一个限制,它是一个静态方法,不能访问正被验证的对象,不能使用对象中的其他属性。

Coercion回调

用于验证互相关联的属性

private static object CoerceMaximum(DependencyObject d, object value)
{RangeBase base1 = (RangeBase)d;if (((double) value) < base1.Minimum){return base1.Minimum;}return value;
}

转载于:https://www.cnblogs.com/cuishengli/archive/2013/06/01/3112538.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/408800.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

机器学习入门系列(1)--机器学习概览

本文比较长&#xff0c;八千字&#xff0c;建议收藏起来慢慢看&#xff01;此外&#xff0c;这其实是合并公众号最开始写的两篇文章&#xff0c;整合在一起了。机器学习入门系列(1)--机器学习概览(上)机器学习入门系列(2)--机器学习概览(下)主要参考《hands-on-ml-with-sklearn…

[bbk5307]第76集 第9章 -数据库性能维护 03

/* Oracle optimizer 执行选择方式原理分析 */ select * from emp where empno7369; oracle在执行查询计划的时候&#xff0c;并不是说要执行一次全表扫描和一次索引扫描之后&#xff0c;来决定到底是走哪一条路?而是通过数据字典里的统计数据信息&#xff0c;来分析判断到底是…

[资源]推荐一些Python书籍和教程,入门和进阶的都有!

前几天后台有读者留言说希望推荐一些入门的书籍&#xff0c;所以这几天都在整理一些我入门时候学习过的书籍教程&#xff0c;或者是口碑还不错的书籍&#xff01;入门和进阶书籍教程入门和进阶方面的书籍教程&#xff0c;这里推荐两本书和一个教程。1. 廖雪峰老师的 Python 教程…

html 状态栏不显示文字,电脑打字的时候输入法不显示状态栏怎么办?

有时我们在打字的时候&#xff0c;输入法不显示&#xff0c;能打出汉字&#xff0c;但无法选字&#xff0c;这就给输入字体造成了很大的麻烦。怎么解决呢&#xff1f;下面以搜狗输入法为例&#xff0c;描述详细解决过程。解决方法一1、我在某个网页输入字体的时候&#xff0c;没…

系统在iis6上部署

1. 安装Framework 4.0 服务器安装Framework4.0版本。 2. 安装IIS 2.1 安装IIS6.0步骤 1) 在添加或删除程序,单击“添加/删除Windows组件”。 2) 勾选“应用程序服务器”&#xff0c;并单击“详细信息”。 3) 勾选“ASP.NET/IIS/启用网络COM访问/启用网络DTC访问”信…

[Github 项目推荐] 一个更好阅读和查找论文的网站

第 28 篇原创文章机器学习发展到现在&#xff0c;已经积累了非常多的文章&#xff0c;特别是深度学习火起来后&#xff0c;每年新增加的论文非常多&#xff0c;如果需要研究某个领域&#xff0c;不仅需要阅读这个领域经典的论文&#xff0c;也必须时刻关注最新的学术进展&#…

html下拉选择框箭头改为年,CSS自定义select下拉选择框的样式(不用其他标签模拟)...

今天群里有人问到怎么自定义select下拉选择框的样式&#xff0c;于是群里就展开了激烈的讨论&#xff0c;刚开始一直就是考虑怎样使用纯CSS实现&#xff0c;把浏览器默认的样式覆盖掉&#xff0c;但最后均因兼容问题处理不好而失败告终&#xff0c;最后的解决方案就是用其他的元…

【语言处理与Python】10.1自然语言理解\10.2命题逻辑

10.1自然语言理解 查询数据库 如果有人提出一个问题&#xff1a; Which country is Athens in? 得到的回答应该是&#xff1a; Greece. 这个数据可以通过数据库语言得到答案&#xff1a; SELECT Country FROM city_table WHERE City athens 这里有一个文法&#xff0c;可以把句…

程序员的数学笔记3--迭代法

第三节课程&#xff0c;介绍的是迭代法。 前两节笔记的文章&#xff1a; 程序员的数学笔记1–进制转换程序员的数学笔记2–余数 03 迭代法 什么是迭代法 迭代法&#xff0c;简单来说&#xff0c;其实就是不断地用旧的变量值&#xff0c;递推计算新的变量值。 这里采用一个…

html网页响应时间调试,HTML5 使用performance.now衡量Webworker的响应时间

JavaScript语言&#xff1a;JaveScriptBabelCoffeeScript确定var worker, start, end,send document.querySelector(.send),receive document.querySelector(.receive > span),bar document.querySelector(.bar > span);var sendMessage function() {start performa…

机器学习入门系列(2)--如何构建一个完整的机器学习项目(一)

上一篇机器学习入门系列&#xff08;1&#xff09;–机器学习概览简单介绍了机器学习的一些基本概念&#xff0c;包括定义、优缺点、机器学习任务的划分等等。 接下来计划通过几篇文章来介绍下&#xff0c;一个完整的机器学习项目的实现步骤会分为几步&#xff0c;最后会结合《…

在Web服务器磁盘上缓存数据和HTML页面

有时候&#xff0c;有“许多”数据要在内存中缓存。“许多”是相对而言的&#xff0c;它取决于能消耗多少内存、缓存项目的数量以及取回数据的频度。任何情况下&#xff0c;如果需要在内存中缓存大量的数据&#xff0c;请考虑以text或者XML文件格式在Web服务器硬盘上做缓存。当…

html5 支持音频格式,html5中audio支持音频格式

HTML5 Audio标签能够支持wav, mp3, ogg, acc, webm等格式&#xff0c;但有个很重要的音乐文件格式midi(扩展名mid)却在各大浏览器中都没有内置的支持。不是所有的浏览器都支持MP3 OGG之类的&#xff0c;每个浏览器因为版权的问题支持的格式都是不一样的。浏览器和音频兼容性浏览…

Ubuntu 8.04 Linux系统下面编译更新内核版本

在 VirtualBox 虚拟机上面测试的&#xff0c;ubuntu 8.04系统。1. 下载内核源代码http://www.kernel.org/ 下载The latest stable version of the Linux kernel is: 2.6.25.7 &#xff0c;点后面的“F” 按钮下载http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.25.…