添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
public class CustomClass public static readonly DependencyProperty CustomProperty = DependencyProperty.RegisterAttached( "Custom", typeof(double), typeof(CustomClass), new PropertyMetadata()); [AttachedPropertyBrowsableForType(typeof(Control))] public static double GetCustom(DependencyObject obj) => (double)obj.GetValue(CustomProperty); public static void SetCustom(DependencyObject obj, double value) => obj.SetValue(CustomProperty, value);

可以看到與相依屬性非常像,附加屬性透過DependencyProperty.RegisterAttached方法來註冊,傳入的參數也一模一樣:

  1. “Custom":附加屬性的名稱
  2. typeof(double):附加屬性的類型
  3. typeof(CustomAttachedProperty):擁有附加屬性的類別
  4. new PropertyMetadata():附加屬性的其它設定,與

與相依屬性最大的不同在於:相依屬性必須要定義在擁有它的類別中,而附加屬性由於是要附加到其他控件上的,所以要額外定義一個類別來裝載附加屬性,就像上面我們用CustomClass來裝載Custom這個附加屬性。

RegisterAttached註冊完附加屬性後,同樣會回傳一個DependencyProperty屬性,這個屬性同樣有 命名規範 ,同樣是 屬性名稱+Property

與相依屬性不同的是:由於附加屬性不是定義在控件類別中,因此若要對附加屬性取值或賦值,就要透過靜態方法GetCustom, SetCustom來操作。而這兩個靜態方法同樣有 命名規範 ,必須是 Get+屬性名稱 / Set + 數性名稱 。這些名稱都必須完全相符,在XAML中才能正確執行附加屬性。

此外在GetCustom上面有一個AttachedPropertyBrowsableForType的修飾詞,可以用來指定甚麼類型的控件才可以使用這個附加屬性。

附加屬性實戰演練

雖然現在已經了解附加屬性要怎麼定義了,但是附加屬性實際上要怎麼使用呢?接下來讓我們實作一個附加屬性來看看吧。假如我們現在想要判斷TextBox中使用者有沒有輸入文字,然而預設的TextBox是沒有HasText這個屬性讓我們判斷的,這個時候就是使用附加屬性的好時機,我們可以為TextBox實作一個HasText的附加屬性來幫助我們判斷。

1. 實作TextBoxServices類別

首先,我們要先建立一個類別來定義HasText附加屬性,這裡我們把當稱之為
HasText Services。

namespace WpfAttachedProperty public class HasTextServices public class HasTextServices public static readonly DependencyProperty IsEnabledProperty = DependencyProperty.RegisterAttached( "IsEnabled", typeof(bool), typeof(HasTextServices), new PropertyMetadata(default(bool))); [AttachedPropertyBrowsableForType(typeof(TextBox))] public static bool GetIsEnabled(DependencyObject obj) => (bool)obj.GetValue(IsEnabledProperty); public static void SetIsEnabled(DependencyObject obj, bool value) => obj.SetValue(IsEnabledProperty, value); public static readonly DependencyProperty HasTextProperty = DependencyProperty.RegisterAttached( "HasText", typeof(bool), typeof(HasTextServices), new PropertyMetadata(default(bool))); [AttachedPropertyBrowsableForType(typeof(TextBox))] public static bool GetHasText(DependencyObject obj) => (bool)obj.GetValue(HasTextProperty); public static void SetHasText(DependencyObject obj, bool value) => obj.SetValue(HasTextProperty, value);

3. 定義OnIsEnabledChanged

定義好附加屬性後,接下來就要讓附加屬性可以正常運作,實現我們想要的功能。實現的方法通常是透過附加屬性改變的回呼(OnPropertyChanged)來達成,在這個回呼裡面註冊事件,由事件驅動的方式來執行我們想要的命令。

具體來說,當某個TextBox控件的IsEnabled附加屬性被使用者設定成true時,我們就要註冊這個TextBox的TextChanged事件。

public class HasTextServices public static readonly DependencyProperty IsEnabledProperty = DependencyProperty.RegisterAttached( "IsEnabled", typeof(bool), typeof(HasTextServices), new PropertyMetadata(default(bool), OnIsEnabledChanged)); private static void OnIsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) var tb = d as TextBox; if ((bool)e.NewValue) tb.TextChanged += Tb_TextChanged; tb.TextChanged -= Tb_TextChanged; private static void Tb_TextChanged(object sender, TextChangedEventArgs e)

在上面的代碼中,我們透過PropertyMetadata定義IsEnabledProperty的屬性改變回呼OnIsEnabledChanged。裡面先把傳入的相依物件d轉型成TextBox(因為我們確定這個附加屬性一定只有TextBox才可以使用),在透過事件參數e.NewValue判斷IsEnabled屬性是否為true,若是,則註冊Tb_TextChanged方法給TextBox.TextChanged事件;若否,則取消註冊。

4. 定義Tb_TextChanged

接下來每當TextChanged時,我們就要判斷現在TextBox.Text是否為空,並把結果設定給HasText附加屬性。注意到要設定控件的附加屬性必須要透過當初定義的Set方法來設定。

private static void Tb_TextChanged(object sender, TextChangedEventArgs e) var tb = sender as TextBox; SetHasText(tb, !string.IsNullOrEmpty(tb.Text));

這樣就大功告成啦!我們可以用下面的代碼來測試一下:

<!--MainWindow.cs--> <Window x:Class="WpfDataBinding.MainWindow" xmlns="http://schemas.microsoft.com/netfx/2009/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ap="clr-namespace:WpfAttachedProperty" Height="300" Width="300"> <StackPanel> <TextBox Name="textBox" ap:HasTextServices.IsEnabled="True" /> <Label Content="{Binding ElementName=textBox, Path=(ap:HasTextServices.HasText)}" /> </StackPanel> </Window>

注意到我們把附加屬性定義在WpfAttachedProperty這個命名空間,因此需要透過xmlns把命名空間引用進來,並稱作ap。之後在設定TextBox.(ap:HasTextServices.IsEnabled)附加屬性為true,並讓Label控件的內容綁定到TextBox的HasText附加屬性,這樣就可以將HasText即時顯示出來。特別注意到綁定的Path,如果要綁定到附加屬性,必須使用 () 把附加屬性包起來。

執行之後,試著在TextBox中輸入一些文字,然後觀察一下Label的改變吧!

附加屬性是WPF提供的非常強大的功能,它的妙用遠遠不只本文中示範的如此而已。熟悉使用附加屬性可以大量簡化XAML與C#的代碼,並且由於附加屬性隨貼隨用的特性,寫出來的代碼泛用性高,可以大幅度的提高代碼的質量。趕快趁現在好好練習自己寫出一個好用的附加屬性吧。