zoukankan      html  css  js  c++  java
  • WPF依赖属性DependencyProperty

    写在之前:

    依赖属性算是WPF醉醉基础的一个组成了。平时写代码的时候,简单的绑定很轻松,但是遇到复杂的层次比较多的绑定,真的是要命。所以,我觉得深刻认识依赖属性是很有必要的。本篇只是个人学习的记录,学习的博客是周永恒先生的《一站式WPF--依赖属性(DependencyProperty)》,这算是一个系列了,说的很详细。如果需要更好的学习,建议移步上述原文,受益匪浅。

    什么是依赖属性?

    Windows Presentation Foundation (WPF) 提供了一组服务,这些服务可用于扩展公共语言运行时 (CLR) 属性的功能,这些服务通常统称为 WPF 属性系统。由 WPF 属性系统支持的属性称为依赖项属性。----MSDN

    也就是说,WPF提供一组叫做‘WPF属性系统’的服务,而依赖属性就是被这个服务所支持的属性。我只能说,每个字都认识,但是放在一起认识的就不那么清晰了……

    首先,想要了解它,必须知道它是为了什么而来。

    虽然不清楚依赖属性,但是属性我们是很清楚的,封装类的字段,表示类的状态,编译后被转化为get_,set_方法,可以被类或结构等使用,常见的一个属性如下:

        public class ClassObject
        {
            private string name;
            public string Name
            {
                get { return name; }
                set { name = value; }
            }
        }

    既然已经有了属性,为什么还要有依赖属性呢?必然是属性有一些缺点了,而依赖属性恰好能够解决这个问题。以Button为例:

    每次继承,父类的私有字段都被继承下来。对Button来说,大多数属性并没有被修改,仍然保持父类定义时的默认值。通常情况下,在整个Button的对象生命周期中,也只有少部分属性被修改。也已看得出来:

    1. 每次继承,子类对象都会获得更多的属性,这样,继承树的低端对象不可避免的膨胀;
    2. 既然大多数属性没有被修改,那么就可以把这些属性从对象中剥离,减少对象的体积;

    可以知道,依赖属性就是为了解决这个问题诞生了。首先定义依赖属性,它里面存储之前2中希望剥离的属性:

        public class DependencyProperty
        {
            // 维护了一个全局的Map用来储存所有的DP
            internal static Dictionary<object, DependencyProperty> RegisteredDps = new Dictionary<object, DependencyProperty>();
            internal string Name;//注册属性名称
            internal object Value;//属性值
            internal object HashCode;//Mape唯一键值
    
            private DependencyProperty(string name, Type propertyName, Type ownerType, object defaultValue)
            {
                this.Name = name;
                this.Value = defaultValue;
                this.HashCode = name.GetHashCode() ^ ownerType.GetHashCode();
            }
            // 对外暴露一个Register方法用来注册新的DP
            public static DependencyProperty Register(string name, Type propertyName, Type ownerType, object defaultValue)
            {
                DependencyProperty dp = new DependencyProperty(name, propertyName, ownerType, defaultValue);
                RegisteredDps.Add(dp.HashCode, dp);
                return dp;
            }
        }

    然后定义DependencyObject来使用DP:

        public class DependencyObject
        {
            // 注册一个新的DP:NameProperty
            public static readonly DependencyProperty NameProperty = DependencyProperty.Register("Name", typeof(string), typeof(DependencyObject), string.Empty);
    
            public object GetValue(DependencyProperty dp)
            {
                return DependencyProperty.RegisteredDps[dp.HashCode].Value;
            }
    
            public void SetValue(DependencyProperty dp, object value)
            {
                DependencyProperty.RegisteredDps[dp.HashCode].Value = value;
            }
    
            public string Name
            {
                get
                {
                    return (string)GetValue(NameProperty);
                }
                set
                {
                    SetValue(NameProperty, value);
                }
            }
        }

    DependencyObject和文章开篇的ClassObject中的Name有什么不同呢?

    >>DependencyObject.Name的实际值不是用字段保存在DependencyObject中,而是保存在NameProperty中,通过SetValue和GetValue来金星赋值取值操作。

    在上述例子中,所有DependncuObject的对象将共用一个NameProperty,这在现实中是不实际的:只要修改一个对象的属性,相当于所有对象的属性值都被修改了。所以,修改的属性,还是要维护在相应的对象中的:(修改部分用表示)

        public class DependencyProperty
        {
            private static int globalIndex = 0;// // 维护了一个全局的Map用来储存所有的DP
            internal static Dictionary<object, DependencyProperty> RegisteredDps = new Dictionary<object, DependencyProperty>();
            internal string Name;//注册属性名称
            internal object Value;//属性值
            internal int Index;// 
    internal object HashCode;//Mape唯一键值 private DependencyProperty(string name, Type propertyName, Type ownerType, object defaultValue) { this.Name = name; this.Value = defaultValue; this.HashCode = name.GetHashCode() ^ ownerType.GetHashCode(); } // 对外暴露一个Register方法用来注册新的DP public static DependencyProperty Register(string name, Type propertyName, Type ownerType, object defaultValue) { DependencyProperty dp = new DependencyProperty(name, propertyName, ownerType, defaultValue); globalIndex++;// dp.Index = globalIndex; // RegisteredDps.Add(dp.HashCode, dp); return dp; } }  

    所有修改过的DP都保存在EffectiveValueEntry里,这样,就可以只保存修改的属性,未修改过的属性仍然读取DP的默认值,优化了属性的储存。

        public class DependencyObject
        {
            // 引入有效的概念// private List<EffectiveValueEntry> _effectiveValues = new List<EffectiveValueEntry>();
            // 注册一个新的DP:NameProperty
            public static readonly DependencyProperty NameProperty = DependencyProperty.Register("Name", typeof(string), typeof(DependencyObject), string.Empty);
    
            public object GetValue(DependencyProperty dp)
            {             // ☆
                EffectiveValueEntry effectiveValue = _effectiveValues.FirstOrDefault(i => i.PropertyIndex == dp.Index);
                if (effectiveValue.PropertyIndex != 0)
                {
                    return effectiveValue.Value;
                }
                else
                {
                    return DependencyProperty.RegisteredDps[dp.HashCode].Value;//仅此部分相同
                }
            }
    
            public void SetValue(DependencyProperty dp, object value)
            {             // 全部 ☆
                EffectiveValueEntry effectiveValue = _effectiveValues.FirstOrDefault(i => i.PropertyIndex == dp.Index);
                if (effectiveValue.PropertyIndex != 0)
                {
                    effectiveValue.Value = value;
                }
                else
                {
                    effectiveValue = new EffectiveValueEntry()
                    {
                        PropertyIndex = dp.Index,
                        Value = value
                    };
                }
                //DependencyProperty.RegisteredDps[dp.HashCode].Value = value;
            }
    
            public string Name
            {
                get
                {
                    return (string)GetValue(NameProperty);
                }
                set
                {
                    SetValue(NameProperty, value);
                }
            }
        }
        internal struct EffectiveValueEntry
        {
            internal int PropertyIndex{get;set;}
            internal object Value{get;set;}
        }
  • 相关阅读:
    网页动画
    浮动
    定位
    盒子模型
    表单
    2017年07月05号课堂笔记
    2017年07月07号课堂笔记
    2017年07月03号课堂笔记
    2017年06月30号课堂笔记
    2017年06月28号课堂笔记
  • 原文地址:https://www.cnblogs.com/YunGy/p/5045931.html
Copyright © 2011-2022 走看看