相依性屬性(Dependency Properties)
如果你要建立一個自訂控制項類,並為這個類定義新的屬性,如果你想給這些屬性設定Style,或者你想通過給那些屬性設定資料繫結(Binding),或者想對這些屬性使用動畫,那麼你需要將這些屬性設定成相依性屬性(Dependency Properties)。
下面我們先看一個簡單了例子,自訂一個類,繼承自Button,也就是我們自己做一個Button,並為之定義兩個屬性Color1和Color2,代碼如下
public class MyButton : Button { public MyButton() { } private Color _forceColor; public Color ForceColor { get { return _forceColor; } set { _forceColor = value; this.Foreground = new SolidColorBrush() { Color = _forceColor}; } } private Color _backColor; public Color BackColor { get { return _backColor; } set { _backColor = value; this.Background = new SolidColorBrush() { Color = _backColor }; } } }
上面定義一個Button,聲明兩個屬性Color1和Color2,為Color1屬性Set值時,同時將值賦給前景色彩Foreground,為Color2屬性Set值時,同時將值賦給背景色Background,
在MainPage中添當前項目的加命名空間xmlns:local="clr-namespace:DependencyProperties"
在頁面中添加一個MyButton,直接枚舉設定ForceColor和BackColor:
<local:MyButton BackColor="Red" ForceColor="Black" Content="MyButton1"></local:MyButton>
添加資源
<Color x:Key="MyForceColor">Red</Color>
<Color x:Key="MyBackColor">White</Color>
再在頁面中添加一個MyButton,設定ForceColor和BackColor值為上面定義的資源
<local:MyButton BackColor="{StaticResource MyBackColor}" ForceColor="{StaticResource MyForceColor}" Content="MyButton2"></local:MyButton>
現在運行一下程式,效果如下
上面是預料中的結果,現在我們用Style設定ForceColor和BackColor的值,定義資源
上面是我定義資源時,代碼編輯器中的效果,看到有錯誤提示,看看錯誤視窗
未將對象引用設定到對象的執行個體,這事怎麼回事呢,先不管他,
在頁面中添加一個MyButton,並使用上面定義的Style
<local:MyButton Style="{StaticResource MyStyle}" Content="MyButton3"></local:MyButton>
運行一下,看看
調試也是通不過,為什麼呢,這就是我之前說的,要想為自訂的屬性使用Style,那麼就必須將之設定為DependencyProperty
DependencyProperty的定義格式為
public static readonly DependencyProperty 變數名=
DependencyProperty.Register("屬性名稱",
typeof(屬性類型),
typeof(所屬類的類型),
new PropertyMetadata(預設值, 值變化時觸發的方法));
現在我們修改之前的代碼,將ForceColor和BackColor設定為DependencyProperty,修改後的MyButton類如下
public class MyButton : Button { public MyButton() { } public static readonly DependencyProperty ForceColorProperty = DependencyProperty.Register("ForceColor", typeof(Color), typeof(MyButton), new PropertyMetadata(Colors.Black, OnColorChanged)); public static readonly DependencyProperty BackColorProperty = DependencyProperty.Register("BackColor", typeof(Color), typeof(MyButton), new PropertyMetadata(Colors.White, OnColorChanged)); public Color ForceColor { set { SetValue(ForceColorProperty, value); } get { return (Color)GetValue(ForceColorProperty); } } public Color BackColor { set { SetValue(BackColorProperty, value); } get { return (Color)GetValue(BackColorProperty); } } static void OnColorChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) { var btn = obj as MyButton; if (args.Property == ForceColorProperty) { btn.Foreground = new SolidColorBrush() { Color = (Color)args.NewValue }; } if (args.Property == BackColorProperty) { btn.Background = new SolidColorBrush() { Color = (Color)args.NewValue }; } } }
現在看看之前定義的Style
已經不報錯了,現在運行程式,效果如下
現在我們知道DependencyProperty的重要性了吧
再給初學者說明點問題,明白人繞過
上面的例子中定義DependencyProperty是使用的是static和readonly,這就是我們不能直接用"="為其複製,而且是靜態變數,而非執行個體變數。所有MyButton公用的屬性,而且上面OnColorChanged也是static,全是靜態,那麼我們猜想,在設定他們的值是,那不就是改變了所有MyButton的屬性了嗎,那可絕對不是我們想要的結果,那麼們看一看,是不是事情是不是我們想的那樣糟糕
再次添加一個Style,並添加一個MyButton,使用次Style
<Style x:Key="MyStyle2" TargetType="local:MyButton">
<Setter Property="BackColor" Value="Yellow"></Setter>
<Setter Property="ForceColor" Value="Black"></Setter>
</Style>
<local:MyButton Style="{StaticResource MyStyle2}" Content="MyButton4"></local:MyButton>
運行一下,看看效果
這不是我們猜想的壞的結果,而是一個令人激動地,滿意的結果,為什麼會這樣,關鍵就在OnColorChanged參數和方法體上,耐心點,再看看完整的OnColorChanged
static void OnColorChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) { var btn = obj as MyButton; if (args.Property == ForceColorProperty) { btn.Foreground = new SolidColorBrush() { Color = (Color)args.NewValue }; } if (args.Property == BackColorProperty) { btn.Background = new SolidColorBrush() { Color = (Color)args.NewValue }; } }
我們看到,有兩個參數,第一個參數就是當前,使用屬性的執行個體對象MyButton,第二個參數是但前設定的值
我們將之擷取,然和設定相應的屬性,就可以了,這樣雖然是靜態變數,也不會不會影響到其他的執行個體。
在看看Button的Foreground屬性,官方定義的是public Brush Foreground { get; set; },所以他是一個執行個體屬性,而非靜態屬性,所以你想用MyButton.Foreground是通不過的,如果你想講自己頂一個屬性用到基礎屬性上,根本不會出錯。
如果你本來就沒有上面的錯誤猜測,就當我說了一個笑話吧