依赖属性是wpf中一个新的概念,这种属性是当前的类没有自己的属性,但是可以通过Binding获取其他的对象的属性。当然在使用的过程中,依赖属性一般要被包装成CLR属性。
依赖属性在实际编码中是怎样应用的,不是这篇文章的讨论的内容,此篇主要讨论一下依赖属性是怎样实现的。
首先我们看示例代码:此代码是从http://www.silverlightchina.net/html/study/WPF/2011/0405/6659_3.html中截取出来的。大家可以看此文章,感觉讲的还算通俗易懂。
class MyDependencyProperty
{
internal static Dictionary<object, MyDependencyProperty>RegisteredDps = new Dictionary<object, MyDependencyProperty>();
internal string Name;
internal object Value;
/**当当前的依赖属性没有被赋值过,那么,GetValue就会缺省从HashCode为索引的哈希表中获取缺省值。
*/
internal object HashCode;
private static int globalIndex = 0;//所有的属性值的index将都会大于0
/**index是当前注册DependencyProperty中的序号- 实际上是检索当前依赖属性的检索号
*/
internal int Index;
private MyDependencyProperty(string name, Type propertyName, Type ownerType, object defaultValue)
{
this.Name = name;
this.Value = defaultValue;
this.HashCode = name.GetHashCode() ^ ownerType.GetHashCode();
}
public static MyDependencyProperty Register(string name, Type propertyType, Type ownerType, object defaultValue)
{
MyDependencyProperty dp = new MyDependencyProperty(name, propertyType, ownerType, defaultValue);
globalIndex++;
dp.Index = globalIndex;
RegisteredDps.Add(dp.HashCode, dp);
return dp;
}
}
internal struct EffectiveValueEntry
{
internal int PropertyIndex { get; set; }
internal object Value { get; set; }
}
class MyDependencyObject
{
//这个list用来存储设置的依赖属性值,包括这个类的所有的依赖属性,都会在设置后存储在这里
private List<EffectiveValueEntry> _effectiveValues = new List<EffectiveValueEntry>();
public object GetValue(MyDependencyProperty dp)
{
//在数据结构中查找对应的依赖属性是否在本地有值。
EffectiveValueEntry effectiveValue = _effectiveValues.FirstOrDefault((i) => i.PropertyIndex == dp.Index);
if (effectiveValue.PropertyIndex != 0)
{//如果获取的元素的PropertyIndex不等于0,说明本地存在这个属性的值
return effectiveValue.Value;
}
else
{//本地不存在就去Dictionary中区查找。
return MyDependencyProperty.RegisteredDps[dp.HashCode].Value;
}
}
public void SetValue(MyDependencyProperty dp, object value)
{
//在数据结构中查找对应的依赖属性是否在本地有值。
EffectiveValueEntry effectiveValue = _effectiveValues.FirstOrDefault((i) => i.PropertyIndex == dp.Index);
if (effectiveValue.PropertyIndex != 0)
{//如果获取的元素的PropertyIndex不等于0,说明本地存在这个属性的值
effectiveValue.Value = value;
}
else
{//本地不存在,但是我们进行了Setvalue的调用,所以需要在本地创建一个该属性的数据结构
effectiveValue = new EffectiveValueEntry() { PropertyIndex = dp.Index, Value = value };
_effectiveValues.Add(effectiveValue);
}
}
}
代码中有一些注释。此外,在附上一张自己对依赖属性理解的图。从图中可以看出,所有的依赖属性都注册到了DependencyProperty的静态变量Dictionary<object, DependecyProperty>中,其中object来存储注册DependecyProperty的哈希值。在依赖属性中,index是一个很重主要的值,此值是当前依赖属性注册到Dictionary中的序号。而含有依赖属性的对象都是继承依赖对象(DependencyObject)的,在依赖对象(DependencyObject)中,含有一个此类中所有依赖属性的列表,此列表包含着依赖属性的值。而依赖对象(DepedencyObject)的列表和依赖属性(DependencyProperty)唯一的联系点就是Index值。