共用方式為


如何建立自訂路由事件 (WPF .NET)

Windows Presentation Foundation (WPF) 應用程式開發人員和元件作者可以建立自訂路由事件,以擴充通用語言執行平台 (CLR) 事件的功能。 如需路由事件功能的相關資訊,請參閱為何使用路由事件。 本文涵蓋建立自訂路由事件的基本概念。

必要條件

本文假設您已基本了解路由事件,而且您已閱讀路由事件概觀。 若要遵循本文中的範例,建議您先熟悉 Extensible Application Markup Language (XAML),並了解如何撰寫 Windows Presentation Foundation (WPF) 應用程式。

路由事件步驟

建立路由事件的基本步驟如下:

  1. 使用 RegisterRoutedEvent 方法註冊 RoutedEvent

  2. 註冊呼叫會傳回 RoutedEvent 實例,又稱為路由事件識別碼,其保存已註冊的事件名稱、路由策略和其他事件詳細資料。 將識別碼指派給靜態唯讀欄位。 按照慣例:

    • 具有事件反昇策略之路由事件的識別碼名為 <event name>Event。 例如,如果事件名稱是 Tap,則識別碼應該命名為 TapEvent
    • 具有通道策略之路由事件的識別碼名為 Preview<event name>Event。 例如,如果事件名稱是 Tap,則識別碼應該命名為 PreviewTapEvent
  3. 定義 CLR 新增移除事件存取子。 如果沒有 CLR 事件存取子,您就只能透過直接呼叫 UIElement.AddHandlerUIElement.RemoveHandler 方法來新增或移除事件處理常式。 使用 CLR 事件存取子時,您會取得下列事件處理常式指派機制:

    • 對於 Extensible Application Markup Language (XAML),您可以使用屬性語法來新增事件處理常式。
    • 對於 C#,您可以使用 +=-= 運算子來新增或移除事件處理常式。
    • 對於 Visual Basic,您可以使用 AddHandlerRemoveHandler 語句來新增或移除事件處理常式。
  4. 新增自訂邏輯以觸發路由事件。 例如,您的邏輯可能會根據使用者輸入和應用程式狀態來觸發事件。

範例

下列範例會在自訂控制項程式庫中實作 CustomButton 類別。 CustomButton 類別衍生自 Button

  1. 使用 RegisterRoutedEvent 方法註冊名為 ConditionalClickRoutedEvent,並在註冊期間指定事件反昇策略。
  2. 將註冊呼叫所傳回的 RoutedEvent 實例指派給名為 ConditionalClickEvent 的靜態唯讀欄位。
  3. 定義 CLR 新增移除事件存取子。
  4. 新增自訂邏輯,以便在按一下 CustomButton 且外部條件適用時,引發自訂路由事件。 雖然範例程式碼會從覆寫的 OnClick 虛擬方法內引發 ConditionalClick 路由事件,但您可以用自選的任何方式來引發事件。
public class CustomButton : Button
{
    // Register a custom routed event using the Bubble routing strategy.
    public static readonly RoutedEvent ConditionalClickEvent = EventManager.RegisterRoutedEvent(
        name: "ConditionalClick",
        routingStrategy: RoutingStrategy.Bubble,
        handlerType: typeof(RoutedEventHandler),
        ownerType: typeof(CustomButton));

    // Provide CLR accessors for assigning an event handler.
    public event RoutedEventHandler ConditionalClick
    {
        add { AddHandler(ConditionalClickEvent, value); }
        remove { RemoveHandler(ConditionalClickEvent, value); }
    }

    void RaiseCustomRoutedEvent()
    {
        // Create a RoutedEventArgs instance.
        RoutedEventArgs routedEventArgs = new(routedEvent: ConditionalClickEvent);

        // Raise the event, which will bubble up through the element tree.
        RaiseEvent(routedEventArgs);
    }

    // For demo purposes, we use the Click event as a trigger.
    protected override void OnClick()
    {
        // Some condition combined with the Click event will trigger the ConditionalClick event.
        if (DateTime.Now > new DateTime())
            RaiseCustomRoutedEvent();

        // Call the base class OnClick() method so Click event subscribers are notified.
        base.OnClick();
    }
}
Public Class CustomButton
    Inherits Button

    ' Register a custom routed event with the Bubble routing strategy.
    Public Shared ReadOnly ConditionalClickEvent As RoutedEvent = EventManager.RegisterRoutedEvent(
        name:="ConditionalClick",
        routingStrategy:=RoutingStrategy.Bubble,
        handlerType:=GetType(RoutedEventHandler),
        ownerType:=GetType(CustomButton))

    ' Provide CLR accessors to support event handler assignment.
    Public Custom Event ConditionalClick As RoutedEventHandler

        AddHandler(value As RoutedEventHandler)
            [AddHandler](ConditionalClickEvent, value)
        End AddHandler

        RemoveHandler(value As RoutedEventHandler)
            [RemoveHandler](ConditionalClickEvent, value)
        End RemoveHandler

        RaiseEvent(sender As Object, e As RoutedEventArgs)
            [RaiseEvent](e)
        End RaiseEvent

    End Event

    Private Sub RaiseCustomRoutedEvent()

        ' Create a RoutedEventArgs instance.
        Dim routedEventArgs As New RoutedEventArgs(routedEvent:=ConditionalClickEvent)

        ' Raise the event, which will bubble up through the element tree.
        [RaiseEvent](routedEventArgs)

    End Sub

    ' For demo purposes, we use the Click event as a trigger.
    Protected Overrides Sub OnClick()

        ' Some condition combined with the Click event will trigger the ConditionalClick event.
        If Date.Now > New DateTime() Then RaiseCustomRoutedEvent()

        ' Call the base class OnClick() method so Click event subscribers are notified.
        MyBase.OnClick()

    End Sub
End Class

此範例包含使用 XAML 標記的個別 WPF 應用程式,以將 CustomButton 的實例新增至 StackPanel,並將 Handler_ConditionalClick 方法指派為 CustomButtonStackPanel1 元素的 ConditionalClick 事件處理常式。

<Window x:Class="CodeSample.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:custom="clr-namespace:WpfControl;assembly=WpfControlLibrary"
        Title="How to create a custom routed event" Height="100" Width="300">

    <StackPanel Name="StackPanel1" custom:CustomButton.ConditionalClick="Handler_ConditionalClick">
        <custom:CustomButton
            Name="customButton"
            ConditionalClick="Handler_ConditionalClick"
            Content="Click to trigger a custom routed event"
            Background="LightGray">
        </custom:CustomButton>
    </StackPanel>
</Window>

在程式碼後置中,WPF 應用程式會定義 Handler_ConditionalClick 事件處理常式方法。 事件處理常式方法只能在程式碼後置中實作。

// The ConditionalClick event handler.
private void Handler_ConditionalClick(object sender, RoutedEventArgs e)
{
    string senderName = ((FrameworkElement)sender).Name;
    string sourceName = ((FrameworkElement)e.Source).Name;

    Debug.WriteLine($"Routed event handler attached to {senderName}, " +
        $"triggered by the ConditionalClick routed event raised on {sourceName}.");
}

// Debug output when CustomButton is clicked:
// Routed event handler attached to CustomButton,
//     triggered by the ConditionalClick routed event raised on CustomButton.
// Routed event handler attached to StackPanel1,
//     triggered by the ConditionalClick routed event raised on CustomButton.
' The ConditionalClick event handler.
Private Sub Handler_ConditionalClick(sender As Object, e As RoutedEventArgs)

    Dim sourceName As String = CType(e.Source, FrameworkElement).Name
    Dim senderName As String = CType(sender, FrameworkElement).Name

    Debug.WriteLine($"Routed event handler attached to {senderName}, " +
        $"triggered by the ConditionalClick routed event raised on {sourceName}.")

End Sub

' Debug output when CustomButton is clicked:
' Routed event handler attached to CustomButton,
'     triggered by the ConditionalClick routed event raised on CustomButton.
' Routed event handler attached to StackPanel1,
'     triggered by the ConditionalClick routed event raised on CustomButton.

按一下 CustomButton 時:

  1. CustomButton 上會引發 ConditionalClick 路由事件。
  2. 觸發附加至 CustomButtonHandler_ConditionalClick 事件處理常式。
  3. ConditionalClick 路由事件會沿著元素樹狀結構向上周游至 StackPanel1
  4. 觸發附加至 StackPanel1Handler_ConditionalClick 事件處理常式。
  5. ConditionalClick 路由事件繼續沿著元素樹狀結構向上周遊,可能會觸發附加至其他周遊元素的其他 ConditionalClick 事件處理常式。

Handler_ConditionalClick 事件處理常式會取得其觸發事件的下列相關資訊:

  • 傳送者物件,事件處理常式附加至此元素。 第一次執行處理常式時,senderCustomButton,第二次則為 StackPanel1
  • RoutedEventArgs.Source 物件,原本引發事件的元素。 在此範例中,Source 一律為 CustomButton

注意

路由事件與 CLR 事件之間的主要差異在於路由事件會周遊元素樹狀結構,尋找處理常式,而 CLR 事件不會周遊元素樹狀結構,且處理常式只能附加至引發事件的來源物件。 因此,路由事件 sender 可以是元素樹狀結構中的任何周遊元素。

除了在事件註冊呼叫中將路由策略設定為 Tunnel 之外,通道事件的建立方式同於事件反昇事件。 如需通道事件的詳細資訊,請參閱 WPF 輸入事件

另請參閱