WPF自学入门(五)WPF依赖属性
在.NET中有事件也有属性,WPF中加入了路由事件,也加入了依赖属性。最近在写项目时还不知道WPF依赖属性是干什么用的,在使用依赖项属性的时候我都以为是在用.NET中的属性,但是确实上不是的,通过阅读文章和看WPF的书籍已经了解了WPF的依赖属性的使用,我们今天就来看看为什么WPF中要加入依赖属性?
一、什么是依赖属性
WPF中的依赖属性有别于.NET中的属性,因为在WPF中有几个很重要的特征都是需要依赖项属性的支持,例如数据绑定,动画,样式设置等。WPF绝大多数属性都是依赖项属性,只不过它是用了普通的.NET属性过程进行了包装,通过这种包装,就可以像使用属性一样使用依赖项属性了,在后面会说一下怎么通过这种方式包装的。这就使用了旧技术来包装新技术的设计理念就不会干扰.NET。WPF中的依赖属性主要有以下三个优点:
1、依赖属性加入了属性变化通知、限制、验证等功能。这样可以使我们更方便地实现应用,同时大大减少了代码量。
2、节约内存:在WinForm中,每个UI控件的属性都赋予了初始值,这样每个相同的控件在内存中都会保存一份初始值。而WPF依赖属性很好地解决了这个问题,它内部实现使用哈希表存储机制,对多个相同控件的相同属性的值都只保存一份。
3、支持多种提供对象:可以通过多种方式来设置依赖属性的值。可以配合表达式、样式和绑定来对依赖属性设置值。
刚才我们一直在说属性,先来看看属性是什么吧。先创建一个类Person,里面有name属性。
public class Person
{
public string name{set;get;}
}
上面就是创建好的属性,看着是不是很简单。属性的创建就是这么简单,在我们想要使用这个类的地方初始化就能用。
既然说WPF中绝大多数的属性都是依赖项属性,我看了一下依赖属性怎么进行创建。
1、依赖属性的所在类型继承自DependencyObject类。
2、使用public static 声明一个DependencyProperty的变量,该变量就是真正的依赖属性。
3、类型的静态构造函数中通过Register方法完成依赖属性的元数据注册。
4、提供依赖属性的包装属性,通过这个属性来完成对依赖属性的读写操作。
创建代码如下:
//依赖属性必须在依赖对象DependencyObject
Public class Person : DependencyObject
{
//CLR属性包装器,使得依赖属性NameProperty在外部能够像普通属性那样使用
public string Name
{
get { return (string)GetValue(NameProperty); }
set { SetValue(NameProperty, value); }
}
//依赖属性必须为static readonly
//DependencyProperty.Register 参数说明
//第一个参数是string类型的,是属性名。
//第二个参数是这个依赖项属性的类型。
//第三个参数是这个拥有这个依赖项属性的类型。
//第四个参数是具有附加属性设置的FramWorkPropertyMetadata对象。
public static readonly DependencyProperty NameProperty =
DependencyProperty.Register("Name", typeof(string), typeof(Person), new PropertyMetadata("DefaultName"));
}
从上面代码可以看出,依赖属性是通过调用DependencyObject的GetValue和SetValue来对依赖属性进行读写的。它使用哈希表来进行存储的,对应的Key就是属性的HashCode值,而值(Value)则是注册的DependencyPropery;而C#中的属性是类私有字段的封装,可以通过对该字段进行操作来对属性进行读写。属性是字段的包装,WPF中使用属性对依赖属性进行包装。
二、依赖属性的优先级
WPF 属性系统提供一种强大的方法,使得依赖属性的值由多种因素决定,从而实现诸如实时属性验证、后期绑定以及向相关属性发出有关其他属性值发生更改的通知等功能。 用来确定依赖属性值的确切顺序和逻辑相当复杂。 了解此顺序有助于避免不必要的属性设置,并且还有可能澄清混淆,使你正确了解为何某些影响或预测依赖属性值的尝试最终却没有得出所期望的值。依赖属性可以在多个位置“设置”,界面代码如下:

本地属性集在设置时具有最高优先级,动画值和强制除外。 如果在本地设置某个值,你可以期待该值优先得到应用,甚至期待其优先级高于任何样式或控件模板。 在上面示例中,此处Background本地设置为红色。 因此,即使它是隐式样式,否则将会应用于该作用域中的该类型的所有元素,在此作用域中定义的样式不是最高优先级给予Background属性及其值。 如果从该 Button 实例中删除本地值红色,样式将获得优先级,而按钮将从该样式中获得 Background 值。 在该样式中,触发器具有优先级,因此当鼠标位于按钮上时,按钮为蓝色,其他情况下则为绿色。
下面的图是在网上找的依赖属性优先级列表图,大家后面再使用属性时可以留意一下优先级。

三、依赖属性的继承
依赖属性的继承是WPF属性系统的一项功能。 属性值继承使元素树中的子元素可以从父元素获取特定属性的值,并继承该值,就如同它是在最近的父元素中任意位置设置的一样。 父元素可能也已通过属性值继承获得了其值,因此系统有可能一直递归到页面根。 属性值继承不是默认属性系统行为;属性必须用特定的元数据设置来建立,以便使该属性对子元素启动属性值继承。

看到上面图片你可能已经发现了问题:StatusBar没有显式设置FontSize值,但它的字体大小没有继承Window.FontSize的值,而是保持了系统的默认值。导致这样的问题是因为并不是所有元素都支持属性值继承的,如StatusBar、Tooptip和Menu控件。另外,StatusBar等控件截获了从父元素继承来的属性,并且该属性也不会影响StatusBar控件的子元素。例如,如果我们在StatusBar中添加一个Button。那么这个Button的FontSize属性也不会发生改变,其值为默认值。
四、自定义依赖属性
如果想要依赖属性继承,我们可以进行自定义依赖属性继承属性值。
自定义属性步骤:
1、创建派生类CustomStackPanl

创建派生类CustomButton

2、在window控件中引入命名空间
xmlns:sys="clr-namespace:System;assembly=mscorlib"
3、在页面添加Button

效果:

五、依赖属性验证和强制功能
在写代码是都会考虑可能发生的错误。在定义属性时,也需要考虑错误设置属性的可能性。对于传统.NET属性,可以在属性的设置器中进行属性值的验证,不满足条件的值可以抛出异常。但对于依赖属性来说,这种方法不合适,因为依赖属性通过SetValue方法来直接设置其值的。然而WPF有其代替的方式,WPF中提供了两种方法来用于验证依赖属性的值。
1、ValidateValueCallback:该回调函数可以接受或拒绝新值。该值可作为DependencyProperty.Register方法的一个参数。
2、CoerceValueCallback:该回调函数可将新值强制修改为可被接受的值。例如某个依赖属性工作年龄的值范围是25到55,在该回调函数中,可以对设置的值进行强制修改,对于不满足条件的值,强制修改为满足条件的值。如当设置为负值时,可强制修改为0。该回调函数PropertyMetadata构造函数参数进行传递。
WPF自学入门(五)WPF依赖属性的更多相关文章
- WPF自学入门(六)WPF带标题的内容控件简单介绍
在WPF自学入门(二)WPF-XAML布局控件的文章中分别介绍StackPanel,WarpPanel,DockPanel,Grid,Canvas五种布局容器的使用,可以让我们大致了解容器可以使用在什 ...
- WPF自学入门(十一)WPF MVVM模式Command命令
在WPF自学入门(十)WPF MVVM简单介绍中的示例似乎运行起来没有什么问题,也可以进行更新.但是这并不是我们使用MVVM的正确方式.正如上一篇文章中在开始说的,MVVM的目的是为了最大限度地降低了 ...
- WPF自学入门(十二)WPF MVVM模式提取函数
我们平时在写代码时为了不重复写代码,会进行复制代码或者写通用方法.今天我们就来把上传做的函数提取成为通用的方法调用.把上次写的函数提取为两个主要的文件:ObserableObject和RelayCom ...
- WPF自学入门(十一)WPF MVVM模式Command命令 WPF自学入门(十)WPF MVVM简单介绍
WPF自学入门(十一)WPF MVVM模式Command命令 在WPF自学入门(十)WPF MVVM简单介绍中的示例似乎运行起来没有什么问题,也可以进行更新.但是这并不是我们使用MVVM的正确方式 ...
- WPF自学入门(三)WPF路由事件之内置路由事件
有没有想过在.NET中已经有了事件机制,为什么在WPF中不直接使用.NET事件要加入路由事件来取代事件呢?最直观的原因就是典型的WPF应用程序使用很多元素关联和组合起来,是否还记得在WPF自学入门(一 ...
- WPF系列 —— 控件添加依赖属性(转)
WPF系列 —— 控件添加依赖属性 依赖属性的概念,用途 ,如何新建与使用.本文用做一个自定义TimePicker控件来演示WPF的依赖属性的简单应用. 先上TimePicker的一个效果图. 概念 ...
- WPF学习(5)依赖属性
今天我们来学习WPF一个比较重要的概念:依赖属性.这里推荐大家看看周永恒大哥的文章,讲的确实很不错.我理解的没那么深入,只能发表一下自己的浅见.提到依赖属性,不得不说我们经常使用的传统的.net属性, ...
- WPF自学入门(一)WPF-XAML基本知识
一.基本概念 1.XAML是派生自XML的可扩展应用程序标记语言(Extensible Application Markup Language)由微软创造应用在WPF,Silverlight等开发技术 ...
- WPF自学入门(四)WPF路由事件之自定义路由事件
在上一遍博文中写到了内置路由事件,其实除了内置的路由事件,我们也可以进行自定义路由事件.接下来我们一起来看一下WPF中的自定义路由事件怎么进行创建吧. 创建自定义路由事件分为3个步骤: 1.声明并注册 ...
随机推荐
- block,inline,inline-block的区别
最近正在复习,紧张地准备几天后的笔试,然后刚好看到这个地方. block:块级元素,会换行,如div,p,h1~h6,table这些,可以设置宽高: inline:行内元素,不换行,挤在一行显示 ...
- Linux下配置SNAT上网
局域网有一台主机A,没有公网的IP, 也就是没有办法直接连到互联网上下载东西,同时内网有另外一台主机B,有公网接入.这个时候为了让A连接到互联网,我把B设置成NAT主机,A的网关指向B.准确的来说,现 ...
- J2EE和android的GZIP测试
使用GZIP进行数据压缩传输实验,服务端是J2EE,使用HTTP的POST方式进行数据请求. 为了方便测试,刚开始在J2EE的环境下写了一个TestCase去调用J2EE写的服务,忘记写GZIP解压代 ...
- CODE大全浅谈谷歌adsense与PIN码
我的博客:CODE大全:www.codedq.net:业余草:www.xttblog.com:爱分享:www.ndislwf.com或ifxvn.com. 近期由于校园招聘笔试和面试等诸多忙碌时间,博 ...
- Spring Boot 2.0(二):Spring Boot 2.0尝鲜-动态 Banner
Spring Boot 2.0 提供了很多新特性,其中就有一个小彩蛋:动态 Banner,今天我们就先拿这个来尝尝鲜. 配置依赖 使用 Spring Boot 2.0 首先需要将项目依赖包替换为刚刚发 ...
- java.net.UnknownHostException
java.net.UnknownHostException 错误解决方向 查看 测试真机或者模拟机是否连上了网络. 如果不是第一步错误的话,一般就是测试机没有链接上网络,可以打开个网页或者其他 ...
- python调试
如果很简单的程序,建议还是pirnt打出来. 对于Linux环境,使用pdb/ipdb是一个不错的选择. 安装ipdb sudo pip install ipdb 开启调试 手动在需要调试的地方写入s ...
- 经典案例之MouseJack
引言:在昨天的文章<无线键鼠监听与劫持>中,我们提到今天会向您介绍一个无线键鼠的监听与劫持的经典案例,<MouseJack>:MouseJack能利用无线鼠标和键盘存在的一些问 ...
- MinGW下简单编译FFmpeg
2009.03.21补充:ffmpeg-0.5正式发布,地址为:[url]http://www.ffmpeg.org/releases/ffmpeg-0.5.tar.bz2[/url].修改了第7步, ...
- Android okHttp网络请求库详解
okhttp 是一个 Java 的 HTTP+SPDY 客户端开发包,同时也支持 Android.需要Android 2.3以上. 特点 OKHttp是Android版Http客户端.非常高效,支持S ...