カスタム ルーティング イベントを作成する方法 (WPF .NET)
Windows Presentation Foundation (WPF) のアプリケーション開発者とコンポーネント作成者は、カスタム ルーティング イベントを作成して、共通言語ランタイム (CLR) イベントの機能を拡張することができます。 ルーティング イベント機能の詳細については、「ルーティング イベントを使用する理由」を参照してください。 この記事では、カスタム ルーティング イベント作成の基本について説明します。
前提条件
この記事では、ルーティング イベントの基本的な知識があり、「ルーティング イベントの概要」をお読みになったことを前提としています。 この記事の例について理解するには、Extensible Application Markup Language (XAML) を使い慣れていて、Windows Presentation Foundation (WPF) アプリケーションの記述方法を理解していると役に立ちます。
ルーティング イベントの手順
ルーティング イベントを作成する基本的な手順は次のとおりです。
RegisterRoutedEvent メソッドを使用して RoutedEvent を登録します。
登録呼び出しは、登録されたイベント名、ルーティング戦略、およびその他のイベントの詳細を保持し、ルーティング イベント識別子と呼ばれる
RoutedEvent
インスタンスを返します。 識別子を静的な読み取り専用フィールドに割り当てます。 次のように慣例に従います。CLR の add と remove のイベント アクセサーを定義します。 CLR イベント アクセサーを使用しない場合、イベント ハンドラーを追加または削除するには、UIElement.AddHandler メソッドと UIElement.RemoveHandler メソッドへの直接呼び出しを使用する必要があります。 CLR イベント アクセサーを使用すると、次のイベント ハンドラーの割り当てメカニズムを取得できます。
- Extensible Application Markup Language (XAML) の場合、属性構文を使用してイベント ハンドラーを追加できます。
- C# の場合、
+=
演算子と-=
演算子を使用してイベント ハンドラーを追加または削除できます。 - VB の場合、AddHandler ステートメントと RemoveHandler ステートメントを使用してイベント ハンドラーを追加または削除できます。
ルーティング イベントをトリガーするためのカスタム ロジックを追加します。 たとえば、ロジックによって、ユーザー入力とアプリケーションの状態に基づいてイベントをトリガーできます。
例
次の例では、カスタム コントロール ライブラリに CustomButton
クラスを実装します。 Button から派生した CustomButton
クラスで、次の処理を実行します。
- RegisterRoutedEvent メソッドを使用して
ConditionalClick
という名前の RoutedEvent を登録し、登録時にバブル戦略を指定します。 - 登録呼び出しから返された
RoutedEvent
インスタンスを、ConditionalClickEvent
という名前の静的な読み取り専用フィールドに割り当てます。 - CLR の add と remove のイベント アクセサーを定義します。
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 に追加し、CustomButton
要素と StackPanel1
要素の ConditionalClick
イベント ハンドラーとして Handler_ConditionalClick
メソッドを割り当てる別個の WPF アプリケーションが含まれています。
<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
がクリックされた場合、次の処理が実行されます。
ConditionalClick
ルーティング イベントがCustomButton
で発生します。CustomButton
にアタッチされたHandler_ConditionalClick
イベント ハンドラーがトリガーされます。ConditionalClick
ルーティング イベントでは、要素ツリーがStackPanel1
まで検査されます。StackPanel1
にアタッチされたHandler_ConditionalClick
イベント ハンドラーがトリガーされます。ConditionalClick
ルーティング イベントは要素ツリー上で継続され、他の検査対象要素にアタッチされた他のConditionalClick
イベント ハンドラーがトリガーされる可能性があります。
Handler_ConditionalClick
イベント ハンドラーは、トリガーしたイベントに関する次の情報を取得します。
- イベント ハンドラーがアタッチされた要素である sender オブジェクト。
sender
は、ハンドラーが初めて実行されたときはCustomButton
、2 回目はStackPanel1
になります。 - 最初にイベントを発生させた要素である RoutedEventArgs.Source オブジェクト。 この例では、
Source
は常にCustomButton
です。
注意
ルーティング イベントと CLR イベントの主な違いは、ルーティング イベントでは要素ツリーを検査してハンドラーを探すのに対し、CLR イベントでは要素ツリーを検査せず、ハンドラーはイベントを発生させたソース オブジェクトにのみアタッチできることです。 その結果、sender
ルーティング イベントには、要素ツリー内の任意の検査対象要素を指定できます。
トンネリング イベントは、バブル イベントと同じ方法で作成できます。ただし、Tunnel へのイベント登録呼び出しでルーティング戦略を設定する点が異なります。 トンネリング イベントの詳細については、「WPF の入力イベント」を参照してください。
参照
.NET Desktop feedback