共用方式為


附加事件概觀

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 可以更輕鬆地在該 UIElement 上使用 MouseDown 來處理任何指定的 UIElement,而不是在 XAML 或程式碼中處理附加事件語法。 附加事件在架構中有其用途,因為它可讓您在未來擴充輸入裝置。 假定的輸入裝置只需要引發 Mouse.MouseDown 即可模擬滑鼠輸入,而無需從 Mouse 衍生即可執行此動作。 不過,此情節牽涉到事件的程式碼處理,附加事件的 XAML 處理與此情節無關。

在 WPF 中處理附加事件

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

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

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

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

如果您衍生自一般 WPF 基底類別,您可以在類別中加入特定模式方法,並使用已在基底類別的公用程式方法,來實作自己的附加事件。

模式如下所示︰

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

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

附加事件處理常式屬性宣告於項目上時,新增 EventName 常式存取子方法可協助 XAML 處理。 新增 EventName 常式移除 EventName 常式方法也可讓程式碼存取附加事件的事件處理常式存放區。

這種一般模式還不夠精確,無法實際實作在架構中,因為任何指定的 XAML 讀取器實作都可能會有不同的方式來識別支援語言與架構中的基礎事件。 這是 WPF 將附加事件實作為路由事件的其中一個原因;WPF 事件系統已經定義了要用於事件的識別項 (RoutedEvent)。 此外,路由事件是 XAML 語言層級的附加事件概念的自然實作延伸模組。

WPF 附加事件的新增 EventName 常式實作包括呼叫 AddHandler 並以路由事件和處理常式作為引數。

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

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

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 的服務類別會負責引發事件。

然而,使用以RoutedEvent為基礎之附加事件的 WPF 模型來定義自訂附加事件時,可以使用 RaiseEvent 方法在任何 UIElementContentElement 上引發附加事件。 引發路由事件 (不論是否附加) 需要您將項目樹狀結構中的特定項目宣告為事件來源,該來源會報告為 RaiseEvent 呼叫端。 判斷樹狀結構中的哪個項目報告為來源是服務的責任

另請參閱