天天看點

第4章 依賴屬性(2)——自定義依賴屬性

一、定義依賴屬性

相對于建立依賴屬性,大多數情況下隻是使用它們。但是,仍然有許多原因需要建立自己的依賴屬性。例如:

(1)在設計自定義的WPF元素時,定義依賴屬性肯定是關鍵部分。

(2)當希望為原本不支援資料綁定、動畫或其他WPF功能的部分代碼添加這些功能時,也需要建立依賴屬性。

注意:隻能為依賴對象(直接或間接繼承自DependencyObject的類)添加依賴屬性。幸運的是,WPF基礎結構的關鍵部分中的大部分都直接或間接繼承自DependencyObject類,最明顯的例子就是元素。因為大多數時候都是為元素添加依賴屬性,是以第一步定義依賴對象就可以免了。

例如,FrameworkElement類對Margin屬性的定義,代碼如下:

public class FrameworkElement : UIElement,...
{
    public static readonly DependencyProperty MarginProperty;
}
           

注意:

(1)使用public static修飾,因為屬性資訊應該始終保持可用,甚至可能需要在多個類之間共享這些資訊。是以必須将DependencyProperty對象定義為與其相關聯的類的靜态字段。

(2)使用readonly修飾,這意味着隻能在FrameworkElement類的靜态構造函數中對其進行設定。

(3)根據約定,定義依賴項屬性的字段的名稱是在普通屬性的末尾處加上單詞"Property"。

二、注冊依賴屬性

注冊依賴屬性一般是在與其關聯的類的靜态構造函數中進行。代碼如下:

static FrameworkElement()
{
    FrameworkPropertyMetadata metadata = new FrameworkPropertyMetadata(new Thickness(), FrameworkPropertyMetadataOptions.AffectsMeasure);
    MarginProperty = DependencyProperty.Register("Margin", typeof(Thickness), typeof(FrameworkElement), metadata, new ValidateValueCallback(FrameworkElement.IsMarginValid));
    ……
}
           

DependencyProperty.Register()方法有三個重載,上面代碼是參數最多的一個,具體含義如下:

(1)屬性名(在該例中為Margin)

(2)屬性使用的資料類型(在該例中為Thickness結構)

(3)擁有該屬性的類(在該例中為FrameworkElement類)

(4)PropertyMetadata為依賴屬性設定附加功能

(5)一個用于驗證屬性的回調函數

三、封裝依賴屬性

使用傳統的.NET屬性封裝WPF依賴屬性。代碼如下:

public Thickness Margin
{
    get { return (Thickness)GetValue(MarginProperty); }
    set { SetValue(MarginProperty, value); }
}
           

四、共享依賴屬性

共享依賴屬性就是在不同的類之間共享同一個依賴屬性。例如,TextBlock.FontFamily屬性和Control.FontFamily屬性指向同一個靜态的依賴屬性。該屬性實際上是在TextElement類中定義的TextElement.FontFamilyProperty依賴屬性。TextElement類的靜态構造函數注冊該屬性,而TextBlock類的靜态構造函數隻是通過調用DependencyProperty.AddOwner()方法重用該屬性:

TextBlock.FontFamilyProperty = TextElement.FontFamilyProperty.AddOwner(typeof(TextBlock));
           

注意:在WPF中重用依賴屬性可得到一些奇異的效果,最有名的是樣式。例如,如果使用樣式自動設定TextBlock.FontFamily屬性,樣式也會影響Control.FontFamily屬性,因為在背景這兩個類使用同一個依賴屬性。

五、快速建立依賴屬性

使用代碼片段(code snippet),快捷鍵為:propdp+兩次Tab

繼續閱讀