附加事件概觀

Extensible Application Markup Language (XAML) 定義稱為 附加事件 的語言元件和事件種類。 附加事件的概念,讓您能新增特定事件的處理常式到任意項目,而不是實際定義或繼承事件的項目。 在此情況下,可能引發事件的物件和目的地處理執行個體都不會定義或以其他方式「擁有」事件。

必要條件

本主題假設您已在 WPF 中讀取 路由事件概觀 XAML。

附加事件語法

附加事件具有 XAML 語法和程式碼撰寫模式,必須由支援程式碼使用,才能支援附加的事件使用方式。

在 XAML 語法中,附加事件不只是由事件名稱指定,而是由其擁有類型加上事件名稱,並以點 (.) 分隔。 因為事件名稱以其擁有類型的名稱來限定,附加事件語法可讓任何附加事件附加至可以具現化的任何項目。

例如,以下是附加自訂 NeedsCleaning 附加事件的處理常式的 XAML 語法:

<aqua:Aquarium Name="theAquarium" Height="600" Width="800" aqua:AquariumFilter.NeedsCleaning="WashMe"/>

請注意 aqua: 前置詞,前置詞在此情況中是必要的,因為附加事件是來自自訂對應 xmlns 的自訂事件。

WPF 如何實作附加事件

在 WPF 中,附加事件是由 RoutedEvent 欄位所支援,並在引發後透過樹狀結構路由傳送。 一般而言,附加事件的來源 (引發事件的物件) 是系統或服務來源,因此執行引發事件之程式碼的物件不直接是項目樹狀結構的一部分。

附加事件的情節

在 WPF 中,附加事件會出現在特定功能區域中,其中具有服務層級抽象概念,例如靜態 Mouse 類別或 Validation 類別所啟用的事件。 與服務互動或是使用服務的類別可以以附加事件語法使用事件,或者它們可以選擇將附加事件公開為路由事件,路由事件是類別整合服務功能的方式之一。

雖然 WPF 會定義一些附加事件,但您將直接使用或處理附加事件的案例非常有限。 一般而言,附加事件會提供架構用途,但接著會轉送至未附加的事件(使用 CLR 事件「包裝函式」支援)路由事件。

例如,基礎附加事件 Mouse.MouseDown 可以更輕鬆地在任何指定的 UIElementMouseDown 上使用 , UIElement 而不是在 XAML 或程式碼中處理附加事件語法。 附加事件在架構中有其用途,因為它可讓您在未來擴充輸入裝置。 假設裝置只需要引發 Mouse.MouseDown 以模擬滑鼠輸入,而且不需要衍生自 Mouse 來執行此動作。 不過,此案例牽涉到事件的程式碼處理,而附加事件的 XAML 處理與此案例無關。

在 WPF 中處理附加事件

處理附加事件的程序,以及您將撰寫的處理常式程式碼,基本上與路由事件一樣。

一般而言,WPF 附加事件與 WPF 路由事件並不大不相同。 差異在於事件的來源方式,以及類別如何將其公開為成員(這也會影響 XAML 處理常式語法)。

不過,如先前所述,現有的 WPF 附加事件並非特別適用于在 WPF 中處理。 更常見的是,事件的目的是要在複合 (compositing) 中啟用報告狀態給父項目的複合項目,在此情況下,事件通常會在程式碼中引發,並依賴相關父類別中的類別處理。 例如,內 Selector 的專案預期會引發附加 Selected 事件,然後由 類別處理 Selector ,然後由 類別轉換成 Selector 不同的路由事件。 SelectionChanged 如需路由事件與類別處理的詳細資訊,請參閱將路由事件標記為已處理以及類別處理

將您自己的附加事件定義為路由事件

如果您要衍生自一般 WPF 基類,您可以藉由在類別中包含特定模式方法,以及使用基類上已經存在的公用程式方法,來實作自己的附加事件。

模式如下所示︰

  • 方法 :使用兩個參數新增 EventName 處理常式 。 第一個參數是加入事件處理常式的實例。 第二個參數是要加入的事件處理常式。 方法必須是 publicstatic ,且沒有傳回值。

  • 使用兩個參數移除 EventName 處理常式 的方法 。 第一個參數是事件處理常式從中移除的實例。 第二個參數是要移除的事件處理常式。 方法必須是 publicstatic ,且沒有傳回值。

Add EventName Handler 存取子方法有助於在專案上宣告附加事件處理常式屬性時進行 XAML 處理。 Add EventName Handler Remove EventName Handler 方法也會啟用附加事件的事件處理常式存放區程式碼存取。

這個一般模式還不足以在架構中實際實作,因為任何給定的 XAML 讀取器實作可能有不同的配置,可在支援的語言和架構中識別基礎事件。 這是 WPF 實作附加事件做為路由事件的原因之一;要用於事件 ( RoutedEvent ) 的識別碼已經由 WPF 事件系統定義。 此外,路由事件是附加事件的 XAML 語言層級概念的自然實作延伸。

WPF 附加事件的 Add EventName Handler 實作包含使用 AddHandler 路由事件和處理常式作為引數呼叫 。

此實作策略和路由事件系統一般會將附加事件的處理限制為 UIElement 衍生類別或 ContentElement 衍生類別,因為只有這些類別具有 AddHandler 實作。

例如,下列程式碼會 NeedsCleaning 使用 WPF 附加事件策略,在擁有者類別 Aquarium 上定義附加事件,將附加事件宣告為路由事件。

public static readonly RoutedEvent NeedsCleaningEvent = EventManager.RegisterRoutedEvent("NeedsCleaning", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(AquariumFilter));
public static void AddNeedsCleaningHandler(DependencyObject d, RoutedEventHandler handler)
{
    UIElement uie = d as UIElement;
    if (uie != null)
    {
        uie.AddHandler(AquariumFilter.NeedsCleaningEvent, handler);
    }
}
public static void RemoveNeedsCleaningHandler(DependencyObject d, RoutedEventHandler handler)
{
    UIElement uie = d as UIElement;
    if (uie != null)
    {
        uie.RemoveHandler(AquariumFilter.NeedsCleaningEvent, handler);
    }
}
Public Shared ReadOnly NeedsCleaningEvent As RoutedEvent = EventManager.RegisterRoutedEvent("NeedsCleaning", RoutingStrategy.Bubble, GetType(RoutedEventHandler), GetType(AquariumFilter))
Public Shared Sub AddNeedsCleaningHandler(ByVal d As DependencyObject, ByVal handler As RoutedEventHandler)
    Dim uie As UIElement = TryCast(d, UIElement)
    If uie IsNot Nothing Then
        uie.AddHandler(AquariumFilter.NeedsCleaningEvent, handler)
    End If
End Sub
Public Shared Sub RemoveNeedsCleaningHandler(ByVal d As DependencyObject, ByVal handler As RoutedEventHandler)
    Dim uie As UIElement = TryCast(d, UIElement)
    If uie IsNot Nothing Then
        uie.RemoveHandler(AquariumFilter.NeedsCleaningEvent, handler)
    End If
End Sub

請注意,用來建立附加事件識別碼欄位 RegisterRoutedEvent 的方法,實際上是用來註冊非附加路由事件的方法。 附加事件和路由事件全都註冊到集中式內部存放區。 此事件存放區實作促成了路由事件概觀中所討論的「事件即介面」概念考量。

引發 WPF 附加事件

您通常不需要從程式碼引發現有的 WPF 定義附加事件。 這些事件遵循一般「服務」概念模型,以及這類 InputManager 服務類別負責引發事件。

不過,如果您要根據 上的附加事件的 WPF 模型定義自訂附加事件 RoutedEvent ,您可以使用 RaiseEvent 來從任何 UIElementContentElement 引發附加事件。 引發路由事件(附加或不附加)需要您將專案樹狀結構中的特定專案宣告為事件來源;該來源會回報為 RaiseEvent 呼叫端。 判斷樹狀結構中的哪個項目報告為來源是服務的責任

另請參閱