如何建立自訂路由事件 (WPF .NET)
Windows Presentation Foundation (WPF) 應用程式開發人員和元件作者可以建立自訂路由事件,以擴充通用語言執行平台 (CLR) 事件的功能。 如需路由事件功能的相關資訊,請參閱為何使用路由事件。 本文涵蓋建立自訂路由事件的基本概念。
必要條件
本文假設您已基本了解路由事件,而且您已閱讀路由事件概觀。 若要遵循本文中的範例,建議您先熟悉 Extensible Application Markup Language (XAML),並了解如何撰寫 Windows Presentation Foundation (WPF) 應用程式。
路由事件步驟
建立路由事件的基本步驟如下:
使用 RegisterRoutedEvent 方法註冊 RoutedEvent。
註冊呼叫會傳回
RoutedEvent
實例,又稱為路由事件識別碼,其保存已註冊的事件名稱、路由策略和其他事件詳細資料。 將識別碼指派給靜態唯讀欄位。 按照慣例:定義 CLR 新增和移除事件存取子。 如果沒有 CLR 事件存取子,您就只能透過直接呼叫 UIElement.AddHandler 和 UIElement.RemoveHandler 方法來新增或移除事件處理常式。 使用 CLR 事件存取子時,您會取得下列事件處理常式指派機制:
- 對於 Extensible Application Markup Language (XAML),您可以使用屬性語法來新增事件處理常式。
- 對於 C#,您可以使用
+=
和-=
運算子來新增或移除事件處理常式。 - 對於 Visual Basic,您可以使用 AddHandler 和 RemoveHandler 語句來新增或移除事件處理常式。
新增自訂邏輯以觸發路由事件。 例如,您的邏輯可能會根據使用者輸入和應用程式狀態來觸發事件。
範例
下列範例會在自訂控制項程式庫中實作 CustomButton
類別。 CustomButton
類別衍生自 Button:
- 使用 RegisterRoutedEvent 方法註冊名為
ConditionalClick
的 RoutedEvent,並在註冊期間指定事件反昇策略。 - 將註冊呼叫所傳回的
RoutedEvent
實例指派給名為ConditionalClickEvent
的靜態唯讀欄位。 - 定義 CLR 新增和移除事件存取子。
- 新增自訂邏輯,以便在按一下
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
方法指派為 CustomButton
和 StackPanel1
元素的 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
時:
CustomButton
上會引發ConditionalClick
路由事件。- 觸發附加至
CustomButton
的Handler_ConditionalClick
事件處理常式。 ConditionalClick
路由事件會沿著元素樹狀結構向上周游至StackPanel1
。- 觸發附加至
StackPanel1
的Handler_ConditionalClick
事件處理常式。 ConditionalClick
路由事件繼續沿著元素樹狀結構向上周遊,可能會觸發附加至其他周遊元素的其他ConditionalClick
事件處理常式。
Handler_ConditionalClick
事件處理常式會取得其觸發事件的下列相關資訊:
- 傳送者物件,事件處理常式附加至此元素。 第一次執行處理常式時,
sender
為CustomButton
,第二次則為StackPanel1
。 - RoutedEventArgs.Source 物件,原本引發事件的元素。 在此範例中,
Source
一律為CustomButton
。
注意
路由事件與 CLR 事件之間的主要差異在於路由事件會周遊元素樹狀結構,尋找處理常式,而 CLR 事件不會周遊元素樹狀結構,且處理常式只能附加至引發事件的來源物件。 因此,路由事件 sender
可以是元素樹狀結構中的任何周遊元素。
除了在事件註冊呼叫中將路由策略設定為 Tunnel 之外,通道事件的建立方式同於事件反昇事件。 如需通道事件的詳細資訊,請參閱 WPF 輸入事件。