在.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依赖属性的更多相关文章

  1. WPF自学入门(六)WPF带标题的内容控件简单介绍

    在WPF自学入门(二)WPF-XAML布局控件的文章中分别介绍StackPanel,WarpPanel,DockPanel,Grid,Canvas五种布局容器的使用,可以让我们大致了解容器可以使用在什 ...

  2. WPF自学入门(十一)WPF MVVM模式Command命令

    在WPF自学入门(十)WPF MVVM简单介绍中的示例似乎运行起来没有什么问题,也可以进行更新.但是这并不是我们使用MVVM的正确方式.正如上一篇文章中在开始说的,MVVM的目的是为了最大限度地降低了 ...

  3. WPF自学入门(十二)WPF MVVM模式提取函数

    我们平时在写代码时为了不重复写代码,会进行复制代码或者写通用方法.今天我们就来把上传做的函数提取成为通用的方法调用.把上次写的函数提取为两个主要的文件:ObserableObject和RelayCom ...

  4. WPF自学入门(十一)WPF MVVM模式Command命令 WPF自学入门(十)WPF MVVM简单介绍

    WPF自学入门(十一)WPF MVVM模式Command命令   在WPF自学入门(十)WPF MVVM简单介绍中的示例似乎运行起来没有什么问题,也可以进行更新.但是这并不是我们使用MVVM的正确方式 ...

  5. WPF自学入门(三)WPF路由事件之内置路由事件

    有没有想过在.NET中已经有了事件机制,为什么在WPF中不直接使用.NET事件要加入路由事件来取代事件呢?最直观的原因就是典型的WPF应用程序使用很多元素关联和组合起来,是否还记得在WPF自学入门(一 ...

  6. WPF系列 —— 控件添加依赖属性(转)

    WPF系列 —— 控件添加依赖属性 依赖属性的概念,用途 ,如何新建与使用.本文用做一个自定义TimePicker控件来演示WPF的依赖属性的简单应用. 先上TimePicker的一个效果图. 概念 ...

  7. WPF学习(5)依赖属性

    今天我们来学习WPF一个比较重要的概念:依赖属性.这里推荐大家看看周永恒大哥的文章,讲的确实很不错.我理解的没那么深入,只能发表一下自己的浅见.提到依赖属性,不得不说我们经常使用的传统的.net属性, ...

  8. WPF自学入门(一)WPF-XAML基本知识

    一.基本概念 1.XAML是派生自XML的可扩展应用程序标记语言(Extensible Application Markup Language)由微软创造应用在WPF,Silverlight等开发技术 ...

  9. WPF自学入门(四)WPF路由事件之自定义路由事件

    在上一遍博文中写到了内置路由事件,其实除了内置的路由事件,我们也可以进行自定义路由事件.接下来我们一起来看一下WPF中的自定义路由事件怎么进行创建吧. 创建自定义路由事件分为3个步骤: 1.声明并注册 ...

随机推荐

  1. linux打印彩色字

    echo显示带颜色,需要使用参数-e格式如下:echo -e "\033[字背景颜色;文字颜色m字符串\033[0m"例如: echo -e "\033[41;37m T ...

  2. OpenVPN的那些坑

    遇到的情形 最近遇到一种情况,当需要同时使用到多个VPN连接时,默认的openVPN连接是不支持的,但是可以通过手动配置虚拟网络适配器进行相关的设置. 具体解决方法 基本思路是:在本地的网络连接中添加 ...

  3. ASP.NET Core 2.0 : 五.服务是如何加载并运行的, Kestrel、配置与环境

    "跨平台"后的ASP.Net Core是如何接收并处理请求的呢? 它的运行和处理机制和之前有什么不同? 本章从"宏观"到"微观"地看一下它的 ...

  4. 表的操作(Oracle和DB2)

    asc和desc 分别表示升序和降序 select * from tablename order by id desc :根据id字段按照降序排列,从大到小 select * from tablena ...

  5. dubbo filter实现接口认证springboot idea

    最近公司有业务需求,要对Dubbo接口调用者进行身份验证,验证通过才能调用,网上一些资料不够全面,遂整理了一下. 在provider方定义一个filter,需要实现com.alibaba.dubbo. ...

  6. 《android开发艺术探索》读书笔记(七)--动画

    接上篇<android开发艺术探索>读书笔记(六)--Drawable No1: 自定义动画:派生一种新动画只需要继承Animation这个抽象类,然后重写它的initialize和app ...

  7. 算法提高 拿糖果 线性DP

    题目链接:拿糖果 思路:首先给小于根号n的素数打表.d(i)表示当前剩余i颗糖,最多可以拿到多少糖.     转移方程:d(i) = max(d(i), k + d(i - 2 * k)),此处k表示 ...

  8. typeahead + JDK 8 并行流 + redis 高速即时查询.

    感谢JDK8,让我们JAVA 程序员暂时不用担心失业. 有些情况,需要根据用户输入值,即时查询数据库,MYSQL显然不再适合这种业务. mongoDB看似最适合,但是为了这么一个破功能,也不值得特意去 ...

  9. linux中的三个文件时间

    Linux系统文件有三个主要的时间属性,分别是ctime(change time), atime(access time), mtime(modify time). 后来为了解决atime的性能问题, ...

  10. RISC_CPU

    采用Top-Down设计方法,深入理解CPU的运作原理,本文参照夏宇闻老师的<Verilog 数字系统设计教程>,并做了相应的修改.仿真工具采用Mentor公司的ModelSim. 1.C ...