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

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

重要

.NET 7 和 .NET 6 的桌面指南檔正在建置中。

必要條件

本文假設您已瞭解路由事件,而且您已閱讀 路由事件概觀 。 若要遵循本文中的範例,如果您熟悉可延伸的應用程式標記語言(XAML),並知道如何撰寫 Windows Presentation Foundation (WPF) 應用程式,它很有説明。

路由事件步驟

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

  1. RoutedEvent使用 RegisterRoutedEvent 方法註冊 。

  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#,您可以使用 +=-= 運算子來新增或移除事件處理常式。
    • 針對 VB,您可以使用 AddHandler 和 RemoveHandler 語句來新增或移除事件處理常式。
  4. 新增自訂邏輯以觸發路由事件。 例如,您的邏輯可能會根據使用者輸入和應用程式狀態觸發事件。

範例

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

  1. RoutedEvent使用 RegisterRoutedEvent 方法註冊名為 ConditionalClick 的 ,並在註冊期間指定 反升 策略。
  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 標記將 實例 CustomButton 加入 至 StackPanel 的個別 WPF 應用程式,以及將 方法指派 Handler_ConditionalClickConditionalClickStackPanel1 專案的事件處理常式 CustomButton

<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. 路由 ConditionalClick 事件會在 上 CustomButton 引發。
  2. 附加至 CustomButtonHandler_ConditionalClick 事件處理常式會觸發。
  3. 路由 ConditionalClick 事件會將專案樹狀結構周遊至 StackPanel1
  4. 附加至 StackPanel1Handler_ConditionalClick 事件處理常式會觸發。
  5. 路由事件會 ConditionalClick 繼續向上移動,元素樹狀結構可能會觸發附加至其他周遊元素的其他 ConditionalClick 事件處理常式。

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

  • sender 物件,這是事件處理常式所附加的專案。 將是 senderCustomButton 處理常式第一次執行,第 StackPanel1 二次。
  • 物件 RoutedEventArgs.Source ,這是原本引發事件的專案。 在此範例中,一 SourceCustomButton 為 。

注意

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

您可以建立通道事件的方式與反升事件相同,不同之處在于您會在事件註冊呼叫 Tunnel 中設定路由策略。 如需通道事件的詳細資訊,請參閱 WPF 輸入事件

另請參閱