ルーティング イベントの概要Routed Events Overview

このトピックでは、Windows Presentation Foundation (WPF)Windows Presentation Foundation (WPF) でのルーティング イベントの概念について説明します。This topic describes the concept of routed events in Windows Presentation Foundation (WPF)Windows Presentation Foundation (WPF). ここでは、ルーティング イベントの用語を定義し、要素ツリーを通じたルーティング イベントのルーティング方法、ルーティング イベントの処理方法、カスタム ルーティング イベントの作成方法について説明します。The topic defines routed events terminology, describes how routed events are routed through a tree of elements, summarizes how you handle routed events, and introduces how to create your own custom routed events.

必要条件Prerequisites

このトピックでは、共通言語ランタイム (CLR) とオブジェクト指向プログラミングについての基本的な知識があること、および WPFWPF 要素間のリレーションシップをツリーとして概念化する方法の概念を理解していることを前提としています。This topic assumes that you have basic knowledge of the common language runtime (CLR) and object-oriented programming, as well as the concept of how the relationships between WPFWPF elements can be conceptualized as a tree. このトピックの例に従うには、Extensible Application Markup Language (XAML)Extensible Application Markup Language (XAML) について理解し、ごく基本的な WPFWPF アプリケーションまたはページを作成できる必要があります。In order to follow the examples in this topic, you should also understand Extensible Application Markup Language (XAML)Extensible Application Markup Language (XAML) and know how to write very basic WPFWPF applications or pages. 詳細については、「チュートリアル: 初めての wpf デスクトップアプリケーションXAML の概要 (wpf)」を参照してください。For more information, see Walkthrough: My first WPF desktop application and XAML Overview (WPF).

ルーティング イベントとはWhat Is a Routed Event?

ルーティング イベントについては、機能または実装の観点から考えることができます。You can think about routed events either from a functional or implementation perspective. どちらを便利と感じるかは個人によって異なるため、ここでは両方の見方を提示します。Both definitions are presented here, because some people find one or the other definition more useful.

観点を機能に置いた場合、ルーティング イベントは、イベントを生成したオブジェクト上だけでなく、要素ツリー内の複数のリスナー上でハンドラーを呼び出すことができる種類のイベントです。Functional definition: A routed event is a type of event that can invoke handlers on multiple listeners in an element tree, rather than just on the object that raised the event.

実装定義: ルーティングイベントは、RoutedEvent クラスのインスタンスによってサポートされ、Windows Presentation Foundation (WPF)Windows Presentation Foundation (WPF) イベントシステムによって処理される CLR イベントです。Implementation definition: A routed event is a CLR event that is backed by an instance of the RoutedEvent class and is processed by the Windows Presentation Foundation (WPF)Windows Presentation Foundation (WPF) event system.

一般的な WPFWPF アプリケーションには、多数の要素が含まれます。A typical WPFWPF application contains many elements. コードで作成したか XAMLXAML の宣言によって作成したかにかかわらず、これらの要素は互いに要素ツリー リレーションシップにあります。Whether created in code or declared in XAMLXAML, these elements exist in an element tree relationship to each other. イベントのルーティングは、イベント定義に従って 2 つの方向のいずれかをたどることができますが、一般にはルーティングは発生元要素から要素ツリーに沿って "浮上" し、最終的には要素ツリーのルート (通常はページまたはウィンドウ) に到達します。The event route can travel in one of two directions depending on the event definition, but generally the route travels from the source element and then "bubbles" upward through the element tree until it reaches the element tree root (typically a page or a window). このバブル (浮上) の概念は、DHTML オブジェクト モデルで使用される概念と似ています。This bubbling concept might be familiar to you if you have worked with the DHTML object model previously.

たとえば、次のような単純な要素ツリーがあるとします。Consider the following simple element tree:

<Border Height="50" Width="300" BorderBrush="Gray" BorderThickness="1">
  <StackPanel Background="LightGray" Orientation="Horizontal" Button.Click="CommonClickHandler">
    <Button Name="YesButton" Width="Auto" >Yes</Button>
    <Button Name="NoButton" Width="Auto" >No</Button>
    <Button Name="CancelButton" Width="Auto" >Cancel</Button>
  </StackPanel>
</Border>

この要素ツリーでは、次のようなものが生成されます。This element tree produces something like the following:

[はい]、[いいえ]、および [キャンセル] ボタンYes, No, and Cancel buttons

この簡略化された要素ツリーでは、Click イベントのソースが Button 要素の1つであり、どちらかの Button がクリックされたは、イベントを処理する機会を持つ最初の要素です。In this simplified element tree, the source of a Click event is one of the Button elements, and whichever Button was clicked is the first element that has the opportunity to handle the event. ただし、Button にアタッチされているハンドラーがイベントに対して動作しない場合、イベントは、StackPanelである要素ツリーの Button 親にバブルされます。But if no handler attached to the Button acts on the event, then the event will bubble upwards to the Button parent in the element tree, which is the StackPanel. 場合によっては、イベントが Borderにバブルした後、要素ツリーのページルートに収まりません (表示されません)。Potentially, the event bubbles to Border, and then beyond to the page root of the element tree (not shown).

言い換えると、この Click イベントのイベントルートは次のようになります。In other words, the event route for this Click event is:

Button-->StackPanel-->Border-->...Button-->StackPanel-->Border-->...

ルーティング イベントのトップレベルのシナリオTop-level Scenarios for Routed Events

次に、ルーティングイベントの概念を実現するシナリオの概要と、一般的な CLR イベントがこれらのシナリオに適していなかった理由について簡単に説明します。The following is a brief summary of the scenarios that motivated the routed event concept, and why a typical CLR event was not adequate for these scenarios:

コントロールの複合とカプセル化: WPFWPF のさまざまなコントロールには、多機能のコンテンツ モデルが採用されています。Control composition and encapsulation: Various controls in WPFWPF have a rich content model. たとえば、Button内にイメージを配置すると、ボタンのビジュアルツリーを効果的に拡張できます。For example, you can place an image inside of a Button, which effectively extends the visual tree of the button. ただし、追加されたイメージは、ユーザーがイメージの技術的な部分にあるピクセルをクリックした場合でも、ボタンがそのコンテンツの Click に応答するようにするヒットテスト動作を中断しないようにする必要があります。However, the added image must not break the hit-testing behavior that causes a button to respond to a Click of its content, even if the user clicks on pixels that are technically part of the image.

単一のハンドラー アタッチ ポイント: Windows フォームWindows Formsでは、複数の要素から発生する可能性があるイベントを処理するために同じハンドラーを複数回アタッチする必要があります。Singular handler attachment points: In Windows フォームWindows Forms, you would have to attach the same handler multiple times to process events that could be raised from multiple elements. ルーティング イベントを使用すると、前の例に示したとおり、ハンドラーを一度だけアタッチし、必要に応じてハンドラーのロジックを使用してイベントの発生元を特定することができます。Routed events enable you to attach that handler only once, as was shown in the previous example, and use handler logic to determine where the event came from if necessary. たとえば、前に示した XAMLXAML では次のようなハンドラーを使用します。For instance, this might be the handler for the previously shown XAMLXAML:

private void CommonClickHandler(object sender, RoutedEventArgs e)
{
  FrameworkElement feSource = e.Source as FrameworkElement;
  switch (feSource.Name)
  {
    case "YesButton":
      // do something here ...
      break;
    case "NoButton":
      // do something ...
      break;
    case "CancelButton":
      // do something ...
      break;
  }
  e.Handled=true;
}
Private Sub CommonClickHandler(ByVal sender As Object, ByVal e As RoutedEventArgs)
  Dim feSource As FrameworkElement = TryCast(e.Source, FrameworkElement)
  Select Case feSource.Name
    Case "YesButton"
      ' do something here ...
    Case "NoButton"
      ' do something ...
    Case "CancelButton"
      ' do something ...
  End Select
  e.Handled=True
End Sub

クラス処理: ルーティング イベントでは、クラスに定義した静的ハンドラーを使用できます。Class handling: Routed events permit a static handler that is defined by the class. このクラス ハンドラーでは、アタッチされたどのインスタンス ハンドラーよりも先にイベントを処理できます。This class handler has the opportunity to handle an event before any attached instance handlers can.

リフレクションを使用しないイベント参照: 特定のコードやマークアップのテクニックでは、特定のイベントを識別する機能が必要とされます。Referencing an event without reflection: Certain code and markup techniques require a way to identify a specific event. ルーティングイベントによって、RoutedEvent フィールドが識別子として作成されます。このフィールドは、静的または実行時のリフレクションを必要としない、堅牢なイベント識別手法を提供します。A routed event creates a RoutedEvent field as an identifier, which provides a robust event identification technique that does not require static or run-time reflection.

ルーティング イベントの実装方法How Routed Events Are Implemented

ルーティングイベントは、RoutedEvent クラスのインスタンスによってサポートされ、WPFWPF のイベントシステムに登録される CLR イベントです。A routed event is a CLR event that is backed by an instance of the RoutedEvent class and registered with the WPFWPF event system. 登録から取得した RoutedEvent インスタンスは、通常、ルーティングイベントを登録して "所有" するクラスの public static readonly フィールドメンバーとして保持されます。The RoutedEvent instance obtained from registration is typically retained as a public static readonly field member of the class that registers and thus "owns" the routed event. 同じ名前を持つ CLR イベント ("ラッパー" イベントと呼ばれることもあります) への接続は、CLR イベントの add および remove の実装をオーバーライドすることによって実現されます。The connection to the identically named CLR event (which is sometimes termed the "wrapper" event) is accomplished by overriding the add and remove implementations for the CLR event. 通常、addremove は、暗黙の既定のままにされ、そのイベントのハンドラーの追加や削除に言語固有の適切なイベント構文が使用されます。Ordinarily, the add and remove are left as an implicit default that uses the appropriate language-specific event syntax for adding and removing handlers of that event. ルーティングイベントのバッキングと接続のメカニズムは、依存関係プロパティが、DependencyProperty クラスによってサポートされ、WPFWPF プロパティシステムに登録されている CLR プロパティであるという概念に似ています。The routed event backing and connection mechanism is conceptually similar to how a dependency property is a CLR property that is backed by the DependencyProperty class and registered with the WPFWPF property system.

次の例は、カスタム Tap ルーティングイベントの宣言を示しています。これには、RoutedEvent 識別子フィールドの登録と公開、Tap CLR イベントの add および remove 実装が含まれます。The following example shows the declaration for a custom Tap routed event, including the registration and exposure of the RoutedEvent identifier field and the add and remove implementations for the Tap CLR event.

public static readonly RoutedEvent TapEvent = EventManager.RegisterRoutedEvent(
    "Tap", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MyButtonSimple));

// Provide CLR accessors for the event
public event RoutedEventHandler Tap
{
        add { AddHandler(TapEvent, value); } 
        remove { RemoveHandler(TapEvent, value); }
}
Public Shared ReadOnly TapEvent As RoutedEvent = EventManager.RegisterRoutedEvent("Tap", RoutingStrategy.Bubble, GetType(RoutedEventHandler), GetType(MyButtonSimple))

' Provide CLR accessors for the event
Public Custom Event Tap As RoutedEventHandler
    AddHandler(ByVal value As RoutedEventHandler)
        Me.AddHandler(TapEvent, value)
    End AddHandler

    RemoveHandler(ByVal value As RoutedEventHandler)
        Me.RemoveHandler(TapEvent, value)
    End RemoveHandler

    RaiseEvent(ByVal sender As Object, ByVal e As RoutedEventArgs)
        Me.RaiseEvent(e)
    End RaiseEvent
End Event

ルーティング イベント ハンドラーと XAMLRouted Event Handlers and XAML

XAMLXAML を使用してイベントのハンドラーを追加するには、イベント リスナーである要素の属性としてイベント名を宣言します。To add a handler for an event using XAMLXAML, you declare the event name as an attribute on the element that is an event listener. 属性の値は、実装したハンドラー メソッドの名前です。このメソッドは、分離コード ファイルの部分クラス内に存在する必要があります。The value of the attribute is the name of your implemented handler method, which must exist in the partial class of the code-behind file.

<Button Click="b1SetColor">button</Button>

標準 CLR イベントハンドラーを追加するための XAMLXAML 構文は、ルーティングイベントハンドラーを追加する場合と同じです。これは、その下にルーティングイベントの実装がある CLR イベントラッパーにハンドラーを追加するためです。The XAMLXAML syntax for adding standard CLR event handlers is the same for adding routed event handlers, because you are really adding handlers to the CLR event wrapper, which has a routed event implementation underneath. イベント ハンドラーをXAMLXAML で追加する方法の詳細については、「XAML の概要 (WPF)」を参照してください。For more information about adding event handlers in XAMLXAML, see XAML Overview (WPF).

ルーティング方法Routing Strategies

ルーティング イベントは、3 つのルーティング方法のいずれかを使用します。Routed events use one of three routing strategies:

  • バブル: イベント ソースのイベント ハンドラーが呼び出されます。Bubbling: Event handlers on the event source are invoked. ルーティング イベントは、次に、要素ツリー ルートに到達するまで、連続する親要素にルーティングします。The routed event then routes to successive parent elements until reaching the element tree root. ほとんどのルーティング イベントでは、このバブル ルーティング方法を使用します。Most routed events use the bubbling routing strategy. バブル ルーティング イベントは、一般に個別のコントロールまたはその他の UI 要素からの入力や状態変化を報告するために使用されます。Bubbling routed events are generally used to report input or state changes from distinct controls or other UI elements.

  • 直接: ソース要素自体のみに、応答としてハンドラーを呼び出す機会が与えられます。Direct: Only the source element itself is given the opportunity to invoke handlers in response. これは、Windows フォームWindows Forms がイベントに使用する "ルーティング" と似ています。This is analogous to the "routing" that Windows フォームWindows Forms uses for events. ただし、標準の CLR イベントとは異なり、ダイレクトルーティングイベントはクラスの処理をサポートしています (クラスの処理については、今後のセクションで説明します)。 EventSetterEventTriggerで使用できます。However, unlike a standard CLR event, direct routed events support class handling (class handling is explained in an upcoming section) and can be used by EventSetter and EventTrigger.

  • トンネル: 要素ツリー ルートのイベント ハンドラーが最初に呼び出されます。Tunneling: Initially, event handlers at the element tree root are invoked. ルーティング イベントは、次に、経路沿いにルーティング イベント ソース (ルーティング イベントを発生させた要素) のノード要素まで、連続する子要素間の経路をたどります。The routed event then travels a route through successive child elements along the route, towards the node element that is the routed event source (the element that raised the routed event). 多くの場合にトンネル ルーティング イベントは、コントロールの複合部分として使用または処理されます。たとえば、複合部分で発生したイベントは、完全なコントロールに固有のイベントによって意図的に抑止されるか置き換えられます。Tunneling routed events are often used or handled as part of the compositing for a control, such that events from composite parts can be deliberately suppressed or replaced by events that are specific to the complete control. 多くの場合、WPFWPF から提供される入力イベントはトンネルとバブルのペアとして実装されます。Input events provided in WPFWPF often come implemented as a tunneling/bubbling pair. トンネル イベントは、このペアに使用される名前付け規則から、プレビュー イベントと呼ばれることもあります。Tunneling events are also sometimes referred to as Preview events, because of a naming convention that is used for the pairs.

ルーティング イベントを使用する理由Why Use Routed Events?

アプリケーションを開発するときに、処理するイベントがルーティング イベントとして実装されているかどうかを常に確認する必要はありません。As an application developer, you do not always need to know or care that the event you are handling is implemented as a routed event. ルーティング イベントの動作は独特ですが、イベントを発生元の要素で処理する限り、動作はあまり表面には見えません。Routed events have special behavior, but that behavior is largely invisible if you are handling an event on the element where it is raised.

ルーティング イベントが効果を発揮するのは、共通ハンドラーを共通ルートに定義する、独自のコントロールを複合化する、カスタム コントロール クラスを定義するなどの、特定のシナリオの場合です。Where routed events become powerful is if you use any of the suggested scenarios: defining common handlers at a common root, compositing your own control, or defining your own custom control class.

ルーティング イベント リスナーとルーティング イベント ソースは、階層内で共通イベントを共有する必要はありません。Routed event listeners and routed event sources do not need to share a common event in their hierarchy. 任意の UIElement または ContentElement は、任意のルーティングイベントのイベントリスナーにすることができます。Any UIElement or ContentElement can be an event listener for any routed event. そのため、アプリケーション内のさまざまな要素がイベント情報を交換できる概念 "インターフェイス" として、動作している API セット全体で利用可能なルーティングイベントの完全なセットを使用できます。Therefore, you can use the full set of routed events available throughout the working API set as a conceptual "interface" whereby disparate elements in the application can exchange event information. ルーティング イベントのこの "インターフェイス" 概念は、特に入力イベントに当てはまります。This "interface" concept for routed events is particularly applicable for input events.

また、ルーティング イベントは、要素ツリー間の通信にも使用できます。これは、イベントのイベント データが経路上の各要素に永続的に保持されるためです。Routed events can also be used to communicate through the element tree, because the event data for the event is perpetuated to each element in the route. ある要素でイベント データの一部を変更した場合、この変更は経路上の次の要素で使用できます。One element could change something in the event data, and that change would be available to the next element in the route.

ルーティングの側面以外にも、特定の WPFWPF イベントが標準の CLR イベントではなくルーティングイベントとして実装される可能性があるという2つの理由があります。Other than the routing aspect, there are two other reasons that any given WPFWPF event might be implemented as a routed event instead of a standard CLR event. 独自のイベントを実装している場合は、次の原則も考慮します。If you are implementing your own events, you might also consider these principles:

  • EventSetterEventTrigger などの特定の WPFWPF スタイル設定およびテンプレート機能では、参照されるイベントがルーティングイベントである必要があります。Certain WPFWPF styling and templating features such as EventSetter and EventTrigger require the referenced event to be a routed event. これは、前に説明したイベント識別子シナリオです。This is the event identifier scenario mentioned earlier.

  • ルーティング イベントは、クラス処理機構をサポートしています。この機構により、クラスに静的メソッドを指定して、登録されたインスタンス ハンドラーがルーティング イベントにアクセスする前にこの静的メソッドでイベントを処理することができます。Routed events support a class handling mechanism whereby the class can specify static methods that have the opportunity to handle routed events before any registered instance handlers can access them. インスタンスでのイベント処理によって誤って抑止されずにイベント駆動のクラス動作を適用できるため、これはコントロールをデザインするときに便利です。This is very useful in control design, because your class can enforce event-driven class behaviors that cannot be accidentally suppressed by handling an event on an instance.

前に示した一連の考慮事項については、このトピックのセクションで個別に説明します。Each of the above considerations is discussed in a separate section of this topic.

ルーティング イベントのイベント ハンドラーの追加と実装Adding and Implementing an Event Handler for a Routed Event

XAMLXAML でイベント ハンドラーを追加するには、次の例に示すように、単にイベント名を要素に属性として追加し、属性の値として、適切なデリゲートを実装するイベント ハンドラーの名前を設定します。To add an event handler in XAMLXAML, you simply add the event name to an element as an attribute and set the attribute value as the name of the event handler that implements an appropriate delegate, as in the following example.

<Button Click="b1SetColor">button</Button>

b1SetColor は、Click イベントを処理するコードを含む実装されたハンドラーの名前です。b1SetColor is the name of the implemented handler that contains the code that handles the Click event. b1SetColor は、RoutedEventHandler デリゲートと同じシグネチャを持つ必要があります。これは、Click イベントのイベントハンドラーデリゲートです。b1SetColor must have the same signature as the RoutedEventHandler delegate, which is the event handler delegate for the Click event. すべてのルーティング イベント ハンドラー デリゲートの 1 番目のパラメーターでは、イベント ハンドラーの追加先の要素を指定し、2 番目のパラメーターでは、イベントのデータを指定します。The first parameter of all routed event handler delegates specifies the element to which the event handler is added, and the second parameter specifies the data for the event.

void b1SetColor(object sender, RoutedEventArgs args)
{
  //logic to handle the Click event
}
Private Sub b1SetColor(ByVal sender As Object, ByVal args As RoutedEventArgs)
  'logic to handle the Click event
End Sub

RoutedEventHandler は、基本的なルーティングイベントハンドラーデリゲートです。RoutedEventHandler is the basic routed event handler delegate. 特定のコントロールやシナリオに特化したルーティング イベントの場合、ルーティング イベント ハンドラーに使用するデリゲートも、より特化したものとなることがあるため、特別なイベント データを転送できます。For routed events that are specialized for certain controls or scenarios, the delegates to use for the routed event handlers also might become more specialized, so that they can transmit specialized event data. たとえば、一般的な入力シナリオでは、DragEnter ルーティングイベントを処理する場合があります。For instance, in a common input scenario, you might handle a DragEnter routed event. ハンドラーは DragEventHandler デリゲートを実装する必要があります。Your handler should implement the DragEventHandler delegate. 最も具体的なデリゲートを使用して、ハンドラー内の DragEventArgs を処理し、ドラッグ操作のクリップボードペイロードを含む Data プロパティを読み取ることができます。By using the most specific delegate, you can process the DragEventArgs in the handler and read the Data property, which contains the clipboard payload of the drag operation.

XAMLXAML を使用してイベント ハンドラーを要素に追加する方法の詳細な例については、「ルーティング イベントを処理する」を参照してください。For a complete example of how to add an event handler to an element using XAMLXAML, see Handle a Routed Event.

コードで作成されたアプリケーションでルーティング イベントのハンドラーを追加するのは簡単です。Adding a handler for a routed event in an application that is created in code is straightforward. ルーティングイベントハンドラーは、常にヘルパーメソッド AddHandler (既存のバッキングが addを呼び出す場合と同じメソッド) を使用して追加できます。ただし、既存の WPFWPF ルーティングイベントは、一般に、ヘルパーメソッドよりも直感的な構文である言語固有のイベント構文でルーティングイベントのハンドラーを追加できるようにする、add および remove ロジックのバッキング実装を備えています。Routed event handlers can always be added through a helper method AddHandler (which is the same method that the existing backing calls for add.) However, existing WPFWPF routed events generally have backing implementations of add and remove logic that allow the handlers for routed events to be added by a language-specific event syntax, which is more intuitive syntax than the helper method. ヘルパー メソッドの使用例を次に示します。The following is an example usage of the helper method:

void MakeButton()
 {
     Button b2 = new Button();
     b2.AddHandler(Button.ClickEvent, new RoutedEventHandler(Onb2Click));
 }
 void Onb2Click(object sender, RoutedEventArgs e)
 {
     //logic to handle the Click event     
 }
Private Sub MakeButton()
     Dim b2 As New Button()
     b2.AddHandler(Button.ClickEvent, New RoutedEventHandler(AddressOf Onb2Click))
End Sub
 Private Sub Onb2Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
     'logic to handle the Click event     
 End Sub

次の例は、 C#演算子の構文を示しています (Visual Basic 逆参照の処理によって、演算子の構文が少し異なります)。The next example shows the C# operator syntax (Visual Basic has slightly different operator syntax because of its handling of dereferencing):

void MakeButton2()
{
  Button b2 = new Button();
  b2.Click += new RoutedEventHandler(Onb2Click2);
}
void Onb2Click2(object sender, RoutedEventArgs e)
{
  //logic to handle the Click event     
}
Private Sub MakeButton2()
  Dim b2 As New Button()
  AddHandler b2.Click, AddressOf Onb2Click2
End Sub
Private Sub Onb2Click2(ByVal sender As Object, ByVal e As RoutedEventArgs)
  'logic to handle the Click event     
End Sub

コードでイベント ハンドラーを追加する方法の例については、「コードを使用してイベント ハンドラーを追加する」を参照してください。For an example of how to add an event handler in code, see Add an Event Handler Using Code.

Visual Basic を使用している場合は、Handles キーワードを使用してハンドラー宣言の一部としてハンドラーを追加することもできます。If you are using Visual Basic, you can also use the Handles keyword to add handlers as part of the handler declarations. 詳細については、「Visual Basic と WPF のイベント処理」を参照してください。For more information, see Visual Basic and WPF Event Handling.

処理済みの概念The Concept of Handled

すべてのルーティングイベントは、共通のイベントデータの基本クラスである RoutedEventArgsを共有します。All routed events share a common event data base class, RoutedEventArgs. RoutedEventArgs は、ブール値を受け取る Handled プロパティを定義します。RoutedEventArgs defines the Handled property, which takes a Boolean value. Handled プロパティの目的は、Handled の値を trueに設定することによって、ルーティングイベントを処理済みとしてマークするために、ルート上の任意のイベントハンドラーを有効にすることです。The purpose of the Handled property is to enable any event handler along the route to mark the routed event as handled, by setting the value of Handled to true. 経路上の 1 つの要素のハンドラーで処理された後、共有イベント データが経路上の各リスナーに再び報告されます。After being processed by the handler at one element along the route, the shared event data is again reported to each listener along the route.

Handled の値は、ルーティングイベントがルートに沿って移動するときに、そのイベントの報告方法や処理方法に影響します。The value of Handled affects how a routed event is reported or processed as it travels further along the route. ルーティングイベントのイベントデータに Handledtrue 場合、他の要素でそのルーティングイベントをリッスンするハンドラーは、通常、その特定のイベントインスタンスに対して呼び出されなくなります。If Handled is true in the event data for a routed event, then handlers that listen for that routed event on other elements are generally no longer invoked for that particular event instance. これは、XAMLXAML でアタッチされたハンドラーの場合も、+=Handles など、言語固有のイベント ハンドラー アタッチ構文によって追加されたハンドラーの場合も同様です。This is true both for handlers attached in XAMLXAML and for handlers added by language-specific event handler attachment syntaxes such as += or Handles. 最も一般的なハンドラーのシナリオでは、Handledtrue に設定してイベントを処理済みとしてマークすると、トンネリングルートまたはバブルルートに対してルーティングが "停止" されます。また、クラスハンドラーによってルートのポイントで処理されるすべてのイベントに対しても "停止" されます。For most common handler scenarios, marking an event as handled by setting Handled to true will "stop" routing for either a tunneling route or a bubbling route, and also for any event that is handled at a point in the route by a class handler.

ただし、イベントデータに Handledtrue ルーティングイベントに応答して、リスナーがハンドラーを実行できるようにする "handledEventsToo" メカニズムがあります。However, there is a "handledEventsToo" mechanism whereby listeners can still run handlers in response to routed events where Handled is true in the event data. つまり、イベント データを処理済みとしてマークしてもイベントのルーティングは完全には停止されません。In other words, the event route is not truly stopped by marking the event data as handled. HandledEventsToo 機構は、コードまたは EventSetterでのみ使用できます。You can only use the handledEventsToo mechanism in code, or in an EventSetter:

Handled 状態がルーティングイベントに生成する動作に加えて、Handled の概念は、アプリケーションを設計し、イベントハンドラーコードを記述する方法に影響します。In addition to the behavior that Handled state produces in routed events, the concept of Handled has implications for how you should design your application and write the event handler code. Handled は、ルーティングイベントによって公開される単純なプロトコルとして概念化できます。You can conceptualize Handled as being a simple protocol that is exposed by routed events. このプロトコルの使用方法はお勧めしますが、Handled の値を使用する方法の概念設計は次のとおりです。Exactly how you use this protocol is up to you, but the conceptual design for how the value of Handled is intended to be used is as follows:

  • ルーティング イベントが処理済みとしてマークされている場合、このイベントを経路上の他の要素でもう一度処理する必要はありません。If a routed event is marked as handled, then it does not need to be handled again by other elements along that route.

  • ルーティングイベントが処理済みとしてマークされていない場合は、ルートの前にある他のリスナーがハンドラーを登録しないことを選択したか、または登録されたハンドラーがイベントデータを操作せずに Handledtrueに設定することを選択しました。If a routed event is not marked as handled, then other listeners that were earlier along the route have chosen either not to register a handler, or the handlers that were registered chose not to manipulate the event data and set Handled to true. (または、現在のリスナーがルートの最初のポイントである可能性もあります)。現在のリスナーのハンドラーには、次の3つのアクションが可能になりました。(Or, it is of course possible that the current listener is the first point in the route.) Handlers on the current listener now have three possible courses of action:

    • アクションをまったく行いません。イベントは未処理のまま、次のリスナーにルーティングされます。Take no action at all; the event remains unhandled, and the event routes to the next listener.

    • イベントに応答してコードを実行しますが、実行したアクションはイベントを処理済みとしてマークするのに十分とは確定されません。Execute code in response to the event, but make the determination that the action taken was not substantial enough to warrant marking the event as handled. イベントは次のリスナーにルーティングされます。The event routes to the next listener.

    • イベントに応答してコードを実行します。Execute code in response to the event. 実行したアクションはイベントを処理済みとしてマークするのに十分と考えられるため、ハンドラーに渡されたイベント データでイベントを処理済みとしてマークします。Mark the event as handled in the event data passed to the handler, because the action taken was deemed substantial enough to warrant marking as handled. イベントは次のリスナーにルーティングされますが、イベントデータには Handled=true があるため、handledEventsToo リスナーだけがさらにハンドラーを呼び出すことができます。The event still routes to the next listener, but with Handled=true in its event data, so only handledEventsToo listeners have the opportunity to invoke further handlers.

この概念設計は、前に説明したルーティング動作によって強化されています。ルート上の前のハンドラーが既に設定されている場合でも呼び出されるルーティングイベントのハンドラーをアタッチするのは、(コードまたはスタイルでも可能ですが) より困難です Handledtrueします。This conceptual design is reinforced by the routing behavior mentioned earlier: it is more difficult (although still possible in code or styles) to attach handlers for routed events that are invoked even if a previous handler along the route has already set Handled to true.

Handled、ルーティングイベントのクラス処理、およびルーティングイベントを Handledとしてマークする適切なタイミングに関する推奨事項の詳細については、「ルーティングイベントを処理済みとしてマークする」および「クラス処理」を参照してください。For more information about Handled, class handling of routed events, and recommendations about when it is appropriate to mark a routed event as Handled, see Marking Routed Events as Handled, and Class Handling.

アプリケーションでは、バブル ルーティング イベントを発生元のオブジェクトで処理するのが一般的であり、イベントのルーティング特性についてはまったく考慮されません。In applications, it is quite common to just handle a bubbling routed event on the object that raised it, and not be concerned with the event's routing characteristics at all. ただし、その場合でも、イベント データでルーティング イベントを処理済みとしてマークすることをお勧めします。そうすれば、要素ツリーの後方にある要素でそれと同じルーティング イベントにハンドラーがアタッチされている場合に起こりうる、予期しない副作用を回避できます。However, it is still a good practice to mark the routed event as handled in the event data, to prevent unanticipated side effects just in case an element that is further up the element tree also has a handler attached for that same routed event.

クラス ハンドラーClass Handlers

DependencyObjectから派生するクラスを定義する場合は、クラスの宣言または継承されたイベントメンバーであるルーティングイベントのクラスハンドラーを定義してアタッチすることもできます。If you are defining a class that derives in some way from DependencyObject, you can also define and attach a class handler for a routed event that is a declared or inherited event member of your class. ルーティング イベントが経路上の要素インスタンスに到達すると、クラスのインスタンスにアタッチされたどのインスタンス リスナー ハンドラーよりも先に、クラス ハンドラーが呼び出されます。Class handlers are invoked before any instance listener handlers that are attached to an instance of that class, whenever a routed event reaches an element instance in its route.

一部の WPFWPF コントロールには、特定のルーティング イベントに対する固有のクラス処理が存在します。Some WPFWPF controls have inherent class handling for certain routed events. このため、ルーティング イベントが発生していないように見えても、実際にはクラス処理されている場合があります。また、特定の手法を使用した場合、インスタンス ハンドラーでも処理される可能性があります。This might give the outward appearance that the routed event is not ever raised, but in reality it is being class handled, and the routed event can potentially still be handled by your instance handlers if you use certain techniques. また、多くの基底クラスとコントロールからは、クラス処理の動作をオーバーライドするために使用できる仮想メソッドが提供されています。Also, many base classes and controls expose virtual methods that can be used to override class handling behavior. 望ましくないクラス処理の回避方法とカスタム クラスを使った独自のクラス処理定義方法の詳細については、「ルーティング イベントの処理済みとしてのマーキング、およびクラス処理」を参照してください。For more information both on how to work around undesired class handling and on defining your own class handling in a custom class, see Marking Routed Events as Handled, and Class Handling.

WPF の添付イベントAttached Events in WPF

XAMLXAML 言語は、添付イベントと呼ばれる特殊な種類のイベントも定義します。The XAMLXAML language also defines a special type of event called an attached event. 添付イベントを使用して、任意の要素に特定のイベントのハンドラーを追加できます。An attached event enables you to add a handler for a particular event to an arbitrary element. イベントを処理する要素が添付イベントを定義または継承する必要はありません。また、イベントを発生させる可能性のあるオブジェクトでも、インスタンスを処理する添付先でも、そのイベントを定義したりクラス メンバーとして "所有" したりする必要はありません。The element handling the event need not define or inherit the attached event, and neither the object potentially raising the event nor the destination handling instance must define or otherwise "own" that event as a class member.

WPFWPF 入力システムでは、添付イベントを多用します。The WPFWPF input system uses attached events extensively. ただし、ほとんどすべての添付イベントは基本要素間で転送されます。However, nearly all of these attached events are forwarded through base elements. 入力イベントは、基本要素クラスのメンバーである、非添付のルーティング イベントに等しいものとして表されます。The input events then appear as equivalent non-attached routed events that are members of the base element class. たとえば、基になるアタッチされたイベント Mouse.MouseDown は、XAMLXAML またはコードで添付イベント構文を処理するのではなく、その UIElementMouseDown を使用することにより、特定の UIElement でより簡単に処理できます。For instance, the underlying attached event Mouse.MouseDown can more easily be handled on any given UIElement by using MouseDown on that UIElement rather than dealing with attached event syntax either in XAMLXAML or code.

WPFWPF の添付イベントの詳細については、「添付イベントの概要」を参照してください。For more information about attached events in WPFWPF, see Attached Events Overview.

XAML の修飾イベント名Qualified Event Names in XAML

typename.eventname 添付イベント構文に似ているが厳密に言えば添付イベントの使用方法ではない、もう 1 つの構文使用方法では、子要素で発生したルーティング イベントのハンドラーをアタッチします。Another syntax usage that resembles typename.eventname attached event syntax but is not strictly speaking an attached event usage is when you attach handlers for routed events that are raised by child elements. 対応するルーティング イベントが共通の親要素にメンバーとして含まれない場合でも、共通の親要素にハンドラーをアタッチしてイベントのルーティングを利用します。You attach the handlers to a common parent, to take advantage of event routing, even though the common parent might not have the relevant routed event as a member. 次の例をもう一度検討します。Consider this example again:

<Border Height="50" Width="300" BorderBrush="Gray" BorderThickness="1">
  <StackPanel Background="LightGray" Orientation="Horizontal" Button.Click="CommonClickHandler">
    <Button Name="YesButton" Width="Auto" >Yes</Button>
    <Button Name="NoButton" Width="Auto" >No</Button>
    <Button Name="CancelButton" Width="Auto" >Cancel</Button>
  </StackPanel>
</Border>

ここでは、ハンドラーが追加される親要素リスナーが StackPanelです。Here, the parent element listener where the handler is added is a StackPanel. ただし、宣言されたルーティングイベントのハンドラーを追加しています。これは Button クラスによって発生します (実際にはButtonBase ますが、継承によって Button できます)。However, it is adding a handler for a routed event that was declared and will be raised by the Button class (ButtonBase actually, but available to Button through inheritance). イベントは "所有" Button ますが、ルーティングイベントシステムでは、任意のルーティングイベントのハンドラーが、共通言語ランタイム (CLR) イベントのリスナーをアタッチできる任意の UIElement または ContentElement インスタンスリスナーにアタッチすることが許可されます。Button "owns" the event, but the routed event system permits handlers for any routed event to be attached to any UIElement or ContentElement instance listener that could otherwise attach listeners for a common language runtime (CLR) event. これらの修飾イベント属性名の既定の xmlns 名前空間は、通常、既定の WPFWPF xmlns 名前空間ですが、カスタム ルーティング イベント用のプレフィックスを持つ名前空間を指定することもできます。The default xmlns namespace for these qualified event attribute names is typically the default WPFWPF xmlns namespace, but you can also specify prefixed namespaces for custom routed events. xmlns の詳細については、「XAML 名前空間および WPF XAML の名前空間の割り当て」を参照してください。For more information about xmlns, see XAML Namespaces and Namespace Mapping for WPF XAML.

WPF の入力イベントWPF Input Events

WPFWPF プラットフォームにおけるルーティング イベントの主な使用例として、入力イベントがあります。One frequent application of routed events within the WPFWPF platform is for input events. WPFWPF では、トンネル ルーティング イベントの名前に "Preview" をプレフィックスとして付加するのが慣例です。In WPFWPF, tunneling routed events names are prefixed with the word "Preview" by convention. 入力イベントは、多くの場合、バブル イベントとトンネル イベントがペアになって構成されます。Input events often come in pairs, with one being the bubbling event and the other being the tunneling event. たとえば、KeyDown イベントと PreviewKeyDown イベントのシグネチャは同じですが、前者はバブル入力イベント、後者はトンネリング入力イベントです。For example, the KeyDown event and the PreviewKeyDown event have the same signature, with the former being the bubbling input event and the latter being the tunneling input event. 入力イベントによっては、バブル形式だけ、または直接ルーティング形式だけを持つ場合もあります。Occasionally, input events only have a bubbling version, or perhaps only a direct routed version. このドキュメント内のルーティング イベントに関するトピックでは、他のルーティング方法を使用する類似ルーティング イベントがある場合は相互参照を示します。またマネージド リファレンス ページでは、各ルーティング イベントのルーティング方法について説明します。In the documentation, routed event topics cross-reference similar routed events with alternative routing strategies if such routed events exist, and sections in the managed reference pages clarify the routing strategy of each routed event.

ペアになった WPFWPF 入力イベントを実装する場合、マウス ボタンを押すなどの入力による 1 つのユーザー操作で、ペアになった両方のルーティング イベントが順次発生するようにします。WPFWPF input events that come in pairs are implemented so that a single user action from input, such as a mouse button press, will raise both routed events of the pair in sequence. まず、トンネル イベントが発生し、その経路をたどります。First, the tunneling event is raised and travels its route. 次に、バブル イベントが発生し、その経路をたどります。Then the bubbling event is raised and travels its route. この2つのイベントは、同じイベントデータインスタンスを同じように共有します。これは、バブルイベントを発生させる実装クラスの RaiseEvent メソッド呼び出しが、トンネルイベントからイベントデータをリッスンし、新しい発生イベントでそのイベントを再利用するためです。The two events literally share the same event data instance, because the RaiseEvent method call in the implementing class that raises the bubbling event listens for the event data from the tunneling event and reuses it in the new raised event. トンネル イベントのハンドラーを持つリスナーは、ルーティング イベントを処理済みとしてマークする機会を最初に与えられます (最初がクラス ハンドラーで、その次がインスタンス ハンドラーです)。Listeners with handlers for the tunneling event have the first opportunity to mark the routed event handled (class handlers first, then instance handlers). トンネル経路上の要素がルーティング イベントを処理済みとしてマークした場合、処理済みイベントのデータがバブル イベントに送信され、同等のバブル入力イベントにアタッチされた標準のハンドラーは呼び出されません。If an element along the tunneling route marked the routed event as handled, the already-handled event data is sent on for the bubbling event, and typical handlers attached for the equivalent bubbling input events will not be invoked. 外部からは、処理済みのバブル イベントが発生しなかったように見えます。To outward appearances it will be as if the handled bubbling event has not even been raised. この処理動作が便利なのは、コントロールの複合化の場合です。この場合、すべてのヒット テスト ベースの入力イベントまたはフォーカス ベースの入力イベントが、コントロールの複合部分ではなく最終的なコントロールから報告される必要があるためです。This handling behavior is useful for control compositing, where you might want all hit-test based input events or focus-based input events to be reported by your final control, rather than its composite parts. 最終的なコントロール要素は、複合のルート近くにあるため、トンネル イベントを最初にクラス処理し、コントロール クラスをサポートするコードの一部としてそのルーティング イベントをコントロール固有のイベントで "置き換える" 機会があります。The final control element is closer to the root in the compositing, and therefore has the opportunity to class handle the tunneling event first and perhaps to "replace" that routed event with a more control-specific event, as part of the code that backs the control class.

入力イベント処理のしくみを説明するため、次の入力イベント例について考えます。As an illustration of how input event processing works, consider the following input event example. 次のツリーの図は、leaf element #2PreviewMouseDownMouseDown イベントの両方のソースであることを示しています。In the following tree illustration, leaf element #2 is the source of both a PreviewMouseDown and then a MouseDown event:

イベント ルーティング ダイアグラム

次の順序でイベントが処理されます。The order of event processing is as follows:

  1. ルート要素の PreviewMouseDown (トンネル)。PreviewMouseDown (tunnel) on root element.

  2. 中間要素 #1 の PreviewMouseDown (トンネル)。PreviewMouseDown (tunnel) on intermediate element #1.

  3. ソース要素 #2 の PreviewMouseDown (トンネル)。PreviewMouseDown (tunnel) on source element #2.

  4. ソース要素 #2 の MouseDown (バブル)。MouseDown (bubble) on source element #2.

  5. 中間要素 #1 の MouseDown (バブル)。MouseDown (bubble) on intermediate element #1.

  6. ルート要素の MouseDown (バブル)。MouseDown (bubble) on root element.

ルーティング イベント ハンドラー デリゲートは、2 つのオブジェクトへの参照を提供します。その 2 つは、イベントを発生したオブジェクトと、ハンドラーが呼び出されたオブジェクトです。A routed event handler delegate provides references to two objects: the object that raised the event and the object where the handler was invoked. ハンドラーが呼び出されたオブジェクトは、sender パラメーターによって報告されるオブジェクトです。The object where the handler was invoked is the object reported by the sender parameter. イベントが最初に発生したオブジェクトは、イベントデータの Source プロパティによって報告されます。The object where the event was first raised is reported by the Source property in the event data. ルーティングイベントは、同じオブジェクトでも発生して処理できます。この場合、senderSource は同じです (これは、イベント処理の例の一覧にある手順3と4の場合)。A routed event can still be raised and handled by the same object, in which case sender and Source are identical (this is the case with Steps 3 and 4 in the event processing example list).

トンネルとバブルにより、親要素は、Source がその子要素の1つである入力イベントを受け取ります。Because of tunneling and bubbling, parent elements receive input events where the Source is one of their child elements. ソース要素の内容を把握することが重要な場合は、Source プロパティにアクセスして、ソース要素を識別できます。When it is important to know what the source element is, you can identify the source element by accessing the Source property.

通常、入力イベントが Handledとしてマークされると、それ以降のハンドラーは呼び出されません。Usually, once the input event is marked Handled, further handlers are not invoked. 一般に、入力イベントが意味することをアプリケーション固有の方法で論理処理するハンドラーが呼び出されたら、直ちに入力イベントを処理済みとしてマークする必要があります。Typically, you should mark input events as handled as soon as a handler is invoked that addresses your application-specific logical handling of the meaning of the input event.

Handled 状態に関するこの一般的なステートメントの例外として、イベントデータの Handled の状態を意図的に無視するように登録されている入力イベントハンドラーは、どちらのルートでも呼び出されます。The exception to this general statement about Handled state is that input event handlers that are registered to deliberately ignore Handled state of the event data would still be invoked along either route. 詳細については、「プレビュー イベント」または「ルーティング イベントの処理済みとしてのマーキング、およびクラス処理」を参照してください。For more information, see Preview Events or Marking Routed Events as Handled, and Class Handling.

トンネル イベントとバブル イベント間の共有イベント データ モデルの概念も、トンネル イベントとバブル イベントの順次発生の概念も、すべてのルーティング イベントに当てはまるとは限りません。The shared event data model between tunneling and bubbling events, and the sequential raising of first tunneling then bubbling events, is not a concept that is generally true for all routed events. そうした動作は、ペアになった入力イベントを WPFWPF 入力デバイスがどのように発生させ接続するよう選択するかによって、個別に実装されます。That behavior is specifically implemented by how WPFWPF input devices choose to raise and connect the input event pairs. 独自の入力イベントの実装は高度なシナリオですが、独自の入力イベントでそうしたモデルを採用することもできます。Implementing your own input events is an advanced scenario, but you might choose to follow that model for your own input events also.

一部のクラスでは、特定の入力イベントをクラス処理します。通常、その目的は、ユーザーによる特定の入力イベントの意味をそのコントロール内で再定義して、新しいイベントを発生させることです。Certain classes choose to class-handle certain input events, usually with the intent of redefining what a particular user-driven input event means within that control and raising a new event. 詳細については、「ルーティング イベントの処理済みとしてのマーキング、およびクラス処理」を参照してください。For more information, see Marking Routed Events as Handled, and Class Handling.

入力と一般的なアプリケーション シナリオにおける入力とイベントの対話方法の詳細については、「入力の概要」を参照してください。For more information on input and how input and events interact in typical application scenarios, see Input Overview.

EventSetter と EventTriggerEventSetters and EventTriggers

スタイルでは、EventSetterを使用して、事前に宣言された XAMLXAML イベント処理構文をマークアップに含めることができます。In styles, you can include some pre-declared XAMLXAML event handling syntax in the markup by using an EventSetter. そのスタイルを適用すると、参照されているハンドラーが、スタイルが適用されるインスタンスに追加されます。When the style is applied, the referenced handler is added to the styled instance. EventSetter は、ルーティングイベントに対してのみ宣言できます。You can declare an EventSetter only for a routed event. 次に例を示します。The following is an example. ここで参照されている b1SetColor メソッドは、分離コード ファイル内にあります。Note that the b1SetColor method referenced here is in a code-behind file.

<StackPanel
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="SDKSample.EventOvw2"
  Name="dpanel2"
  Initialized="PrimeHandledToo"
>
  <StackPanel.Resources>
    <Style TargetType="{x:Type Button}">
      <EventSetter Event="Click" Handler="b1SetColor"/>
    </Style>
  </StackPanel.Resources>
  <Button>Click me</Button>
  <Button Name="ThisButton" Click="HandleThis">
    Raise event, handle it, use handled=true handler to get it anyway.
  </Button>
</StackPanel>

ここで得られる利点は、スタイルには、アプリケーションの任意のボタンに適用される可能性があるその他の多くの情報が含まれている可能性があります。また、EventSetter をそのスタイルの一部にすることで、マークアップレベルでもコードの再利用が促進されます。The advantage gained here is that the style is likely to contain a great deal of other information that could apply to any button in your application, and having the EventSetter be part of that style promotes code reuse even at the markup level. また、EventSetter は、一般的なアプリケーションやページマークアップからさらに一歩離れたハンドラーのメソッド名を抽象化します。Also, an EventSetter abstracts method names for handlers one step further away from the general application and page markup.

WPFWPF のルーティングイベント機能とアニメーション機能を組み合わせたもう1つの特殊な構文は、EventTriggerです。Another specialized syntax that combines the routed event and animation features of WPFWPF is an EventTrigger. EventSetterと同様に、EventTriggerにはルーティングイベントのみを使用できます。As with EventSetter, only routed events may be used for an EventTrigger. 通常、EventTrigger はスタイルの一部として宣言されますが、EventTriggerTriggers コレクションの一部として、または ControlTemplate内で、ページレベルの要素で宣言することもできます。Typically, an EventTrigger is declared as part of a style, but an EventTrigger can also be declared on page-level elements as part of the Triggers collection, or in a ControlTemplate. EventTrigger を使用すると、ルーティングイベントが、そのイベントの EventTrigger を宣言するルート内の要素に到達するたびに実行される Storyboard を指定できます。An EventTrigger enables you to specify a Storyboard that runs whenever a routed event reaches an element in its route that declares an EventTrigger for that event. イベントを処理するだけでなく、既存のストーリーボードを起動させる EventTrigger の利点は、EventTrigger がストーリーボードとその実行時の動作をより適切に制御できることです。The advantage of an EventTrigger over just handling the event and causing it to start an existing storyboard is that an EventTrigger provides better control over the storyboard and its run-time behavior. 詳細については、「開始後のストーリーボードをイベント トリガーを使用して制御する」を参照してください。For more information, see Use Event Triggers to Control a Storyboard After It Starts.

ルーティング イベントの詳細More About Routed Events

このトピックの主な目的は、ルーティング イベントの基本概念を説明し、さまざまな基本要素や基本コントロール内の既存のルーティング イベントに応答する方法とタイミングについて解説することです。This topic mainly discusses routed events from the perspective of describing the basic concepts and offering guidance on how and when to respond to the routed events that are already present in the various base elements and controls. しかし、独自のルーティング イベントを、特殊なイベント データ クラスやデリゲートなど、必要な支援機能すべてと共に、カスタム クラスに作成することもできます。However, you can create your own routed event on your custom class along with all the necessary support, such as specialized event data classes and delegates. ルーティングイベントの所有者は任意のクラスにすることができますが、ルーティングイベントはによって発生し、UIElement または ContentElement 派生クラスによって処理される必要があります。The routed event owner can be any class, but routed events must be raised by and handled by UIElement or ContentElement derived classes in order to be useful. カスタム イベントの詳細については、「カスタム ルーティング イベントを作成する」を参照してください。For more information about custom events, see Create a Custom Routed Event.

関連項目See also