在.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. WPF项目学习.三

    工具代码记录 版权声明:本文为博主初学经验,未经博主允许不得转载. 一.前言 记录在学习与制作WPF过程中遇到的解决方案. 分页控件的制作,邮件发送,日志代码,excel导入导出等代码的实现过程: 二 ...

  2. Sourcetree的安装与使用

    1 安装遇到的问题 https://segmentfault.com/q/1010000007643870 解决该问题的方法: http://www.jianshu.com/p/3478e2a214a ...

  3. 启动MySql提示:The server quit without updating PID file(…)失败

    1.可能是/usr/local/mysql/data/rekfan.pid文件没有写的权限解决方法 :给予权限,执行 "chown -R mysql:mysql /var/data" ...

  4. httpd的三种模式比较

    查看你的httpd使用了哪种模式: /usr/local/apache2/bin/httpd -V |grep 'Server MPM' 使用哪种模式,需要在编译的时候指定 --with-mpm=pr ...

  5. Android Native App自动化测试实战讲解(上)(基于python)

    1.Native App自动化测试及Appuim框架介绍 android平台提供了一个基于java语言的测试框架uiautomator,它一个测试的Java库,包含了创建UI测试的各种API和执行自动 ...

  6. EntityFramework Core 2.0自定义标量函数两种方式

    前言 上一节我们讲完原始查询如何防止SQL注入问题同时并提供了几种方式.本节我们继续来讲讲EF Core 2.0中的新特性自定义标量函数. 自定义标量函数两种方式 在EF Core 2.0中我们可以将 ...

  7. C语言链表的建立、插入和删除

    先看下向链表中插入节点 下面这个是删除链表节点

  8. Quartz基本使用

    1.Quartz概述:简单的说就是java的一个定时任务的框架,没有那么复杂的解释,跟前端的定时器一样.在了解它之前,首先熟悉几个概念. 2.基本概念 2.1 Job:表示一个工作,要执行的具体内容. ...

  9. (!(~+[])+{})[--[~+""][+[]]*[~+[]] + ~~!+[]]+({}+[])[[~!+[]]*~+[]]一行js代码的原理分析

    再说这行代码之前,咱们先来预习一下知识. 我们都知道计算机操作系统分为32位或者64位.那么这个32位或64位指的是什么意思呢?其实,要想解释它并不难,其实这就是计算机处理数据的机制,32位表示计算机 ...

  10. bash文件的详细解读

    一.bash的分类 1. 按生效范围分类 全局生效 /etc/profile /etc/profile.d/*.sh /etc/bashrc 个人用户生效 ~/.bash_profile ~/.bas ...