在.NET中有事件也有属性,WPF中加入了路由事件,也加入了依赖属性。最近在写项目时还不知道WPF依赖属性是干什么用的,在使用依赖项属性的时候我都觉得是在用.NET中的属性,可是确实上不是的,经过阅读文章和看WPF的书籍已经了解了WPF的依赖属性的使用,咱们今天就来看看为何WPF中要加入依赖属性?函数
WPF中的依赖属性有别于.NET中的属性,由于在WPF中有几个很重要的特征都是须要依赖项属性的支持,例如数据绑定,动画,样式设置等。WPF绝大多数属性都是依赖项属性,只不过它是用了普通的.NET属性过程进行了包装,经过这种包装,就能够像使用属性同样使用依赖项属性了,在后面会说一下怎么经过这种方式包装的。这就使用了旧技术来包装新技术的设计理念就不会干扰.NET。WPF中的依赖属性主要有如下三个优势:字体
一、依赖属性加入了属性变化通知、限制、验证等功能。这样可使咱们更方便地实现应用,同时大大减小了代码量。动画
二、节约内存:在WinForm中,每一个UI控件的属性都赋予了初始值,这样每一个相同的控件在内存中都会保存一份初始值。而WPF依赖属性很好地解决了这个问题,它内部实现使用哈希表存储机制,对多个相同控件的相同属性的值都只保存一份。spa
三、支持多种提供对象:能够经过多种方式来设置依赖属性的值。能够配合表达式、样式和绑定来对依赖属性设置值。设计
刚才咱们一直在说属性,先来看看属性是什么吧。先建立一个类Person,里面有name属性。3d
public string name{set;get;}对象
上面就是建立好的属性,看着是否是很简单。属性的建立就是这么简单,在咱们想要使用这个类的地方初始化就能用。
既然说WPF中绝大多数的属性都是依赖项属性,我看了一下依赖属性怎么进行建立。
一、依赖属性的所在类型继承自DependencyObject类。
二、使用public static 声明一个DependencyProperty的变量,该变量就是真正的依赖属性。
三、类型的静态构造函数中经过Register方法完成依赖属性的元数据注册。
四、提供依赖属性的包装属性,经过这个属性来完成对依赖属性的读写操做。
Public class Person : DependencyObject
//CLR属性包装器,使得依赖属性NameProperty在外部可以像普通属性那样使用
get { return (string)GetValue(NameProperty); }
set { SetValue(NameProperty, value); }
//DependencyProperty.Register 参数说明
//第四个参数是具备附加属性设置的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属性也不会发生改变,其值为默认值。
若是想要依赖属性继承,咱们能够进行自定义依赖属性继承属性值。
xmlns:sys="clr-namespace:System;assembly=mscorlib"
在写代码是都会考虑可能发生的错误。在定义属性时,也须要考虑错误设置属性的可能性。对于传统.NET属性,能够在属性的设置器中进行属性值的验证,不知足条件的值能够抛出异常。但对于依赖属性来讲,这种方法不合适,由于依赖属性经过SetValue方法来直接设置其值的。然而WPF有其代替的方式,WPF中提供了两种方法来用于验证依赖属性的值。
一、ValidateValueCallback:该回调函数能够接受或拒绝新值。该值可做为DependencyProperty.Register方法的一个参数。
二、CoerceValueCallback:该回调函数可将新值强制修改成可被接受的值。例如某个依赖属性工做年龄的值范围是25到55,在该回调函数中,能够对设置的值进行强制修改,对于不知足条件的值,强制修改成知足条件的值。如当设置为负值时,可强制修改成0。该回调函数PropertyMetadata构造函数参数进行传递。