WPF自學入門(五)WPF依賴屬性


      在.NET中有事件也有屬性,WPF中加入了路由事件,也加入了依賴屬性。最近在寫項目時還不知道WPF依賴屬性是干什么用的,在使用依賴項屬性的時候我都以為是在用.NET中的屬性,但是確實上不是的,通過閱讀文章和看WPF的書籍已經了解了WPF的依賴屬性的使用,我們今天就來看看為什么WPF中要加入依賴屬性?

 

一、什么是依賴屬性

       WPF中的依賴屬性有別於.NET中的屬性,因為在WPF中有幾個很重要的特征都是需要依賴項屬性的支持,例如數據綁定,動畫,樣式設置等。WPF絕大多數屬性都是依賴項屬性,只不過它是用了普通的.NET屬性過程進行了包裝,通過這種包裝,就可以像使用屬性一樣使用依賴項屬性了,在后面會說一下怎么通過這種方式包裝的。這就使用了舊技術來包裝新技術的設計理念就不會干擾.NET。WPF中的依賴屬性主要有以下三個優點:

    1、依賴屬性加入了屬性變化通知、限制、驗證等功能。這樣可以使我們更方便地實現應用,同時大大減少了代碼量。

    2、節約內存:在WinForm中,每個UI控件的屬性都賦予了初始值,這樣每個相同的控件在內存中都會保存一份初始值。而WPF依賴屬性很好地解決了這個問題,它內部實現使用哈希表存儲機制,對多個相同控件的相同屬性的值都只保存一份。

      3、支持多種提供對象:可以通過多種方式來設置依賴屬性的值。可以配合表達式、樣式和綁定來對依賴屬性設置值。

 

     剛才我們一直在說屬性,先來看看屬性是什么吧。先創建一個類Person,里面有name屬性。

public class Person

{

       public string name{set;get;}

}

上面就是創建好的屬性,看着是不是很簡單。屬性的創建就是這么簡單,在我們想要使用這個類的地方初始化就能用。

       既然說WPF中絕大多數的屬性都是依賴項屬性,我看了一下依賴屬性怎么進行創建。

        1、依賴屬性的所在類型繼承自DependencyObject類。

        2、使用public static 聲明一個DependencyProperty的變量,該變量就是真正的依賴屬性。

        3、類型的靜態構造函數中通過Register方法完成依賴屬性的元數據注冊。

        4、提供依賴屬性的包裝屬性,通過這個屬性來完成對依賴屬性的讀寫操作。

創建代碼如下:

//依賴屬性必須在依賴對象DependencyObject

Public class Person : DependencyObject 

    //CLR屬性包裝器,使得依賴屬性NameProperty在外部能夠像普通屬性那樣使用 

    public string Name 

    { 

        get { return (string)GetValue(NameProperty); } 

        set { SetValue(NameProperty, value); } 

    } 

 

 //依賴屬性必須為static readonly

//DependencyProperty.Register 參數說明

//第一個參數是string類型的,是屬性名。

//第二個參數是這個依賴項屬性的類型。

//第三個參數是這個擁有這個依賴項屬性的類型。

//第四個參數是具有附加屬性設置的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屬性也不會發生改變,其值為默認值。

四、自定義依賴屬性    

       如果想要依賴屬性繼承,我們可以進行自定義依賴屬性繼承屬性值。

自定義屬性步驟:

1、創建派生類CustomStackPanl

 

創建派生類CustomButton

 

2、在window控件中引入命名空間

   xmlns:sys="clr-namespace:System;assembly=mscorlib"

3、在頁面添加Button

 

效果:

 

五、依賴屬性驗證和強制功能

        在寫代碼是都會考慮可能發生的錯誤。在定義屬性時,也需要考慮錯誤設置屬性的可能性。對於傳統.NET屬性,可以在屬性的設置器中進行屬性值的驗證,不滿足條件的值可以拋出異常。但對於依賴屬性來說,這種方法不合適,因為依賴屬性通過SetValue方法來直接設置其值的。然而WPF有其代替的方式,WPF中提供了兩種方法來用於驗證依賴屬性的值。

       1、ValidateValueCallback:該回調函數可以接受或拒絕新值。該值可作為DependencyProperty.Register方法的一個參數。

       2、CoerceValueCallback:該回調函數可將新值強制修改為可被接受的值。例如某個依賴屬性工作年齡的值范圍是25到55,在該回調函數中,可以對設置的值進行強制修改,對於不滿足條件的值,強制修改為滿足條件的值。如當設置為負值時,可強制修改為0。該回調函數PropertyMetadata構造函數參數進行傳遞。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM