写在以前:html
依赖属性算是WPF醉醉基础的一个组成了。平时写代码的时候,简单的绑定很轻松,可是遇到复杂的层次比较多的绑定,真的是要命。因此,我以为深入认识依赖属性是颇有必要的。本篇只是我的学习的记录,学习的博客是周永恒先生的《一站式WPF--依赖属性(DependencyProperty)》,这算是一个系列了,说的很详细。若是须要更好的学习,建议移步上述原文,受益不浅。学习
什么是依赖属性?优化
Windows Presentation Foundation (WPF) 提供了一组服务,这些服务可用于扩展公共语言运行时 (CLR) 属性的功能,这些服务一般统称为 WPF 属性系统。由 WPF 属性系统支持的属性称为依赖项属性。----MSDNthis
也就是说,WPF提供一组叫作‘WPF属性系统’的服务,而依赖属性就是被这个服务所支持的属性。我只能说,每一个字都认识,可是放在一块儿认识的就不那么清晰了……spa
首先,想要了解它,必须知道它是为了什么而来。3d
虽然不清楚依赖属性,可是属性咱们是很清楚的,封装类的字段,表示类的状态,编译后被转化为get_,set_方法,能够被类或结构等使用,常见的一个属性以下:code
public class ClassObject { private string name; public string Name { get { return name; } set { name = value; } } }
既然已经有了属性,为何还要有依赖属性呢?必然是属性有一些缺点了,而依赖属性刚好可以解决这个问题。以Button为例:htm
每次继承,父类的私有字段都被继承下来。对Button来讲,大多数属性并无被修改,仍然保持父类定义时的默认值。一般状况下,在整个Button的对象生命周期中,也只有少部分属性被修改。也已看得出来:对象
能够知道,依赖属性就是为了解决这个问题诞生了。首先定义依赖属性,它里面存储以前2中但愿剥离的属性:blog
public class DependencyProperty { // 维护了一个全局的Map用来储存全部的DP internal static Dictionary<object, DependencyProperty> RegisteredDps = new Dictionary<object, DependencyProperty>(); internal string Name;//注册属性名称 internal object Value;//属性值 internal object HashCode;//Mape惟一键值 private DependencyProperty(string name, Type propertyName, Type ownerType, object defaultValue) { this.Name = name; this.Value = defaultValue; this.HashCode = name.GetHashCode() ^ ownerType.GetHashCode(); } // 对外暴露一个Register方法用来注册新的DP public static DependencyProperty Register(string name, Type propertyName, Type ownerType, object defaultValue) { DependencyProperty dp = new DependencyProperty(name, propertyName, ownerType, defaultValue); RegisteredDps.Add(dp.HashCode, dp); return dp; } }
而后定义DependencyObject来使用DP:
public class DependencyObject { // 注册一个新的DP:NameProperty public static readonly DependencyProperty NameProperty = DependencyProperty.Register("Name", typeof(string), typeof(DependencyObject), string.Empty); public object GetValue(DependencyProperty dp) { return DependencyProperty.RegisteredDps[dp.HashCode].Value; } public void SetValue(DependencyProperty dp, object value) { DependencyProperty.RegisteredDps[dp.HashCode].Value = value; } public string Name { get { return (string)GetValue(NameProperty); } set { SetValue(NameProperty, value); } } }
DependencyObject和文章开篇的ClassObject中的Name有什么不一样呢?
>>DependencyObject.Name的实际值不是用字段保存在DependencyObject中,而是保存在NameProperty中,经过SetValue和GetValue来金星赋值取值操做。
在上述例子中,全部DependncuObject的对象将共用一个NameProperty,这在现实中是不实际的:只要修改一个对象的属性,至关于全部对象的属性值都被修改了。因此,修改的属性,仍是要维护在相应的对象中的:(修改部分用☆表示)
public class DependencyProperty { private static int globalIndex = 0;// ☆ // 维护了一个全局的Map用来储存全部的DP internal static Dictionary<object, DependencyProperty> RegisteredDps = new Dictionary<object, DependencyProperty>(); internal string Name;//注册属性名称 internal object Value;//属性值 internal int Index;// ☆
internal object HashCode;//Mape惟一键值 private DependencyProperty(string name, Type propertyName, Type ownerType, object defaultValue) { this.Name = name; this.Value = defaultValue; this.HashCode = name.GetHashCode() ^ ownerType.GetHashCode(); } // 对外暴露一个Register方法用来注册新的DP public static DependencyProperty Register(string name, Type propertyName, Type ownerType, object defaultValue) { DependencyProperty dp = new DependencyProperty(name, propertyName, ownerType, defaultValue); globalIndex++;// ☆ dp.Index = globalIndex; // ☆ RegisteredDps.Add(dp.HashCode, dp); return dp; } }
全部修改过的DP都保存在EffectiveValueEntry里,这样,就能够只保存修改的属性,未修改过的属性仍然读取DP的默认值,优化了属性的储存。
public class DependencyObject { // 引入有效的概念// ☆ private List<EffectiveValueEntry> _effectiveValues = new List<EffectiveValueEntry>(); // 注册一个新的DP:NameProperty public static readonly DependencyProperty NameProperty = DependencyProperty.Register("Name", typeof(string), typeof(DependencyObject), string.Empty); public object GetValue(DependencyProperty dp) { // ☆ EffectiveValueEntry effectiveValue = _effectiveValues.FirstOrDefault(i => i.PropertyIndex == dp.Index); if (effectiveValue.PropertyIndex != 0) { return effectiveValue.Value; } else { return DependencyProperty.RegisteredDps[dp.HashCode].Value;//仅此部分相同 } } public void SetValue(DependencyProperty dp, object value) { // 所有 ☆ EffectiveValueEntry effectiveValue = _effectiveValues.FirstOrDefault(i => i.PropertyIndex == dp.Index); if (effectiveValue.PropertyIndex != 0) { effectiveValue.Value = value; } else { effectiveValue = new EffectiveValueEntry() { PropertyIndex = dp.Index, Value = value }; } //DependencyProperty.RegisteredDps[dp.HashCode].Value = value; } public string Name { get { return (string)GetValue(NameProperty); } set { SetValue(NameProperty, value); } } }
internal struct EffectiveValueEntry { internal int PropertyIndex{get;set;} internal object Value{get;set;} }