WPF中的依赖项属性的AddOwner与OverrideMetadata有何区别?什么情况下使用AddOwner?什么情况下使用OverrideMetadata呢?
依赖项属性是WPF框架中非常核心的属性,相比传统属性提供了丰富的功能。如:内置绑定支持,渲染行为支持,动画支持等等。
1、 DependencyProperty.AddOwner
顾名思义,AddOwner
,就是给当前的依赖项属性添加“所有者”或者“拥有者”。也就是说,它的主要作用是给新的类型,定义相同的依赖项属性,从而省去了我们自己通过DependencyProperty.Registry
方式进行注册。实际上两者的效果是差不多的,都是给指定的类型定义一个依赖项属性。
AddOwner
接受的参数是 Type
,通过AddOwner方法,只需要传入我们注册依赖项属性的类型就可以了。
举例:
假设我们要给TestClass
定义一个Background
依赖项属性。而TestClass
也是继承自FrameworkElement
,同时假设他的Background
属性的作用和Border
的Background
属性是相同的。
那么这个时候,我们完全没有必要重新去注册一个依赖项属性,直接用Border.BackgroundProperty.AddOwner(typeof(TestClass))
即可。
所以我们在使用AddOwner
方法时,是我们想要注册的属性,在现有的依赖项属性中已经存在注册了,并且两者的行为功能一致的情况下即可使用。
2、 DependencyProperty.OverrideMetadata
同样的,OverrideMetadata
从字面上看,是重写元数据。它主要是用于现有的依赖项属性的元数据进行修改。
实际上,OverrideMetadata
内部的实现是一个委托链,当我们在重写它的时候,它只是在委托链上增加了一个委托方法。当我们方法在执行的时候,我们最终的实现方法,会覆盖部分已定义的功能实现。
所以,OverrideMetadata
主要使用场景在于,我们要修改依赖项属性的一些默认行为。
我们在使用OverrideMetadata
方法的过程中,需要注意,元数据需要跟积累的元数据类型相同。
如基类元数据类型是FrameworkPropertyMetadata
,那我们重写的时候也必须是这个类型。默认情况下是PropertyMetadata
。这种情况下会导致错误,需要注意一下。
3、 两者区别
AddOwner
是OverrideMetadata
和添加PropertyFromName
哈希表的合集,OverrideMetadata
是把当前元数据和继承体系中最近的父类的依赖属性的元数据PropertyChangedCallback
进行合并,CoerceCallback
进行取舍。AddOwner
调用的过程中会调用OverrideMetadata
方法。
部分参考代码:
//AddOwner部分代码
public DependencyProperty AddOwner(Type ownerType, PropertyMetadata typeMetadata)
{
if (ownerType == null)
{
throw new ArgumentNullException("ownerType");
}
FromNameKey key = new FromNameKey(this.Name, ownerType);
lock (Synchronized)
{
if (PropertyFromName.Contains(key))
{
throw new ArgumentException(MS.Internal.WindowsBase.SR.Get("PropertyAlreadyRegistered", new object[] { this.Name, ownerType.Name }));
}
}
if (typeMetadata != null)
{
this.OverrideMetadata(ownerType, typeMetadata);
}
lock (Synchronized)
{
PropertyFromName.set_Item(key, this);
}
return this;
}
public void OverrideMetadata(Type forType, PropertyMetadata typeMetadata)
{
//省略
//部分代码
DependencyObjectType dType = DependencyObjectType.FromSystemType(forType);
PropertyMetadata baseMetadata = this.GetMetadata(dType.BaseType);
//合并PropertyMetaChanged的事件
if (baseMetadata.PropertyChangedCallback != null)
{
Delegate[] invocationList = baseMetadata.PropertyChangedCallback.GetInvocationList();
if (invocationList.Length > 0)
{
System.Windows.PropertyChangedCallback a = (System.Windows.PropertyChangedCallback) invocationList[0];
for (int i = 1; i < invocationList.Length; i++)
{
a = (System.Windows.PropertyChangedCallback) Delegate.Combine(a, (System.Windows.PropertyChangedCallback) invocationList[i]);
}
a = (System.Windows.PropertyChangedCallback) Delegate.Combine(a, this._propertyChangedCallback);
this._propertyChangedCallback = a;
}
}
if (this._coerceValueCallback == null)
{
//委托直接覆盖
this._coerceValueCallback = baseMetadata.CoerceValueCallback;
}
if (this._freezeValueCallback == null)
{
this._freezeValueCallback = baseMetadata.FreezeValueCallback;
}
//省略
}
总的来讲,如果是需要给依赖项属性添加新的数据类型,就可以直接用AddOwner
;如果是想要更改默认的行为,那么可以用OverrideMetadata
;如果要定义的依赖项属性框架没有提供,那么就重新注册一个即可。
本文会经常更新,请阅读原文: https://huchengv5.gitee.io//post/WPF-%E4%BE%9D%E8%B5%96%E9%A1%B9%E5%B1%9E%E6%80%A7%E7%9A%84AddOwner%E4%B8%8EOverrideMetadata%E5%8C%BA%E5%88%AB.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名胡承(包含链接: https://huchengv5.gitee.io/ ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 。