在.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. markdown语法探究

    \[\sum_{i=1}^n a_i=0\] \[f(x_1,x_x,\ldots,x_n) = x_1^2 + x_2^2 + \cdots + x_n^2 \] \[\sum^{j-1}_{k=0 ...

  2. Sublime编辑器的使用

    Sublime编辑器的使用 我的本地使用环境是Win7下安装的Sublime3编辑器(提取码:nzuw). 1. 新建index.html,在代码编辑区输入<html,然后按下Tab键,可以快速 ...

  3. C++11 标准库也有坑(time-chrono)

    恰巧今天调试程序遇到时间戳问题, 于是又搜了搜关于取时间戳,以及时间戳转字符串的问题, 因为 time()   只能取到秒(win和linux) 想试试看能不能找到 至少可以取到毫秒的, 于是, 就找 ...

  4. 【netty这点事儿】ByteBuf 的使用模式

    堆缓冲区 最常用的 ByteBuf 模式是将数据存储在 JVM 的堆空间中. 这种模式被称为支撑数组(backing array), 它能在没有使用池化的情况下提供快速的分配和释放. 直接缓冲区 直接 ...

  5. mysql存储引擎、事务

    MySQL存储引擎介绍 文件系统 操作系统组织和存取数据的一种机制. 文件系统是一种软件. 文件系统类型 ext2  ext3  ext4  xfs 数据 不管使用什么文件系统,数据内容不会变化 不同 ...

  6. ch7复用类

    导出类的初始化是从基类开始向下扩展的,先初始化基类,再初始化由基类继承而来的类. 若类B需要类A中的一些甚至全部方法,但类B实际上不是并不是真正的类A,则可以通过代理的方式在B中实现所需要的A的方法, ...

  7. CentOS7上安装Nginx、PHP、MySQL

    一.安装准备 首先由于nginx的一些模块依赖一些lib库,所以在安装nginx之前,必须先安装这些lib库,这些依赖库主要有g++.gcc.openssl-devel.pcre-devel和zlib ...

  8. 基于epoll实现简单的web服务器

    1. 简介 epoll 是 Linux 平台下特有的一种 I/O 复用模型实现,于 2002 年在 Linux kernel 2.5.44 中被引入.在 epoll 之前,Unix/Linux 平台下 ...

  9. SQLite常用函数及语句

    SQLite3.0使用的是C的函数接口,常用函数如下: sqlite3_open() //打开数据库 sqlite3_close() //关闭数据库 sqlite3_exec() //执行sql语句, ...

  10. SpringBoot Hello World

    本文首发于我的github博客 前言 SpringBoot是Spring MVC升级版,基于『约定优于配置』的原则,快速开发出web程序. 环境 本系列笔记环境如下: Sun JDK1.8.0_20 ...