1. 程式人生 > >WPF入門教程系列十一——依賴屬性(一)

WPF入門教程系列十一——依賴屬性(一)

nts 如果 edev 出現 樣式 語法 寫法 屬性。 結構

一、依賴屬性基本介紹

  本篇開始學習WPF的另一個重要內容依賴屬性。

大家都知道WPF帶來了很多新的特性,其中一個就是引入了一種新的屬性機制——依賴屬性。依賴屬性出現的目的是用來實現WPF中的樣式、自動綁定及實現動畫等特性。依賴屬性的出現是WPF這種特殊的呈現原理派生出來的,與.NET普通屬性不同的是,依賴屬性的值是依靠多個提供程序來判斷的,並且其具有內建的傳遞變更通知的能力。

依賴屬性基本應用在了WPF的所有需要設置屬性的元素。依賴屬性根據多個提供對象來決定它的值 (可以是動畫、父類元素、綁定、樣式和模板等),同時這個值也能及時響應變化。

依賴屬性就是可以自己沒有值,並能夠通過Binding從數據源獲 取值(依賴在別人身上)的屬性。擁有依賴屬性的對象被稱為“依賴對象”。依賴項屬性的重點在於“依賴”二字,既然是依賴了,也就是說:依賴項屬性的值的改變過程一定與其它對相關,不A依賴B就B依賴A,或者相互依賴。

說白了,所謂依賴,主要應用在以下地方:

1、雙向綁定。有了這個,依賴項屬性不用寫額的代碼,也不用實現什麽接口,它本身就俱備雙向綁定的特性,比如,我把員工對象的姓名綁定到搖文本框,一旦綁定,只要文本框中的值發生改變,依賴項屬性員工姓名也會跟著變化,反之亦然;

2、觸發器。這個東西在WPF中很重要,比如,一個按鈕背景是紅色,我想讓它在鼠標停留在它上面是背景變成綠色,而鼠標一旦移開,按鈕恢復紅色。

如果在傳統的Windows編程中,你一定會想辦法弄一些事件,或者委托來處理,還要寫一堆代碼。告訴你,有了依賴項屬性,你將一行代碼都不用寫,所有的處理均由WPF屬性系統自動處理。而觸發器只是臨時改變屬性的值,當觸完成時,屬性值自動被“還原”。

3、附加屬性。附加屬性也是依賴項屬性,它可以把A類型的的某些屬性推遲到運行時根據B類型的具體情況來進行設置,而且可以同時被多個類型對象同時維護同一個屬性值,但每個實例的屬性值是獨立的。

4、A屬性改變時,也同時改變其它屬性的值,如TogleButton按下的同時,彈出下拉框。

與傳統的CLR屬性和面向對象相比依賴屬性有很多新穎之處,其中包括:

1、新功能的引入:加入了屬性變化通知,限制、驗證等等功能,這樣就可以使我們更方便的實現我們的應用,同時也使代碼量大大減少了,許多之前不可能的功能都可以輕松的實現了。
2、 節約內存:在WinForm等項目開發中,你會發現UI控件的屬性通常都是賦予的初始值,為每一個屬性存儲一個字段將是對內存的巨大浪費。WPF依賴屬性 允許對象在被創建的時候並不包含用於存儲數據的空間(即字段所占用的空間)、只保留在需要用到數據的時候能夠獲得默認值。借用其它對象的數據或者實 時分配空間的能力----這種對象稱為依賴對象而他這種實時獲取數據的能力則依靠依賴屬性來實現。在WPF開發中,必須使用依賴對象作為依賴屬性的宿主, 使二者結合起來,才能形成完整的Binding目標被數據所驅動。。
3、支持多個提供對象:我們可以通過多種方式來設置依賴屬性的值。同時其內部可以儲存多個值,配合Expression、Style、Animation等可以給我們帶來很強的開發體驗。
  在.NET當中,對於屬性是大家應該很熟悉,封裝類的字段,表示類的狀態,編譯後被轉化為對應的get和set方法。屬性可以被類或結構等使用。 一個簡單的屬性如下,也是我們常用的寫法:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 public class Student { string m_Name; public string Name { get { return m_Name; } set { m_Name = value; } } static Student() { } }

依賴屬性與普通的.NET屬性的區別是普通的.NET屬性定義只需要定義其set和get區塊的賦值與設置。那麽依賴屬性應該怎麽定義呢?依賴屬性和屬性到底有什麽區別和聯系呢?其實依賴屬性的實現也很簡單,按以下步驟做就可以了:

第一步: 讓自己的類繼承自 DependencyObject基類。在WPF中,幾乎所有的UI元素都繼承自DependencyObject,這個類封裝了對依賴屬性的存儲及 訪問等操作,使用靜態類型與依賴屬性的內部存儲機制相關。WPF處理依賴屬性不再像普通.NET屬性那樣將屬性值存儲到一個私有變量中,而是使用一個字典 型的變量來存放用戶顯示設置的值。

第二步:依賴屬性的定義必須使用 public static 聲明一個 DependencyProperty的變量,並且有一個Property作為後綴,該變量才是真正的依賴屬性 。例如下面的代碼定義了一個依賴屬性NameProperty:

1 public static readonly DependencyProperty NameProperty;

第三步:在靜態構造函數中向屬性系統註冊依賴屬性,並獲取對象引用。依賴屬性是通過調用DependencyProperty.Register靜態方法創建,該方法需要傳遞一個屬性 名稱,這個名稱非常重要,在定義控件Style和Template的時候,Setter的Property屬性填入的值就是註冊依賴屬性時使用的名稱。propertyType指明了依賴屬性實際的類型,ownerType指明了是哪個類註冊了此依賴屬性,最後typeMetadata存放了一些依賴屬 性的元信息,包括依賴屬性使用的默認值,還有屬性值發生變更時的通知函數。例如,下面的代碼註冊了依賴屬性。

1 NameProperty = DependencyProperty.Register("Name", typeof(string), typeof(Student), new PropertyMetadata("名稱", OnValueChanged));

第四步:在前面的三步中,我們完成了一個依賴屬性的註冊,那麽我們怎樣才能對這個依賴屬性進行讀寫呢?答案就是提供一個依賴屬性的實例化包裝屬性,通過這個屬性來實現具體的讀寫操作。和CLR屬性不同,依賴屬性不是直接對私有變量的操縱,而是通過GetValue()和SetValue()方法來操作屬性值的,可以使用標準的.NET屬性定義語法進行封裝,使依賴屬性可以像標準屬性那樣來使用,代碼如下。

1 2 3 4 5 6 7 8 9 public string Name { get { return (string)GetValue(NameProperty); } set { SetValue(NameProperty, value); } }

根據前面的四步操作,我們就可以寫出下面的代碼:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 public class Student : DependencyObject { //聲明一個靜態只讀的DependencyProperty字段 public static readonly DependencyProperty NameProperty; static Student() { //註冊我們定義的依賴屬性Name NameProperty = DependencyProperty.Register("Name", typeof(string), typeof(Student), new PropertyMetadata("名稱", OnValueChanged)); } private static void OnValueChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) { //當值改變時,我們可以在此做一些邏輯處理 } //屬性包裝器,通過它來讀取和設置我們剛才註冊的依賴屬性 public string Name { get { return (string)GetValue(NameProperty); } set { SetValue(NameProperty, value); } } }

總結:我們一般.NET屬性是直接對類的一個私有屬性進行封裝,所以讀取值的時候,也就是直接讀取這個字段;而依賴屬性則是通過調用繼承自DependencyObject的GetValue()和SetValue來進行操作,它實際存儲在DependencyProperty的一個IDictionary的鍵-值配對字典中,所以一條記錄中的鍵(Key)就是該屬性的HashCode值,而值(Value)則是我們註冊的DependencyProperty。

WPF入門教程系列十一——依賴屬性(一)