Dependency Property 依賴屬性
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中的,當然可讀可寫啦。
Dependency Property 依賴屬性