依賴項屬性雖然在使用上和CLR屬性同樣,可是它是WPF特有的,不一樣於CLR屬性。只是封裝爲咱們經常使用CLR的屬性,在語法使用上和CLR屬性同樣。WPF中一些功能:動畫,屬性綁定,樣式等都是以依賴項屬性爲基礎的。WPF中元素的屬性大部分都是依賴項屬性。html
依賴項屬性和CLR屬性最主要的區別是:CLR屬性是經過一個私有的字段來讀取。而依賴項屬性則是經過繼承在DependencyObject
的GetValue()
和SetValue()
方法動態的讀取屬性值。app
就是說當設置一個依賴項屬性值時,並非直接給一個對象的字段賦值,而是在一個DependencyObject
對象的字典中設置鍵值對。Key
值爲屬性的名稱,Value
值爲你要賦值的值。函數
爲何使用依賴項屬性:字體
減小內存
當UI控件的90%以上的屬性一般停留在初始值時,爲每一個屬性存儲字段會是一個巨大的消耗。依賴項屬性則是隻在實例中存儲修改的屬性,那些默認值只在依賴項屬性中存儲一次。(如字體屬性,並非每一個元素都存儲一個字體屬性,字體屬性只存儲一次,其餘元素則是繼承該字體屬性。即:值繼承)動畫
值繼承
當訪問依賴項屬性時,該屬性值將經過使用一個值解析策略來解決:若是沒有設置本地值,則依賴屬性將導航到邏輯樹,直到找到一個值爲止。當在根元素上設置FontSize時,它將應用該根元素的全部子元素的全部文本塊,除非在子元素中從新設置了FontSize值。.net
更改通知
依賴屬性有一個內置的變動通知機制。經過在屬性元數據中註冊一個回調,當屬性值被更改時,就會獲得通知。這也是數據綁定所使用的。code
若是但願本來不支持數據綁定,動畫,或其餘WPF功能的代碼實現這些功能時,就要建立依賴項屬性。htm
聲明一個DependencyProperty
類型的字段,表示依賴項屬性的對象。該屬性的值應該始終保持可用,同時爲了保證在多個類之間共享該屬性信息,必須將DependencyProperty
對象定義爲與其類關聯的靜態字段,WPF爲了確保在建立DependencyProperty
對象後不能修改該對象,因此全部的DependencyProperty
成員都是隻讀的。
(如:Margin屬性,全部的類都共享該屬性,因此該屬性必須是與類自己關聯。)對象
//聲明一個當前時間的依賴項屬性 public static readonly DependencyProperty CurrentTimeProperty;
在使用該屬性代碼以前要先完成註冊(即該屬性和被註冊的類和數據類型,默認值,及一些事件關聯起來)完成,所以要在與其關聯的靜態構造函數中進行。WPF爲了確保DependencyProperty
對象不能被直接實例化,使DependencyProperty
類沒有公有的構造函數。只能使用靜態方法DependencyPropery.Register()
建立DependencyProperty
實例。這些註冊的值必須做爲Register()
方法的參數來提供。繼承
public class MyClockControl1 { CurrentTimeProperty = DependencyProperty.Register( "CurrentTime", typeof(DateTime), typeof(MyClockControl), new FrameworkPropertyMetadata(DateTime.Now),validateValueCallback); static bool validateValueCallback(object data) { //自定義驗證 return true; } }
Register()
註冊方法一共有五個參數,其中前三個爲必選,後兩個爲可選參數。
每一個依賴屬性都提供了更改通知、值強制和驗證的回調。這些回調能夠經過FrameworkPropertyMetadata
來實現。
如:
new FrameworkPropertyMetadata( DateTime.Now, OnCurrentTimePropertyChanged, OnCoerceCurrentTimeProperty ),OnValidateCurrentTimeProperty );
值更改回調是一個靜態方法,每當該屬性值更改時,都會調用這個回調方法。
private static void OnCurrentTimePropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e) { MyClockControl control = source as MyClockControl; DateTime time = (DateTime)e.NewValue; }
在執行屬性驗證回調前先執行該方法,嘗試糾正不合法的屬性值。
private static object OnCoerceTimeProperty( DependencyObject sender, object data ) { if ((DateTime)data > DateTime.Now ) { data = DateTime.Now; } return data; }
但依賴項屬性的值發生變化時調用該回調方法。該回調方法驗證屬性值是否合法,若是不合法,返回false,拋出異常。
private static bool OnValidateTimeProperty(object data) { return data is DateTime; }
依賴項屬性的包裝器,是經過DependencyObject的GetValue()和SetValue()方法來包裝。
public DateTime CurrentTime { get { return (DateTime)GetValue(CurrentTimeProperty); } set { SetValue(CurrentTimeProperty, value); } }
完整的代碼以下:
// Dependency Property public static readonly DependencyProperty CurrentTimeProperty = DependencyProperty.Register( "CurrentTime", typeof(DateTime), typeof(MyClockControl), new FrameworkPropertyMetadata(DateTime.Now)); // .NET Property wrapper public DateTime CurrentTime { get { return (DateTime)GetValue(CurrentTimeProperty); } set { SetValue(CurrentTimeProperty, value); } } static bool validateValueCallback(object data) { //自定義驗證 return true; }
自定義一個依賴項屬性,須要挺多的套路,固然這些套路不須要你一個一個代碼來敲,在Visual Studio能夠輸入propdp
再點擊兩次tab
鍵,就能夠建立依賴項屬性模板。 只需修改模板的屬性名稱和類型便可。
模板代碼以下:
public int MyProperty { get { return (int)GetValue(MyPropertyProperty); } set { SetValue(MyPropertyProperty, value); } } // Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc... public static readonly DependencyProperty MyPropertyProperty = DependencyProperty.Register("MyProperty", typeof(int), typeof(ownerclass), new PropertyMetadata(0));
附加屬性也是一種依賴項屬性。與其餘依賴項屬性不一樣的時,其餘的依賴項屬性是應用到被註冊的類上,而附加屬性則是應用到其餘的類上。
好比:Canvas
的類的Top
和Left
等爲附加屬性,其餘的元素並無該屬性,只有Canvas
類有,在使用Canvas.Top
時,若是爲每一個元素都定義一個這樣的依賴項屬性,那麼就會大量的重複性代碼,且不可維護更改。若是隻在Canvas
類型上定義這個依賴項屬性,其餘的元素只繼承使用該屬性就好。附加屬性就是這樣。
附加屬性的定義和依賴項屬性的定義幾乎同樣。惟一不一樣的是註冊是經過調用DependencyProperty.GegisterAttached()
方法來實現,且屬性包裝器爲靜態方法。
如:
public static readonly DependencyProperty TopProperty = DependencyProperty.RegisterAttached("Top", typeof(double), typeof(Canvas), new FrameworkPropertyMetadata(0d, FrameworkPropertyMetadataOptions.Inherits)); public static void SetTop(UIElement element, double value) { element.SetValue(TopProperty, value); } public static double GetTop(UIElement element) { return (double)element.GetValue(TopProperty); }
至此就能夠像使用普通的CLR屬性同樣使用WPF的依賴項屬性。
若有不對,請多多指教!
參考列表: