WPF中的依赖项属性的AddOwner与OverrideMetadata有何区别?什么情况下使用AddOwner?什么情况下使用OverrideMetadata呢?

依赖项属性是WPF框架中非常核心的属性,相比传统属性提供了丰富的功能。如:内置绑定支持,渲染行为支持,动画支持等等。

1、 DependencyProperty.AddOwner

顾名思义,AddOwner,就是给当前的依赖项属性添加“所有者”或者“拥有者”。也就是说,它的主要作用是给新的类型,定义相同的依赖项属性,从而省去了我们自己通过DependencyProperty.Registry方式进行注册。实际上两者的效果是差不多的,都是给指定的类型定义一个依赖项属性。

AddOwner 接受的参数是 Type ,通过AddOwner方法,只需要传入我们注册依赖项属性的类型就可以了。

举例:

假设我们要给TestClass定义一个Background依赖项属性。而TestClass也是继承自FrameworkElement,同时假设他的Background属性的作用和BorderBackground属性是相同的。

那么这个时候,我们完全没有必要重新去注册一个依赖项属性,直接用Border.BackgroundProperty.AddOwner(typeof(TestClass))即可。

所以我们在使用AddOwner方法时,是我们想要注册的属性,在现有的依赖项属性中已经存在注册了,并且两者的行为功能一致的情况下即可使用。

2、 DependencyProperty.OverrideMetadata

同样的,OverrideMetadata从字面上看,是重写元数据。它主要是用于现有的依赖项属性的元数据进行修改。

实际上,OverrideMetadata内部的实现是一个委托链,当我们在重写它的时候,它只是在委托链上增加了一个委托方法。当我们方法在执行的时候,我们最终的实现方法,会覆盖部分已定义的功能实现。

所以,OverrideMetadata主要使用场景在于,我们要修改依赖项属性的一些默认行为。

我们在使用OverrideMetadata方法的过程中,需要注意,元数据需要跟积累的元数据类型相同。

如基类元数据类型是FrameworkPropertyMetadata,那我们重写的时候也必须是这个类型。默认情况下是PropertyMetadata。这种情况下会导致错误,需要注意一下。

3、 两者区别

AddOwnerOverrideMetadata和添加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/ ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系