天天看點

WPF控件開發之自定義控件(2)

屬性的中繼資料。中繼資料包含該屬性的預設值、CoerceValueCallback 和 PropertyChangedCallback。

通過實作該屬性的 get 和 set 通路器,定義一個名為 Value 的 CLR“包裝”屬性,這個名稱也就是用來注冊該依賴項屬性的名稱。請注意,get 和 set 通路器隻是分别調用 GetValue 和 SetValue。建議依賴項屬性的通路器不要包含其他邏輯,這是因為用戶端和 WPF 可繞過這兩個通路器直接調用 GetValue 和 SetValue。例如,如果屬性綁定到資料源,則不會調用該屬性的 set 通路器。不要向 get 和 set 通路器添加其他邏輯,而應使用 ValidateValueCallback、CoerceValueCallback 和 PropertyChangedCallback 委托在值更改時進行響應或檢查該值。

為 CoerceValueCallback 定義一個名為 CoerceValue 的方法。CoerceValue 確定 Value 大于或等于 MinValue 且小于或等于 MaxValue。

為 PropertyChangedCallback 定義一個名為 OnValueChanged 的方法。OnValueChanged 建立一個 RoutedPropertyChangedEventArgs<(Of <(T>)>) 對象,并準備引發 ValueChanged 路由事件。路由事件在下一節中讨論。

使用 RoutedEvent

就像依賴項屬性以附加功能擴充 CLR 屬性的用途一樣,路由事件擴充了标準 CLR 事件的用途。在建立新的 WPF 控件時,将事件實作為路由事件也是一種好方法,這是因為路由事件支援以下行為:

事件可以在多個控件的父級上進行處理。如果事件是冒泡事件,則元素樹中的單個父級可預訂該事件。然後,應用程式作者可以使用一個處理程式來響應多個控件的該事件。例如,如果控件屬于 ListBox 中的每個項(因為它包含在 DataTemplate 中),則應用程式開發人員可以為該控件的 ListBox 事件定義相應的事件處理程式。每當這些控件中的任何控件發生該事件時,都會調用該事件處理程式。

路由事件可在 EventSetter 中使用,應用程式開發人員通過 EventSetter 可以在樣式内指定事件的處理程式。

路由事件可在 EventTrigger 中使用,這對于使用 XAML 對屬性進行動畫處理很有用。

下面的示例定義了一個路由事件。

WPF控件開發之自定義控件(2)

這段代碼執行下面的操作:

将一個名為 ValueChangedEvent 的 RoutedEvent 辨別符定義為 publicstaticreadonly 字段。

通過調用 EventManager..::.RegisterRoutedEvent 方法注冊路由事件。該示例在調用 RegisterRoutedEvent 時指定以下資訊:

事件的名稱為 ValueChanged。

路由政策為 Bubble,這意味着首先調用源(引發事件的對象)上的事件處理程式,然後從最近的父元素上的事件處理程式開始,相繼調用源的各個父元素上的事件處理程式。

該事件處理程式的類型為 RoutedPropertyChangedEventHandler<(Of <(T>)>),是用 Decimal 類型構造的。

該事件的所屬類型為 NumericUpDown。

聲明一個名為 ValueChanged 的公共事件,并包含事件通路器聲明。該示例調用 add 通路器聲明中的 AddHandler 和 remove 通路器聲明中的 RemoveHandler 來使用 WPF 事件服務。

建立一個名為 OnValueChanged 的受保護的虛方法,該方法引發 ValueChanged 事件。

使用綁定

若要将控件 UI 與其邏輯分離,請考慮使用資料綁定。如果是使用 ControlTemplate 定義控件的外觀,這一點尤其重要。使用資料綁定時,可能能夠避免引用 UI 的特定部分。

下面的示例更新 NumericUpDown 控件的 TextBlock,向它配置設定一個名稱,然後在代碼中按名稱引用該文本框。

WPF控件開發之自定義控件(2)
WPF控件開發之自定義控件(2)

下面的示例使用綁定來達到相同的目的。

WPF控件開發之自定義控件(2)

針對設計器設計

若要在 Visual Studio Windows Presentation Foundation (WPF) 設計器中獲得對自定義 WPF 控件的支援(例如,使用“屬性”視窗編輯屬性),請遵循以下準則。

依賴項屬性

確定實作 CLRget 通路器和 set 通路器,如前面“使用依賴項屬性”中所述。設計器可以使用包裝來檢測某個依賴項屬性是否存在,但與 WPF 和控件用戶端一樣,在擷取或設定屬性時不需要使用設計器來調用通路器。

附加屬性

應按照以下原則在自定義控件上實作附加屬性:

具有一個使用 RegisterAttached 方法建立的 publicstaticreadonlyDependencyProperty,其形式為“屬性名稱Property”。傳遞到 RegisterAttached 的屬性名稱必須與屬性名稱 比對。

實作一對名為 Set屬性名稱 和 Get屬性名稱 的 public static CLR 方法。這兩種方法都應接受從 DependencyProperty 派生的類作為其第一個參數。Set屬性名稱 方法還接受其類型與屬性的注冊資料類型比對的參數。Get屬性名稱 方法應傳回相同類型的值。如果缺少 Set屬性名稱 方法,則該屬性标記為隻讀。

Set 屬性名稱 和 Get屬性名稱 必須分别直接路由到目标依賴項對象的 GetValue 和 SetValue 方法。通過調用方法包裝或直接調用目标依賴項對象,設計器可以通路附加屬性。