2

WPF UncommonField 类型是什么

 3 years ago
source link: https://lindexi.gitee.io/post/WPF-UncommonField-%E7%B1%BB%E5%9E%8B%E6%98%AF%E4%BB%80%E4%B9%88.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
WPF UncommonField 类型是什么

本文告诉大家一个黑科技,这个黑科技在 .NET 框架外无法使用,这就是 UncommonField 类。下面将会告诉大家这个类有什么用。

如果大家有反编译 UIElement 那么就会看到下面的代码

internal static readonly UncommonField<EventHandlersStore> EventHandlersStoreField = new UncommonField<EventHandlersStore>();

那么这个UncommonField是什么?这个类是解决DependencyObject 使用很多内存。使用这个类可以作为轻量的DependencyObject 因为他使用很少的内存。

因为使用了DependencyObject 就会创建很多默认的值,无论使用的是TextBox.Text的依赖属性还是Grid.Row附加的,都会有很多不需要使用的值。但是在框架,需要使用很少的内存,所以就使用UncommonField

如果使用UncommonField就会去掉很多元数据、校验、通知,UncommonField会使用和DependencyObject 相同的机制,让他可以存放在DependencyObject 中和其他存放的属性一样,在没有改变值的时候会使用上一级、默认的值。所以可以减少一些内存。

因为现在很少人会写出和框架一样的那么多使用依赖属性,所以就不需要使用这个功能。

下面就是UncommonField代码,我添加一些注释

     //这个类可以减少内存使用,比使用 DependencyObject 少的内存,这个类在框架使用,不在外面使用
  [FriendAccessAllowed] // Built into Base, used by Core and Framework
    internal class UncommonField<T>
    {
        /// <summary>
        ///     Create a new UncommonField.
        /// </summary>
        public UncommonField() : this(default(T))
        {
        }
 
        /// <summary>
        ///     Create a new UncommonField.
        /// </summary>
        /// <param name="defaultValue">The default value of the field.</param>
        public UncommonField(T defaultValue)
        {
            _defaultValue = defaultValue;
            _hasBeenSet = false;
 
            lock (DependencyProperty.Synchronized)
            {
            	//注册方法和依赖属性相同
                _globalIndex = DependencyProperty.GetUniqueGlobalIndex(null, null);
 
                DependencyProperty.RegisteredPropertyList.Add();
            }
        }
 
        /// <summary>
        ///     从下面代码可以看到,设置值代码和依赖属性相同
        ///     Write the given value onto a DependencyObject instance.
        /// </summary>
        /// <param name="instance">The DependencyObject on which to set the value.</param>
        /// <param name="value">The value to set.</param>
        public void SetValue(DependencyObject instance, T value)
        {
        	//如果传入的值是空,会有异常
            if (instance != null)
            {
                EntryIndex entryIndex = instance.LookupEntry(_globalIndex);
 
                //设置的值如果和默认的相同,那么就直接跳过
                // Set the value if it's not the default, otherwise remove the value.
                if (!object.ReferenceEquals(value, _defaultValue))
                {
                	//下面的代码进行设置值
                    instance.SetEffectiveValue(entryIndex, null /* dp */, _globalIndex, null /* metadata */, value, BaseValueSourceInternal.Local);
                    _hasBeenSet = true;
                }
                else
                {
                    instance.UnsetEffectiveValue(entryIndex, null /* dp */, null /* metadata */);
                }
            }
            else
            {
                throw new ArgumentNullException("instance");
            }
        }
 
        /// <summary>
        ///     如果没有设置值,就从默认获取,或者上一级,方法和依赖属性相同
        ///     Read the value of this field on a DependencyObject instance.
        /// </summary>
        /// <param name="instance">The DependencyObject from which to get the value.</param>
        /// <returns></returns>
        public T GetValue(DependencyObject instance)
        {
            if (instance != null)
            {
                if (_hasBeenSet)
                {
                    EntryIndex entryIndex = instance.LookupEntry(_globalIndex);
 
                    if (entryIndex.Found)
                    {
                        object value = instance.EffectiveValues[entryIndex.Index].LocalValue;
 
                        if (value != DependencyProperty.UnsetValue)
                        {
                            return (T)value;
                        }
                    }
                    return _defaultValue;
                }
                else
                {
                    return _defaultValue;
                }
            }
            else
            {
                throw new ArgumentNullException("instance");
            }
        }
 
 
        /// <summary>
        ///     Clear this field from the given DependencyObject instance.
        /// </summary>
        /// <param name="instance"></param>
        public void ClearValue(DependencyObject instance)
        {
            if (instance != null)
            {
                EntryIndex entryIndex = instance.LookupEntry(_globalIndex);
 
                instance.UnsetEffectiveValue(entryIndex, null /* dp */, null /* metadata */);
            }
            else
            {
                throw new ArgumentNullException("instance");
            }
        }
 
        internal int GlobalIndex
        {
            get
            {
                return _globalIndex;
            }
        }
 
        #region Private Fields
 
        private T _defaultValue;
        private int _globalIndex;
        private bool _hasBeenSet;
 
        #endregion
    }

从上面的代码可以自己定义一个和他一样的类,用来存放比较少的属性,但是使用不多,因为现在的软件很少需要减少那么少的内存。

参见 https://stackoverflow.com/a/18280136/6116637

当前的 WPF 在 https://github.com/dotnet/wpf 完全开源,使用友好的 MIT 协议,意味着允许任何人任何组织和企业任意处置,包括使用,复制,修改,合并,发表,分发,再授权,或者销售。在仓库里面包含了完全的构建逻辑,只需要本地的网络足够好(因为需要下载一堆构建工具),即可进行本地构建


本文会经常更新,请阅读原文: https://blog.lindexi.com/post/WPF-UncommonField-%E7%B1%BB%E5%9E%8B%E6%98%AF%E4%BB%80%E4%B9%88.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

如果你想持续阅读我的最新博客,请点击 RSS 订阅,推荐使用RSS Stalker订阅博客,或者前往 CSDN 关注我的主页

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名林德熙(包含链接: https://blog.lindexi.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系

无盈利,不卖课,做纯粹的技术博客

以下是广告时间

推荐关注 Edi.Wang 的公众号
lindexi%2F201985113622445

欢迎进入 Eleven 老师组建的 .NET 社区
lindexi%2F20209121930471745.jpg

以上广告全是友情推广,无盈利


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK