依赖属性(Dependency Property)

文章详细解释了WPF中DependencyProperty的使用过程,包括声明、注册步骤,以及依赖属性实例与CLR属性名和宿主类型的关联机制。着重介绍了RegisterCommon方法的工作原理和属性值的获取与设置方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

第一步:在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;

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值