依赖属性(Dependency Property)

依赖属性的使用大致分为两步:

第一步:在DependencyObject派生类中声明public static修饰的Dependency Property成员变量,并使用DependencyProperty.Register方法获得DependencyProperty实例;

第二步:使用DependencyObject的SetValue和GetValue方法、借助Dependency实例来存取值

DependencyProperty类具有这样一个成员:

private statci Hashtable PropertyFromName = new Hashtable();

显然,一旦程序运行,就会有这样一个全局的Hashtable存在,这个Hashtable就是用来注册DependencyProperty实例的地方。

在源码中,所有的DependencyProperty.Register方法重载最后都归结为对DependencyProperty.RegisterCommon方法的调用

RegisterCommon方法的原型如下:

private static DependencyProperty RegisterCommon
(
    string name,
    Type propertyType,
    Type ownerType,
    PropertyMetadata defaultMetadata,
    ValidateValueCallback validateValueCallback
 )

 下面让我们研究一下RegisterCommon方法如何操作他的参数:

进入RegisterCommon方法的时候你会看到这样一句话:

  FromNameKey key = new FromNameKey(name,ownerType);
//FromNameKey是一个.Net Fromework内部数据类型

 FromNameKey对象(变量key)的hash code,实际上是RegisterCommon第一个参数(CLR属性名字符串) 的hash code 与第3个参数(宿主类型)的hash code 做异或得来的

这样操作,每对“CLR属性名--宿主类型” 所决定的DependencyProperty实例是唯一的。所以,在RegisterCommon方法里会发现这样的代码:

if(PropertyFromName.Contains(key))
{
    throw new ArgumentException(SR.Get(SRID.PropertyAlreadyRegistered,name,ownerType.Name));
}

也就是说,如果你尝试使用同一个CLR属性名字和同一个宿主类型进行注册,程序会抛出异常。

接下来RegisterCommon检查程序员是否提供了PropertyMetadate,如果没有提供则为之准备一个默认的PropertyMetadate实例。当所有“原料”都准备妥当、没有问题后,DependencyProperty的实例被创建出来:

Dependency dp = new DependencyProperty(name,propertyType,ownerType,defaultMetadata,validateValueCallback);

并且被注册进Hashtable中(Hashtable会自动调用key的GetHashcode方法获取其hash code):

PropertyFromName[key] = dp;

用一句话概括DependencyProperty对象的创建与注册,那就是:创建一个DependencyProperty实例并用它的CLR属性名和宿主类型名生成hash code,最后把hash code 和DependencyProperty实例作为Key-Value存入全局的、名为PropertyFromName的Hashtable中,这样,WPF属性系统通过CLR属性名和宿主类型名就可以从这个全局的Hashtable中检索出对应的DependencyProperty实例。

最后,生成的DependencyProperty实例被当作返回值交还:

return dp;

 一个DependencyProperty实例已经被创建并注册进一个全局的Hashtable中,下面就要使用DepdendencyObject的SetValue和GetValue借助这个DependencyProperty实例保存和读取值了。

public object GetValue(DependencyProperty dp)
{
        this.VerifyAccess();
        if (dp == null)
        {
            throw new ArgumentException("dp");
        }
        return GetValueEntry(LookupEnter(dp.GlobalIndex), dp, null, RequestFlags.FullyResolved).value;
}

 方法的起若干行均是为了校验传入参数的有效性,只有一句才是核心内容。这句话的函数嵌套比较深,展开

EntryIndex entryIndex = LookupEntry(dp.GlobalIndex);
EffectiveValueEntry valueEntry = GetValueEntry(entryIndex,dp,null,RequestFlags.FullyRsolved)
return valueEntry.Value;

 

你可能感兴趣的:(开发语言,c#,笔记,wpf,学习)