Dependency Property 依賴屬性

依賴屬性就是一種可以自己沒有值,並能通過使用Binding從數據源獲得值(依賴在別人身上)的屬性。擁有依賴屬性的對象稱爲“依賴對象”。

WPF開發中,必須使用依賴對象作爲依賴屬性的宿主,使二者結合起來。依賴對象的概念被DependencyObject類所實現,依賴屬性的概念則由DependencyProperty類所實現

從這棵繼承樹上可以看出,WPF的所有UI空間都是依賴對象。

看最簡單的依賴屬性

複製代碼
class Student : DependencyObject
    {

        public string Name
        {
            get { return (string)GetValue(NameProperty); }
            set { SetValue(NameProperty, value); }
        }

        public static readonly DependencyProperty NameProperty =
            DependencyProperty.Register("Name", typeof(string), typeof(Student));        
    }
複製代碼

實例並非使用new操作符得到而是使用DependencyProperty.Register方法生成。

現在我們使用的Register方法是參數最少,最簡單的一個重載,我們來分析一下

  • 第一個參數爲string類型,表示指明以哪個CLR屬性作爲這個依賴屬性的包裝器。就是代碼
public string Name
        {
            get { return (string)GetValue(NameProperty); }
            set { SetValue(NameProperty, value); }
        }
  • 第二個參數指明此依賴屬性用來存儲什麼樣的值。
  • 第三個參數用來指明此依賴屬性的宿主是什麼類型,或者說DependencyProperty.Register方法要將這個依賴屬性註冊到哪個類型上。

注意:1.依賴屬性包裝器是一個CLR屬性,並不是依賴屬性,沒有包裝器,依賴屬性依舊存在。

         2.既然沒有包裝器依賴屬性也存在,那麼包裝器是幹什麼用的呢?包裝器的作用是以“實例屬性”的形式向外界暴露依賴屬性,這樣,一個依賴屬性才能成爲數據源的一個Path。

         3.註冊依賴屬性時使用的第二個參數是一個數據類型,這個數據類型也是包裝器的數據類型。

請看例子

複製代碼
<Window x:Class="DependencyPropertySample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel>
        <TextBox x:Name="textbox1" BorderBrush="Black" Margin="5"/>
        <TextBox x:Name="textbox2" BorderBrush="Black" Margin="5"/>
        <Button Content="OK" Margin="5" Click="Button_Click"/>
    </StackPanel>
</Window>
複製代碼
複製代碼
public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Student stu = new Student();
            stu.SetValue(Student.NameProperty, textbox1.Text);
            textbox2.Text = (string)stu.GetValue(Student.NameProperty);
        }
    }
複製代碼

當第一次看到這個例子的時候,也許會有點百思不得其解的感覺——依賴屬性不是一個Static對象麼?哪怕有1000個Student實例,依賴屬性只有一個啊,那麼SetValue把值存儲到哪裏去了?GetValue又從哪裏讀取值?並且,依賴屬性不是一個只讀的嗎?怎麼可以寫入值呢?其實這個問題直指依賴屬性機制的核心,我們過一會再討論。

還要注意一點,儘管student類沒有實現INotifyPropertyChange接口,當屬性的值發生改變時與之關聯的Binding對象依然可以得到通知,依賴屬性默認帶有這樣的功能,天生就是合格的數據源。

使用vs2010有一個小技巧,生成依賴屬性可以使用代碼段propdp,DependencyProperty.Register帶4個參數,第四個參數的類型是PropertyMetadata類,作用是給依賴屬性的DefaultMetadata屬性賦值。顧名思義,DefaultMetadata的作用就是向依賴屬性的調用者提供一些基本信息,這些信息包括:

  • CoerceValueCallback:依賴屬性的值被強制改變時此委託會被調用,此委託可關聯一個函數。
  • DefaultValue:依賴屬性未被顯示賦值時,若讀取之則獲得此默認值,不設置此值會拋出異常。
  • IsSealed:控制PropertyMetadata的屬性值是否可以更改,默認值爲true。
  • PropertyChangeCallback:依賴屬性的值被改變之後此委託會被調用,此委託可關聯一個函數。

注意:依賴屬性的DefaultMetadata只能通過Register方法的第四個參數驚醒賦值,而且一旦賦值就不能改變。如果想用新的PropertyMetadata替換這個默認的Metadata,需要使用DependencyProperty.OverrideMetadata方法。

下面我們來解決剛纔的紅色問題。

首先值存到什麼地方去了?

創建一個DependencyProperty實例並用它的CLR屬性名和宿主類型名生成hash code,最後把hash code和DependencyProperty實例作爲Key-Value對存入全局的,名爲PropertyFormName的Hashtable中。

。。。(我認爲書上寫的太深奧啦,想要深究的同學可以參考《深入淺出WPF》)

初學者不必深究,那就是使用了static和readonly是爲了保證DependencyProperty的索引值唯一。真正的值是存在一個Hashtable中的,當然可讀可寫啦。

發佈了17 篇原創文章 · 獲贊 9 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章