WPF依賴屬性DependencyProperty

寫在以前:html

依賴屬性算是WPF醉醉基礎的一個組成了。平時寫代碼的時候,簡單的綁定很輕鬆,可是遇到複雜的層次比較多的綁定,真的是要命。因此,我以爲深入認識依賴屬性是頗有必要的。本篇只是我的學習的記錄,學習的博客是周永恆先生的《一站式WPF--依賴屬性(DependencyProperty)》,這算是一個系列了,說的很詳細。若是須要更好的學習,建議移步上述原文,受益不淺。學習

什麼是依賴屬性?優化

Windows Presentation Foundation (WPF) 提供了一組服務,這些服務可用於擴展公共語言運行時 (CLR) 屬性的功能,這些服務一般統稱爲 WPF 屬性系統。由 WPF 屬性系統支持的屬性稱爲依賴項屬性。----MSDNthis

也就是說,WPF提供一組叫作‘WPF屬性系統’的服務,而依賴屬性就是被這個服務所支持的屬性。我只能說,每一個字都認識,可是放在一塊兒認識的就不那麼清晰了……spa

首先,想要了解它,必須知道它是爲了什麼而來。3d

雖然不清楚依賴屬性,可是屬性咱們是很清楚的,封裝類的字段,表示類的狀態,編譯後被轉化爲get_,set_方法,能夠被類或結構等使用,常見的一個屬性以下:code

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

既然已經有了屬性,爲何還要有依賴屬性呢?必然是屬性有一些缺點了,而依賴屬性剛好可以解決這個問題。以Button爲例:htm

每次繼承,父類的私有字段都被繼承下來。對Button來講,大多數屬性並無被修改,仍然保持父類定義時的默認值。一般狀況下,在整個Button的對象生命週期中,也只有少部分屬性被修改。也已看得出來:對象

  1. 每次繼承,子類對象都會得到更多的屬性,這樣,繼承樹的低端對象不可避免的膨脹;
  2. 既然大多數屬性沒有被修改,那麼就能夠把這些屬性從對象中剝離,減小對象的體積;

能夠知道,依賴屬性就是爲了解決這個問題誕生了。首先定義依賴屬性,它裏面存儲以前2中但願剝離的屬性:blog

    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;} }
相關文章
相關標籤/搜索