天天看點

依賴屬性之“風雲再起”四十. PropertyMetadata測試代碼十一. PropertyMetadata實作代碼

前面我們看到一個依賴屬性的注冊最全的形式是下面這樣子的:

  第一個參數是該依賴屬性的名字,第二個參數是依賴屬性的類型,第三個參數是該依賴屬性的所有者的類型,第五個參數就是一個驗證值的回調委托,那麼最使我們感興趣的還是這個可愛的 PropertyMetadata ,也就是我們接下來要講的中繼資料。 提到WPF屬性中繼資料,大家可能第一想到的是剛才的PropertyMetadata,那麼這個類到底是怎樣的呢?我們應該怎樣使用它呢?首先我們看它的構造函數(我們選參數最多的來講):

  其中的第一個參數是預設值,最後兩個分别是PropertyChanged(變化通知)以及Coerce(強制)的兩個委托變量,我們在執行個體化的時候,隻需要把這兩個委托變量關聯到具體的方法上即可。

  事實上,除了PropertyMetadata以外,常見的還有 FrameworkPropertyMetadata,UIPropertyMetadata。他們的繼承關系是F->U->P。其中以 FrameworkPropertyMetadata參數最多,亦最為複雜。

FrameworkPropertyMetadata的構造函數提供了很多重載,我們挑選最為複雜的重載來看它到底有哪些參數以及提供了哪些功能:

  其中第一個參數是預設值,最後兩個參數分别是是否允許動畫,以及綁定時更新的政策(在Binding當中相信大家并不陌生),這個不詳細解釋 了。重點看一下裡第三、四兩個參數,兩個 CallBack的委托。結合前面Register的時候提到的ValidateValueCallback共組成三大”金剛“,這三個Callback 分别代表Validate(驗證),PropertyChanged(變化通知)以及Coerce(強制)。當然,作為 Metadata,FrameworkPropertyMetadata隻是儲存了該依賴屬性的政策資訊,WPF屬性系統會根據這些資訊來提供功能并在适 當的時機回調傳入的delegate,是以最重要的還是我們定義的這些方法,通過他們傳入委托才能起到真正的作用。

具體PropertyMetadata包含哪些成員呢?我們先看微軟的PropertyMetadata類

<a href="http://images.cnblogs.com/cnblogs_com/KnightsWarrior/WindowsLiveWriter/d1051bd1bd80_136FD/2010-8-26%2019-14-21_2.png"></a>

  在寫其他測試用例之前,我們先來建立兩個類,第一個類TestDepObj,内部注冊了四個依賴屬性,前三個沒有中繼資料操作,也就是沒有顯示聲 明并構造中繼資料類,第四個添加了一個中繼資料類,這個中繼資料類包含了預設值、值改變回調委托、強制值回調委托。第二個類TestSubclass繼承自 TestDepObj。

  大家看到我們在建立PropertyMetadata的時候對某些功能并沒有實作,這裡我們就通過子類來具體實作,MONO的這種做法想沿襲微 軟PropertyMetadata、FrameworkPropertyMetadata和UIPropertyMetadata的做法,但是個人覺得 它實作得并不是太好,很多地方感覺很别扭。

  下面的測試代碼主要看一下中繼資料的預設值,執行個體化一個中繼資料類,然後調用它的DefaultValue、PropertyChangedCallback、CoerceValueCallback,測試他們是否為Null。

  我們在WPF和Silverlight中都有過這樣的體會:到底什麼時候這個依賴屬性不能再修改了,其實這個操作得歸功于OnApply什麼時 候觸發,我們也可以調用IsSealed來檢視,那麼這裡我們就先寫測試代碼。第一段代碼直接顯示調用CallApply方法進行密封;第二段代碼則是通 過OverrideMetadata操作後内部調用的CallApply;第三段代碼是通過AddOwner操作中調用的CallApply;最後一段代 碼通過調用DependencyProperty.Register時傳入中繼資料,在其内部調用CallApply。

下面這段測試代碼是驗證AddOwner後的DependencyProperty是否和原來的DependencyProperty是同一個DependencyProperty。

  下面這個測試用例是首先執行個體化中繼資料并作為注冊依賴屬性時的參數傳入,大家都知道此時如果想修改中繼資料,可以通過AddOwner或者OverrideMetadata,如果直接指派,會抛出錯誤,因為中繼資料已經密封。

這個和上面的那個測試用例基本一樣,隻不過把CoerceValueCallback換成了PropertyChangedCallback

下面這個測試用例也和上面的兩個測試用例類似,它是修改中繼資料的DefaultValue

  通過前面的測試用例,大家可能都會發現有一個Merge這個方法,它在什麼時候調用呢?其實它在OverrideMetadata和AddOwner操作中都會調用,在

DependencyProperty中的Register也會顯示調用一次。我們需要注意的是:在中繼資料密封了以後就會抛出錯誤。

下面的測試用例主要是預設值是不能被設定成Unset的

通過前面的多個測試用例,其實已經包含了PropertyMetadata的基本功能,那我們接下來就看一下PropertyMetadata的内部設計和實作。

MONO的PropertyMetadata類要比微軟的PropertyMetadata類簡單很多,不過我們也需要注意一下幾點:

1,中繼資料類包含哪些成員以及有幾個構造函數重載?因為這些直接關系到外部的調用。

2,大家要注意ValidateValueCallback不是PropertyMetadata的成員,是以在PropertyMetadata的構造函數中不要把它作為參數傳入。

3,注意OnApply函數,因為調用它之後就不能修改中繼資料的成員,隻有通過OverrideMetadata和AddOwner間接實作,如果大家想知道到底這個中繼資料有沒有被密封,可以調用IsSealed屬性來檢視,這個功能我們也會經常用到。

4,中繼資料類中提供了Merge的功能,用來友善合并父類和子類的中繼資料。

在上面幾個類就是依賴屬性系統的核心類,下面将看到幾個Helper類。

本文轉自KnightsWarrior51CTO部落格,原文連結: http://blog.51cto.com/knightswarrior/405233,如需轉載請自行聯系原作者