WPF的依賴項屬性 屬性與事件是.NET抽象模型的核心部分。WPF使用了更高級的依賴項屬性(Dependency Property)功能來替換原來.NET的屬性,實現了更高效率的保存機制,還添加了附加功能,如屬性變更通知以及強制回調、屬性值繼承(在邏輯樹中向下傳播預設屬性值的能力)以及屬性有效性驗證 ...
WPF的依賴項屬性
屬性與事件是.NET抽象模型的核心部分。WPF使用了更高級的依賴項屬性(Dependency Property)功能來替換原來.NET的屬性,實現了更高效率的保存機制,還添加了附加功能,如屬性變更通知以及強制回調、屬性值繼承(在邏輯樹中向下傳播預設屬性值的能力)以及屬性有效性驗證等。同時,依賴項屬性也是WPF許多重要功能的基礎,包括動畫、數據綁定以及樣式。
依賴項屬性的使用基礎
使用依賴項屬性包括三個部分,定義依賴項屬性;註冊依賴項屬性以及添加屬性包裝器。
定義依賴項屬性,使用三個修飾詞,public、static、readonly。數據類型為DependecyProperty,而每一個依賴項屬性都會有一個去掉“Property”的CLR屬性和他對應,而我們在xaml中訪問的都是CLR屬性。
註冊依賴項屬性,這也是依賴項屬性的真正含義,在於定義一個DependecyProperty屬性後外部訪問只能通過其對應的CLR屬性,其本質通過DependecyProperty.Register註冊,寫入了DependecyProperty類中的Hastable中,所有的依賴屬性都寫入這個哈希表中,哈希表的key值由依賴項屬性的name+type組成,保證了key值的唯一性。當需要設置依賴項屬性的值時,則會為這個對象創建一個數組,數據類型為EffectiveValueEntry,包含了一個屬性的index,DependencyProperty提供了一個方法GetglobalIndex來獲取此屬性在Hashtable中的位置,value當然就可以在此取出。
註冊依賴項屬性,在這一步驟中,我們主要負責提供5個要素:
- 屬性名
- 屬性使用的數據類型
- 擁有該屬性的類型
- 一個具有附加屬性設置的(Framework)PropertyMetadata對象,可選
- 一個用於驗證屬性的回調函數 ValidateValueCallback(驗證回調),可選
其中的FrameworkPropertyMetadata依賴屬性元數據對象,是功能最為豐富的一項要素,元數據中可能包括WPF不同級別的依賴屬性的特征,這些特征報告各種服務(如 WPF框架級別的佈局引擎和屬性繼承邏輯)的信息和狀態,大致包括以下信息:
- 依賴項屬性的預設值
- 更改通知的回調實現的引用
- 強制回調實現的引用
public static DependencyProperty Register( string name,--依賴項對象的名稱 Type propertyType,--屬性的類型 Type ownerType,--依賴項對象的所有者類型 PropertyMetadata typeMetadata,--依賴項對象的屬性元數據 ValidateValueCallback validateValueCallback--對回調的引用 ) public PropertyMetadata( Object defaultValue,--依賴項對象的預設值 --每當屬性的有效值更改時,屬性系統都將調用該處理程式實現 PropertyChangedCallback propertyChangedCallback, --每當屬性系統對該屬性調用 CoerceValue 時都將調用此處理程式實現 CoerceValueCallback coerceValueCallback ) --核心級別具有呈現/用戶界面影響的非框架屬性提供屬性元數據 public UIPropertyMetadata( Object defaultValue, PropertyChangedCallback propertyChangedCallback, CoerceValueCallback coerceValueCallback, bool isAnimationProhibited--是否禁止動畫處理,預設為false ) --框架的屬性系統 public FrameworkPropertyMetadata( Object defaultValue, --元數據選項標誌(FrameworkPropertyMetadataOptions 值的組合) FrameworkPropertyMetadataOptions flags, PropertyChangedCallback propertyChangedCallback, CoerceValueCallback coerceValueCallback, bool isAnimationProhibited, --此屬性的綁定時使用的 UpdateSourceTrigger UpdateSourceTrigger defaultUpdateSourceTrigger )
依賴項屬性值變更回調、強制回調以及驗證回調的執行順序如下:
驗證:ValidateValueCallback
強制值:CoerceValueCallback
回調:PropertyChangedCallback
添加屬性包裝器,最後一個步驟是使用傳統的.NET屬性封裝WPF的依賴項屬性,封裝函數中set、get訪問器分別調用了DependecyObjec基類中定義的GetValue()和SetValue()方法。
依賴項屬性在數據綁定中的應用
數據綁定中,有5個要素:
- Source:確定哪個對象作為數據源
- Target:確定哪個對象作為目標
- 聲明一個Binding實例,用於關聯數據
- 數據源的Path,可以是CLR屬性也可以是依賴項屬性,甚至屬性的子屬性
- 目標的D.P.,只能是依賴項屬性
D.P.的全稱是“Dependency Property”,直譯過來就是“依賴式屬性”,意思是說它自己本身是沒有值的,它的值是“依賴”在其它對象的屬性值上、通過Binding的傳遞和轉換而得來的。表現在例子里,它就是Target上的被數據所驅動的聯動屬性了!
其中值得註意的是,當源數據發生改變時,需要通知界面數據變更,併進行界面更新。如若,數據源的Path是一個普通屬性,即需要實現INotifyPropertyChanged介面,以此來通知界面變更;而如果數據源的Path是一個依賴項屬性,其中INotifyPropertyChanged是為DependencyObject服務的,即可自動發生界面更新事件。
在數據綁定中,也凸顯了Winform與WPF的巨大差異,WPF真正意義上實現了 “數據驅動界面” 的模式。換而言之,數據是底層、是心臟,數據變了作為表層的UI就會跟著變、將數據展現給用戶;如果用戶修改了UI元素上的值,相當於透過UI元素直接修改了底層的數據;數據處於核心地位,UI處於從屬地位。數據是程式的發動機(驅動者)、UI成了幾乎不包含任何邏輯專供用戶觀察數據和修改數據的“視窗”(被驅動者)。