依赖属性就是一种可以自己没有值,并能通过使用Binding从数据源获得值(依赖在别人身上)的属性。拥有依赖属性的对象称为“依赖对象”。

WPF开发中,必须使用依赖对象作为依赖属性的宿主,使二者结合起来。依赖对象的概念被DependencyObject类所实现,依赖属性的概念则由DependencyProperty类所实现

从这棵继承树上可以看出,WPF的所有UI空间都是依赖对象。

看最简单的依赖属性

class Student : DependencyObject
{ public string Name
{
get { return (string)GetValue(NameProperty); } //依赖属性和附加属性定义的不同
set { SetValue(NameProperty, value); }
} public static readonly DependencyProperty NameProperty =
DependencyProperty.Register("Name", typeof(string), typeof(Student));
}

实例并非使用new操作符得到而是使用DependencyProperty.Register方法生成。

现在我们使用的Register方法是参数最少,最简单的一个重载,我们来分析一下

  • 第一个参数为string类型,表示指明以哪个CLR属性作为这个依赖属性的包装器。就是代码
public string Name
{
get { return (string)GetValue(NameProperty); }
set { SetValue(NameProperty, value); }
}
  • 第二个参数指明此依赖属性用来存储什么样的值。
  • 第三个参数用来指明此依赖属性的宿主是什么类型,或者说DependencyProperty.Register方法要将这个依赖属性注册到哪个类型上。

注意:1.依赖属性包装器是一个CLR属性,并不是依赖属性,没有包装器,依赖属性依旧存在。

2.既然没有包装器依赖属性也存在,那么包装器是干什么用的呢?包装器的作用是以“实例属性”的形式向外界暴露依赖属性,这样,一个依赖属性才能成为数据源的一个Path。

3.注册依赖属性时使用的第二个参数是一个数据类型,这个数据类型也是包装器的数据类型。

请看例子

<Window x:Class="DependencyPropertySample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<TextBox x:Name="textbox1" BorderBrush="Black" Margin="5"/>
<TextBox x:Name="textbox2" BorderBrush="Black" Margin="5"/>
<Button Content="OK" Margin="5" Click="Button_Click"/>
</StackPanel>
</Window>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
} private void Button_Click(object sender, RoutedEventArgs e)
{
Student stu = new Student();
stu.SetValue(Student.NameProperty, textbox1.Text);
textbox2.Text = (string)stu.GetValue(Student.NameProperty); //依赖属性代码用法
}
}

当第一次看到这个例子的时候,也许会有点百思不得其解的感觉——依赖属性不是一个Static对象么?哪怕有1000个Student实例,依赖属性只有一个啊,那么SetValue把值存储到哪里去了?GetValue又从哪里读取值?并且,依赖属性不是一个只读的吗?怎么可以写入值呢?其实这个问题直指依赖属性机制的核心,我们过一会再讨论。

还要注意一点,尽管student类没有实现INotifyPropertyChange接口,当属性的值发生改变时与之关联的Binding对象依然可以得到通知,依赖属性默认带有这样的功能,天生就是合格的数据源。

使用vs2010有一个小技巧,生成依赖属性可以使用代码段propdp,DependencyProperty.Register带4个参数,第四个参数的类型是PropertyMetadata类,作用是给依赖属性的DefaultMetadata属性赋值。顾名思义,DefaultMetadata的作用就是向依赖属性的调用者提供一些基本信息,这些信息包括:

  • CoerceValueCallback:依赖属性的值被强制改变时此委托会被调用,此委托可关联一个函数。
  • DefaultValue:依赖属性未被显示赋值时,若读取之则获得此默认值,不设置此值会抛出异常。
  • IsSealed:控制PropertyMetadata的属性值是否可以更改,默认值为true。
  • PropertyChangeCallback:依赖属性的值被改变之后此委托会被调用,此委托可关联一个函数。

注意:依赖属性的DefaultMetadata只能通过Register方法的第四个参数惊醒赋值,而且一旦赋值就不能改变。如果想用新的PropertyMetadata替换这个默认的Metadata,需要使用DependencyProperty.OverrideMetadata方法。

下面我们来解决刚才的红色问题。

首先值存到什么地方去了?

创建一个DependencyProperty实例并用它的CLR属性名和宿主类型名生成hash code,最后把hash code和DependencyProperty实例作为Key-Value对存入全局的,名为PropertyFormName的Hashtable中。

。。。(我认为书上写的太深奥啦,想要深究的同学可以参考《深入浅出WPF》)

初学者不必深究,那就是使用了static和readonly是为了保证DependencyProperty的索引值唯一。真正的值是存在一个Hashtable中的,当然可读可写啦。

Dependency Property 依赖属性的更多相关文章

  1. WPF学习笔记——依赖属性(Dependency Property)

    1.什么是依赖属性 依赖属性是一种可以自己没有值,并且通过Binding从数据源获得值(依赖在别人身上)的属性,拥有依赖属性的对象被称为"依赖对象". 依赖项属性通过调用 Regi ...

  2. WPF整理-为User Control添加依赖属性

    依赖属性 ".NET properties are nothing more than syntactic sugar over set and get methods." 我们知 ...

  3. WPF入门教程系列十二——依赖属性(二)

    二. 依赖属性的优先级 由于WPF 允许我们可以在多个地方设置依赖属性的值,所以我们就必须要用一个标准来保证值的优先级别.比如下面的例子中,我们在三个地方设置了按钮的背景颜色,那么哪一个设置才会是最终 ...

  4. WPF依赖属性详解

    WPF依赖属性详解 WPF 依赖属性 英文译为 Dependency Properties,是WPF引入的一种新类型的属性,在WPF中有着极为广泛的应用,在WPF中对于WPF Dependency P ...

  5. WPF快速入门系列(2)——深入解析依赖属性

    一.引言 感觉最近都颓废了,好久没有学习写博文了,出于负罪感,今天强烈逼迫自己开始更新WPF系列.尽管最近看到一篇WPF技术是否老矣的文章,但是还是不能阻止我系统学习WPF.今天继续分享WPF中一个最 ...

  6. WPF基础到企业应用系列7——深入剖析依赖属性(WPF/Silverlight核心)

    一. 摘要 首先圣殿骑士非常高兴这个系列能得到大家的关注和支持.这个系列从七月份開始到如今才第七篇,上一篇公布是在8月2日,掐指一算有二十多天没有继续更新了,最主要原因一来是想把它写好,二来是由于近期 ...

  7. silverlight依赖属性

    依赖属性(Dependency Property)和附加属性(Attached Property) 参考 http://www.cnblogs.com/KevinYang/archive/2010/0 ...

  8. 重新想象 Windows 8 Store Apps (16) - 控件基础: 依赖属性, 附加属性, 控件的继承关系, 路由事件和命中测试

    原文:重新想象 Windows 8 Store Apps (16) - 控件基础: 依赖属性, 附加属性, 控件的继承关系, 路由事件和命中测试 [源码下载] 重新想象 Windows 8 Store ...

  9. [UWP]依赖属性2:使用依赖属性

    5. 完整的自定义依赖属性 5.1 定义 /// <summary> /// 标识 Title 依赖属性. /// </summary> public static reado ...

随机推荐

  1. pip运行报错Fatal error in launcher: Unable to create process using pip.exe

    使用pip的时候报错Fatal error in launcher: Unable to create process using pip.exe 解决办法,升级pip python -m pip i ...

  2. HTTP缓存策略 304

    1.图解缓存 示例: 200 (from disk cache): 200 (from memory cache) MemoryCache顾名思义,就是将资源缓存到内存中,等待下次访问时不需要重新下载 ...

  3. Mybatis <where>标签

    <select id="findActiveBlogLike" resultType="Blog"> SELECT * FROM BLOG WHER ...

  4. 阿里云web播放器

    原文地址:https://help.aliyun.com/document_detail/51991.html?spm=5176.doc61109.6.703.ZTCYoi 一.概念说明 1. pla ...

  5. crc32 根据字符串获取校验值

    using System;using System.Collections.Generic;using System.IO;using System.Linq;using System.Text; n ...

  6. .NET面试题(二)

    基础方面: 1.简单的描述一下C# 中重写,重载,隐藏的概念 C#中重写(overide)是子类继承父类后,对父类中的方法进行行为改写. 重载是指方法名相同,参数不同 重写和隐藏的定义: 重写:基类方 ...

  7. 将ViewState放在Session里(转载)

    using System; using System.Collections.Generic; using System.Linq; using System.Web;   namespace Ent ...

  8. 点滴积累【JS】---JS小功能(JS实现隐藏显示侧边栏,也就是分享栏的隐藏显示)

    效果: 思路: 首先,利用计时器setInterval实现DIV的隐藏显示功能,然后在进行一个判断,之后在把要移动的相应距离进行一个参数传递,再根据参数判断出移动的方向也就是offsetLeft移动的 ...

  9. [k8s]监控

    监控架构 参考 https://github.com/DataDog/the-monitor/blob/master/kubernetes/how-to-collect-and-graph-kuber ...

  10. [docker]搭建私有registry

    导入导出镜像比较麻烦,共享镜像占了工作中一大部分时间. 搭建了个本地registry, 不支持用户名密码验证的 和 支持用户名密码验证的两种. 参考: https://docs.docker.com/ ...