在.NET中有事件也有屬性,WPF中加入了路由事件,也加入了依賴屬性。最近在寫項目時還不知道WPF依賴屬性是幹什麼用的,在使用依賴項屬性的時候我都覺得是在用.NET中的屬性,可是確實上不是的,經過閱讀文章和看WPF的書籍已經瞭解了WPF的依賴屬性的使用,咱們今天就來看看爲何WPF中要加入依賴屬性?函數
WPF中的依賴屬性有別於.NET中的屬性,由於在WPF中有幾個很重要的特徵都是須要依賴項屬性的支持,例如數據綁定,動畫,樣式設置等。WPF絕大多數屬性都是依賴項屬性,只不過它是用了普通的.NET屬性過程進行了包裝,經過這種包裝,就能夠像使用屬性同樣使用依賴項屬性了,在後面會說一下怎麼經過這種方式包裝的。這就使用了舊技術來包裝新技術的設計理念就不會干擾.NET。WPF中的依賴屬性主要有如下三個優勢:字體
一、依賴屬性加入了屬性變化通知、限制、驗證等功能。這樣可使咱們更方便地實現應用,同時大大減小了代碼量。動畫
二、節約內存:在WinForm中,每一個UI控件的屬性都賦予了初始值,這樣每一個相同的控件在內存中都會保存一份初始值。而WPF依賴屬性很好地解決了這個問題,它內部實現使用哈希表存儲機制,對多個相同控件的相同屬性的值都只保存一份。spa
三、支持多種提供對象:能夠經過多種方式來設置依賴屬性的值。能夠配合表達式、樣式和綁定來對依賴屬性設置值。設計
剛纔咱們一直在說屬性,先來看看屬性是什麼吧。先建立一個類Person,裏面有name屬性。3d
public string name{set;get;}對象
上面就是建立好的屬性,看着是否是很簡單。屬性的建立就是這麼簡單,在咱們想要使用這個類的地方初始化就能用。
既然說WPF中絕大多數的屬性都是依賴項屬性,我看了一下依賴屬性怎麼進行建立。
一、依賴屬性的所在類型繼承自DependencyObject類。
二、使用public static 聲明一個DependencyProperty的變量,該變量就是真正的依賴屬性。
三、類型的靜態構造函數中經過Register方法完成依賴屬性的元數據註冊。
四、提供依賴屬性的包裝屬性,經過這個屬性來完成對依賴屬性的讀寫操做。
Public class Person : DependencyObject
//CLR屬性包裝器,使得依賴屬性NameProperty在外部可以像普通屬性那樣使用
get { return (string)GetValue(NameProperty); }
set { SetValue(NameProperty, value); }
//DependencyProperty.Register 參數說明
//第四個參數是具備附加屬性設置的FramWorkPropertyMetadata對象。
public static readonly DependencyProperty NameProperty =
DependencyProperty.Register("Name", typeof(string), typeof(Person), new PropertyMetadata("DefaultName"));
從上面代碼能夠看出,依賴屬性是經過調用DependencyObject的GetValue和SetValue來對依賴屬性進行讀寫的。它使用哈希表來進行存儲的,對應的Key就是屬性的HashCode值,而值(Value)則是註冊的DependencyPropery;而C#中的屬性是類私有字段的封裝,能夠經過對該字段進行操做來對屬性進行讀寫。屬性是字段的包裝,WPF中使用屬性對依賴屬性進行包裝。
WPF 屬性系統提供一種強大的方法,使得依賴屬性的值由多種因素決定,從而實現諸如實時屬性驗證、後期綁定以及向相關屬性發出有關其餘屬性值發生更改的通知等功能。 用來肯定依賴屬性值的確切順序和邏輯至關複雜。 瞭解此順序有助於避免沒必要要的屬性設置,而且還有可能澄清混淆,使你正確瞭解爲什麼某些影響或預測依賴屬性值的嘗試最終卻沒有得出所指望的值。依賴屬性能夠在多個位置「設置」,界面代碼以下:
本地屬性集在設置時具備最高優先級,動畫值和強制除外。 若是在本地設置某個值,你能夠期待該值優先獲得應用,甚至期待其優先級高於任何樣式或控件模板。 在上面示例中,此處Background本地設置爲紅色。 所以,即便它是隱式樣式,不然將會應用於該做用域中的該類型的全部元素,在此做用域中定義的樣式不是最高優先級給予Background屬性及其值。 若是從該 Button 實例中刪除本地值紅色,樣式將得到優先級,而按鈕將從該樣式中得到 Background 值。 在該樣式中,觸發器具備優先級,所以當鼠標位於按鈕上時,按鈕爲藍色,其餘狀況下則爲綠色。
下面的圖是在網上找的依賴屬性優先級列表圖,你們後面再使用屬性時能夠留意一下優先級。
依賴屬性的繼承是WPF屬性系統的一項功能。 屬性值繼承使元素樹中的子元素能夠從父元素獲取特定屬性的值,並繼承該值,就如同它是在最近的父元素中任意位置設置的同樣。 父元素可能也已經過屬性值繼承得到了其值,所以系統有可能一直遞歸到頁面根。 屬性值繼承不是默認屬性系統行爲;屬性必須用特定的元數據設置來創建,以便使該屬性對子元素啓動屬性值繼承。
看到上面圖片你可能已經發現了問題:StatusBar沒有顯式設置FontSize值,但它的字體大小沒有繼承Window.FontSize的值,而是保持了系統的默認值。致使這樣的問題是由於並非全部元素都支持屬性值繼承的,如StatusBar、Tooptip和Menu控件。另外,StatusBar等控件截獲了從父元素繼承來的屬性,而且該屬性也不會影響StatusBar控件的子元素。例如,若是咱們在StatusBar中添加一個Button。那麼這個Button的FontSize屬性也不會發生改變,其值爲默認值。
若是想要依賴屬性繼承,咱們能夠進行自定義依賴屬性繼承屬性值。
xmlns:sys="clr-namespace:System;assembly=mscorlib"
在寫代碼是都會考慮可能發生的錯誤。在定義屬性時,也須要考慮錯誤設置屬性的可能性。對於傳統.NET屬性,能夠在屬性的設置器中進行屬性值的驗證,不知足條件的值能夠拋出異常。但對於依賴屬性來講,這種方法不合適,由於依賴屬性經過SetValue方法來直接設置其值的。然而WPF有其代替的方式,WPF中提供了兩種方法來用於驗證依賴屬性的值。
一、ValidateValueCallback:該回調函數能夠接受或拒絕新值。該值可做爲DependencyProperty.Register方法的一個參數。
二、CoerceValueCallback:該回調函數可將新值強制修改成可被接受的值。例如某個依賴屬性工做年齡的值範圍是25到55,在該回調函數中,能夠對設置的值進行強制修改,對於不知足條件的值,強制修改成知足條件的值。如當設置爲負值時,可強制修改成0。該回調函數PropertyMetadata構造函數參數進行傳遞。