イベントとルーティング イベントの概要

重要な API

Windows ランタイム アプリで、プログラミング言語に C#、Visual Basic、または Visual C++ コンポーネント拡張機能 (C++/CX) を、UI 定義に XAML を使う場合のイベントのプログラミングの概念について説明します。 イベントのハンドラーは、UI 要素の宣言の一部として XAML で割り当てることも、コードで追加することもできます。 Windows ランタイムは "ルーティング イベント" をサポートしており、特定の入力イベントとデータ イベントを、そのイベントを発生させたオブジェクト以外のオブジェクトで処理できます。 ルーティング イベントは、コントロール テンプレートを定義する際や、ページまたはレイアウト コンテナーを使う際に役立ちます。

プログラミング概念としてのイベント

一般に、Windows ランタイム アプリをプログラミングするときのイベントの概念は、最も一般的なプログラミング言語のイベント モデルに似ています。 Microsoft .NET または C++ のイベントを既に操作する方法がわかっている場合は、ヘッド スタートを行います。 ただし、ハンドラーのアタッチなど、一部の基本的なタスクを実行する場合、イベント モデルの概念について詳しく知る必要はありません。

プログラミング言語として C#、Visual Basic、または C++/CX を使用する場合、UI はマークアップ (XAML) で定義されます。 XAML マークアップ構文では、マークアップ要素とランタイム コード エンティティ間でイベントを接続する原則の一部は、ASP.NET や HTML5 などの他の Web テクノロジと類似しています。

XAML で定義された UI のランタイム ロジックを提供するコードは、多くの場合、"コード ビハインド" またはコード ビハインド ファイルと呼ばれます。 Microsoft Visual Studio ソリューション ビューでは、XAML ページに対する依存する分離コード ファイルと入れ子になったファイルの関係がグラフィカルに表示されます。

Button.Click: イベントと XAML の概要

Windows ランタイム アプリの最も一般的なプログラミング タスクの 1 つは、UI へのユーザー入力を取得することです。 たとえば、UI にボタンがあり、ユーザーがクリックして情報を送信したり、状態を変更したりする必要があります。

XAML を生成して、Windows ランタイム アプリの UI を定義します。 この XAML は、通常、Visual Studio のデザイン サーフェイスからの出力です。 また、プレーンテキスト エディターまたはサード パーティの XAML エディターで XAML を記述することもできます。 その XAML を生成するときに、個々の UI 要素のイベント ハンドラーを同時にワイヤリングし、その UI 要素のプロパティ値を確立する他のすべての XAML 属性を定義できます。

XAML でイベントをワイヤリングするには、既に定義したハンドラー メソッド、または分離コード内で後で定義するハンドラー メソッドの文字列形式の名前を指定します。 たとえば、この XAML では、他のプロパティ (x:Name 属性コンテンツ) が属性として割り当てられたButton オブジェクトを定義し、ShowUpdatesButton_Click という名前のメソッドを参照することによって、ボタンの Click イベントのハンドラーをワイヤリングします。

<Button x:Name="showUpdatesButton"
  Content="{Binding ShowUpdatesText}"
  Click="ShowUpdatesButton_Click"/>

ヒントイベント ワイヤリン はプログラミング用語です。 これは、イベントの発生時に名前付きハンドラー メソッドを呼び出す必要があることを示すプロセスまたはコードを指します。 ほとんどの手続き型コード モデルでは、イベント ワイヤリングは、イベントとメソッドの両方に名前を付ける暗黙的または明示的な "AddHandler" コードであり、通常はターゲット オブジェクト インスタンスが関係します。 XAML では、"AddHandler" は暗黙的であり、イベント ワイヤリングは、イベントにオブジェクト要素の属性名として名前を付け、ハンドラーにその属性の値として名前を付けることだけで構成されます。

実際のハンドラーは、アプリのすべてのコードと分離コードに使用するプログラミング言語で記述します。 この属性 Click="ShowUpdatesButton_Click"を使用して、XAML がマークアップ コンパイルおよび解析されるときに、IDE のビルド アクションの XAML マークアップ コンパイル ステップと、アプリの読み込み時の最終的な XAML 解析の両方が、アプリのコードの一部として名前付けされた ShowUpdatesButton_Click メソッドを見つけることができるコントラクトを作成しました。 ShowUpdatesButton_Click は、Click イベントのハンドラーに互換性のあるメソッド シグネチャ (デリゲートに基づく) を実装するメソッドである必要があります。 たとえば、このコードは ShowUpdatesButton_Click ハンドラーを定義します。

private void ShowUpdatesButton_Click (object sender, RoutedEventArgs e) 
{
    Button b = sender as Button;
    //more logic to do here...
}
Private Sub ShowUpdatesButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
    Dim b As Button = CType(sender, Button)
    '  more logic to do here...
End Sub
void winrt::MyNamespace::implementation::BlankPage::ShowUpdatesButton_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e)
{
    auto b{ sender.as<Windows::UI::Xaml::Controls::Button>() };
    // More logic to do here.
}
void MyNamespace::BlankPage::ShowUpdatesButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) 
{
    Button^ b = (Button^) sender;
    //more logic to do here...
}

この例では、ShowUpdatesButton_Clickメソッドは RoutedEventHandler デリゲートに基づいています。 Click メソッドの構文にこのデリゲートが指定されているため、このデリゲートを使います。

ヒント Visual Studio では、XAML の編集中に、簡単にイベント ハンドラーに名前を付けたり、ハンドラー メソッドを定義したりできます。 XAML テキスト エディターでイベントの属性名を指定する場合は、Microsoft IntelliSense リストが表示されるまでしばらく待ちます。 一覧から <[新しいイベント ハンドラー]> をクリックすると、Microsoft Visual Studio は要素の x:Name (または型名)、イベント名、および数値サフィックスに基づいてメソッド名を提案します。 その後、選択したイベント ハンドラー名を右クリックし、[イベント ハンドラーへ移動] をクリックします。 これにより、XAML ページの分離コード ファイルのコード エディター ビューに表示されているように、新しく挿入されたイベント ハンドラー定義に直接移動します。 イベント ハンドラーには、sender パラメーターやイベントで使用されるイベント データ クラスなどの正しいシグネチャが既にあります。 また、正しいシグネチャを持つハンドラー メソッドが分離コード内に既に存在する場合、そのメソッドの名前が <[新しいイベント ハンドラー]> オプションと共にオートコンプリート ドロップダウンに表示されます。 IntelliSense リスト項目をクリックする代わりに、ショートカットとして Tab キーを使うこともできます。

イベント ハンドラーの定義

UI 要素であり、XAML で宣言されているオブジェクトの場合、イベント ハンドラー コードは、XAML ページの分離コードとして機能する部分クラスで定義されます。 イベント ハンドラーは、XAML に関連付けられている部分クラスの一部として記述するメソッドです。 これらのイベント ハンドラーは、特定のイベントが使用するデリゲートに基づいています。 イベント ハンドラー メソッドは、パブリックまたはプライベートにすることができます。 XAML で作成されたハンドラーとインスタンスは最終的にコード生成によって結合されるため、プライベート アクセスが機能します。 一般に、イベント ハンドラー メソッドをクラス内でプライベートにすることをお勧めします。

C++ のイベント ハンドラーは、部分クラスで定義するのではなく、private のクラス メンバーとしてヘッダーで宣言します。 C++ プロジェクトのビルド アクションは、C++ の XAML 型システムと分離コード モデルをサポートするコードの生成を処理します。

sender パラメーターとイベント データ

イベントに対して記述するハンドラーは、ハンドラーが呼び出されるケースごとに入力として使用できる 2 つの値にアクセスできます。 最初の値は sender で、ハンドラーがアタッチされているオブジェクトへの参照です。 sender パラメーターは、基本オブジェクト型として型指定されます。 一般的な手法は、sender をより正確な型にキャストすることです。 この手法は、sender オブジェクト自体の状態をチェックまたは変更する必要がある場合に役立ちます。 通常、独自のアプリ設計に基づいて、 ハンドラーのアタッチ先やその他の設計仕様をもとに sender を安全にキャストできる型がわかります

2 つ目の値はイベント データで、通常は構文定義で e パラメーターとして表示されます。 使用できるイベント データのプロパティを確認するには、処理する特定のイベントに割り当てられているデリゲートの e パラメーターを確認し、Visual Studio で IntelliSense またはオブジェクト ブラウザーを使用します。 または、Windows ランタイムリファレンス ドキュメントを使用することもできます。

一部のイベントでは、イベント データの特定のプロパティ値は、イベントが発生したことを知るのと同じくらい重要です。 これは、入力イベントに特に当てはまります。 ポインター イベントの場合、イベントが発生したときのポインターの位置が重要な場合があります。 キーボード イベントの場合、キーを押すと KeyDown イベントと KeyUp イベントが発生します。 ユーザーが押したキーを特定するには、イベント ハンドラーで使用できる KeyRoutedEventArgs にアクセスする必要があります。 詳しくは、[キーボード インタラクション][ポインター入力の処理] をご覧ください。 入力イベントと入力シナリオには、ポインター イベントのポインター キャプチャ、キーボード イベントの修飾子キーとプラットフォーム キー コードなど、このトピックでは説明されていない追加の考慮事項があります。

非同期パターンを使用するイベント ハンドラー

場合によっては、イベント ハンドラー内で非同期パターンを使用する API を使用する必要があります。 たとえば、AppBarButton を使用してファイル ピッカーを表示し、操作することができます。 ただし、ファイル ピッカー API の多くは非同期です。 これらは非同期/待機可能スコープ内で呼び出す必要があり、コンパイラはこれを強制します。 そのため、ハンドラーが asyncvoid になるように、非同期キーワード をイベント ハンドラーに追加します。 これで、イベント ハンドラーは非同期/待機可能な呼び出しを行うことができます。

非同期パターンを使用したユーザー操作イベント処理の例については、「ファイル アクセスとピッカー」(「C# または Visual Basic を使用した最初の Windows ランタイム アプリの作成」シリーズの一部) を参照してください。 「C での非同期 API の呼び出し」も参照してください。

コードにイベント ハンドラーを追加する

XAML は、イベント ハンドラーをオブジェクトに割り当てる唯一の方法ではありません。 XAML で使用できないオブジェクトを含め、コード内の特定のオブジェクトにイベント ハンドラーを追加するには、言語固有の構文を使用してイベント ハンドラーを追加できます。

C# では、構文で += 演算子を使用します。 ハンドラーを登録する場合は、演算子の右側にあるイベント ハンドラー メソッド名を参照します。

コードを使用してランタイム UI に表示されるオブジェクトにイベント ハンドラーを追加する場合、一般的な方法は、オブジェクトの有効期間イベントまたはコールバック ( LoadedOnApplyTemplate など) に応答してこのようなハンドラーを追加し、関連するオブジェクトのイベント ハンドラーが実行時にユーザーが開始するイベントに対応できるようにすることです。 この例では、ページ構造の XAML アウトラインを示し、オブジェクトにイベント ハンドラーを追加するための C# 言語構文を提供します。

<Grid x:Name="LayoutRoot" Loaded="LayoutRoot_Loaded">
  <StackPanel>
    <TextBlock Name="textBlock1">Put the pointer over this text</TextBlock>
...
  </StackPanel>
</Grid>
void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
{
    textBlock1.PointerEntered += textBlock1_PointerEntered;
    textBlock1.PointerExited += textBlock1_PointerExited;
}

これには、より冗長な形式の構文もあります。 2005 年、C# はデリゲート推論と呼ばれる機能が追加されました。これにより、コンパイラは新しいデリゲート インスタンスを推論できるようになり、以前のより単純な構文が有効になります。 詳細構文は機能的には前の例と同じですが、登録する前に新しいデリゲート インスタンスを明示的に作成するため、デリゲート推論は利用されません。 この明示的な構文はあまり一般的ではありませんが、一部のコード例では引き続き表示される場合があります。

void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
{
    textBlock1.PointerEntered += new PointerEventHandler(textBlock1_PointerEntered);
    textBlock1.PointerExited += new MouseEventHandler(textBlock1_PointerExited);
}

Visual Basic 構文には 2 つの可能性があります。 1 つは、C# 構文を並列化し、ハンドラーをインスタンスに直接アタッチすることです。 これには、AddHandler キーワード (keyword)と、ハンドラー メソッド名を逆参照する AddressOf 演算子も必要です。

Visual Basic 構文のもう 1 つのオプションは、イベント ハンドラーでHandles キーワードを使用することです。 この手法は、読み込み時にハンドラーがオブジェクトに存在し、オブジェクトの有効期間にわたって存続することが期待される場合に適しています。 XAML で定義されているオブジェクトで Handles を使用するには、Name / x:Name を指定する必要があります。 この名前は、Handles 構文の Instance.Event 部分に必要なインスタンス修飾子になります。 この場合、他のイベント ハンドラーのアタッチを開始するためにオブジェクトの有効期間ベースのイベント ハンドラーは必要ありません。Handles 接続は、XAML ページをコンパイルするときに作成されます。

Private Sub textBlock1_PointerEntered(ByVal sender As Object, ByVal e As PointerRoutedEventArgs) Handles textBlock1.PointerEntered
' ...
End Sub

Visual Studio とその XAML デザイン サーフェイスでは、一般に、Handles キーワードの代わりにインスタンス処理の手法が推奨されます。 これは、XAML でイベント ハンドラーのワイヤリングを確立することは一般的な設計者と開発者のワークフローの一部であり、Handles キーワード手法は XAML でのイベント ハンドラーの接続と互換性がないためです。

C++/CX でも += 構文が使われますが、C# の基本的な形式とは次のような違いがあります。

  • デリゲート推論は存在しないため、デリゲート インスタンスにref new を使用する必要があります。
  • デリゲート コンストラクターには 2 つのパラメーターがあり、最初のパラメーターとしてターゲット オブジェクトが必要です。 通常は、 this.を指定 します。
  • デリゲート コンストラクターは、メソッド アドレスを 2 番目のパラメーターとして必要とするため、& 参照演算子はメソッド名の前に置きます。
textBlock1().PointerEntered({this, &MainPage::TextBlock1_PointerEntered });
textBlock1->PointerEntered += 
ref new PointerEventHandler(this, &BlankPage::textBlock1_PointerEntered);

コード内のイベント ハンドラーの削除

コードでイベント ハンドラーを追加した場合でも、通常はコード内のイベント ハンドラーを削除する必要はありません。 ページやコントロールなどのほとんどのWindows ランタイムオブジェクトのオブジェクトの有効期間の動作では、オブジェクトがメイン ウィンドウとそのビジュアル ツリーから切断されるとオブジェクトが破棄され、デリゲート参照も破棄されます。 .NET はガベージ コレクションを通じてこれを行い、C++/CX を使用するWindows ランタイムでは、既定で弱い参照が使用されます。

イベント ハンドラーを明示的に削除する場合はまれです。 これには以下が含まれます。

  • 静的イベント用に追加したハンドラー。従来の方法ではガベージ コレクションを行うことができません。 Windows ランタイム API の静的イベントの例として、CompositionTarget クラスと Clipboard クラスのイベントがあります。
  • ハンドラーの削除のタイミングを即時にするコードをテストするか、実行時にイベントの新旧イベント ハンドラーを交換するコードをテストします。
  • カスタム 削除 アクセサーの実装。
  • カスタム静的イベント。
  • ページ ナビゲーションのハンドラー。

FrameworkElement.Unloaded または Page.NavigatedFrom は、他のイベントのハンドラーを削除するために使用できるように、状態管理とオブジェクトの有効期間内で適切な位置にあるイベント トリガーです。

たとえば、このコードを使うと、ターゲット オブジェクト textBlock1 から textBlock1_PointerEntered という名前のイベント ハンドラーを削除できます。

textBlock1.PointerEntered -= textBlock1_PointerEntered;
RemoveHandler textBlock1.PointerEntered, AddressOf textBlock1_PointerEntered

イベントが XAML 属性を通じて追加された場合、つまり生成されたコードにハンドラーが追加された場合のハンドラーを削除することもできます。 ハンドラーがアタッチされた要素に Name 値を指定した場合は、後でコードのオブジェクト参照が提供されるため、これを行う方が簡単です。ただし、オブジェクトに Name がない場合に必要なオブジェクト参照を見つけるためにオブジェクト ツリーを辿ることもできます。

C++/CX でイベント ハンドラーを削除する必要がある場合、+= イベント ハンドラー登録の戻り値から取得した登録トークンが必要です。 これは、C++/CX 構文の -= 登録解除の右側に使用する値がトークンであるためです (メソッド名ではない)。 C++/CX の場合、C++/CX で生成されたコードはトークンを保存しないため、XAML 属性として追加されたハンドラーを削除できません。

ルーティング イベント

C#、Microsoft Visual Basic、または C++/CX を使用したWindows ランタイムは、ほとんどの UI 要素に存在する一連のイベントに対するルーティング イベントの概念をサポートしています。 これらのイベントは、入力とユーザー インタラクション シナリオ用であり、UIElement 基本クラスに実装されます。 ルーティング イベントである入力イベントの一覧を次に示します。

ルーティング イベントは、子オブジェクトからオブジェクト ツリー内の連続する各親オブジェクトに渡される (ルーティングされる) 可能性があるイベントです。 UI の XAML 構造は、このツリーを近似し、そのツリーのルートが XAML のルート要素になります。 オブジェクト ツリーにはプロパティ要素タグなどの XAML 言語機能が含まれていないため、実際のオブジェクト ツリーは XAML 要素の入れ子とは多少異なる場合があります。 ルーティング イベントは、イベントを発生する XAML オブジェクト要素の子要素から、それを含む親オブジェクト要素に向かってバブリングすると考えることができます。 イベントとそのイベント データは、イベント ルートに沿って複数のオブジェクトで処理できます。 どの要素にもハンドラーがない場合、ルート要素に到達するまでルートが継続する可能性があります。

動的 HTML (DHTML) や HTML5 などの Web テクノロジに精通している方は、バブリングイベントの概念について既に理解している可能性があります。

ルーティング イベントがイベント ルートを通過すると、アタッチされたイベント ハンドラーはすべて、イベント データの共有インスタンスにアクセスします。 そのため、いずれかのイベント データがハンドラーによって書き込み可能な場合、イベント データに加えられた変更は次のハンドラーに渡され、イベントの元のイベント データを表さなくなる可能性があります。 イベントにルーティング イベントの動作がある場合、リファレンス ドキュメントにはルーティング動作に関する注釈またはその他の表記が含まれます。

RoutedEventArgsOriginalSource プロパティ

イベントがイベント ルートをバブルアップすると、sender はイベント発生オブジェクトと同じオブジェクトではなくなります。 代わりに、 sender は、呼び出されるハンドラーがアタッチされているオブジェクトです。

場合によっては、 sender には興味がなく、代わりに、ポインター イベントが発生したときにポインターが存在する可能性のある子オブジェクトの特定、またはユーザーがキーボードのキーを押したときに大きな UI 内のどのオブジェクトがフォーカスを保持したかなどの情報に興味があることがあります。 このような場合は、OriginalSource プロパティの値を使用できます。 ルート上のすべてのポイントで、 OriginalSource は、ハンドラーがアタッチされているオブジェクトではなく、イベントを発生させた元のオブジェクトを報告します。 ただし、UIElement 入力イベントの場合、その元のオブジェクトは、多くの場合、ページ レベルの UI 定義 XAML ですぐには表示されないオブジェクトです。 代わりに、元のソース オブジェクトがコントロールのテンプレート化された部分である可能性があります。 たとえば、ユーザーが Button の端にポインターを合わせた場合、ほとんどのポインター イベントでは、OriginalSourceButton 自体ではなく、 Template 内の Border テンプレート パーツになります。

ヒント 入力イベントのバブル ルーティングは、テンプレート化されたコントロールを作成する場合に特に便利です。 テンプレートを持つコントロールはどれも、そのコンシューマーによって適用される新しいテンプレートを持つことができます。 作業テンプレートを再作成しようとしているコンシューマは、既定のテンプレートで宣言されているイベント処理を意図せずに削除してしまう可能性があります。 クラス定義の OnApplyTemplate オーバーライドの一部としてハンドラーをアタッチすることで、コントロール レベルのイベント処理を提供できます。 その後、インスタンス化時にコントロールのルートまでバブルアップする入力イベントをキャッチできます。

Handled プロパティ

特定のルーティング イベントのいくつかのイベント データ クラスには、Handled という名前のプロパティが含まれています。 例については、「PointerRoutedEventArgs.Handled」、「KeyRoutedEventArgs.Handled」、「DragEventArgs.Handled」を参照してください。 いずれの場合も、 Handled は設定可能なブール型プロパティです。

Handled プロパティを true に設定すると、イベント システムの動作に影響します。 Handledtrue の場合、ほとんどのイベント ハンドラーのルーティングは停止します。イベントは、その特定のイベント ケースを他のアタッチされたハンドラーに通知するためにルートに沿って続行されません。 このイベントのコンテキストにおいて "処理済" が何を意味するか、そしてアプリがそれにどのように応答するかはユーザー次第です。 基本的に、Handled は、イベントの発生がコンテナにバブリングする必要がなく、必要なことはアプリのロジックが処理することをアプリ コードで宣言できるようにする単純なプロトコルです。 ただし、逆に、組み込みのシステムまたはコントロールの動作を可能にするためにバブリングする必要があるイベントを処理していないことに注意する必要があります。たとえば、選択コントロールのパーツまたは項目内で低レベルのイベントを処理すると、悪影響を及ぼす可能性があります。  選択コントロールは、選択内容を変更する必要があることを知るために入力イベントを探している可能性があります。

すべてのルーティング イベントがこの方法でルートをキャンセルできるわけではありません。イベントには Handled プロパティがないため、それがわかります。 たとえば、GotFocus LostFocus はバブルを実行しますが、常にルートまでバブルを発生させ、そのイベント データ クラスには、その動作に影響を与える可能性のある Handled プロパティがありません。

コントロール内の入力イベント ハンドラー

特定のWindows ランタイム コントロールでは、内部的に入力イベントに Handled の概念を使用することがあります。 これにより、ユーザー コードが入力イベントを処理できないため、入力イベントがまったく発生しないように見える可能性があります。 たとえば、Button クラスには、一般的な入力イベント PointerPressed を意図的に処理するロジックが含まれています。 これは、ボタンがポインターを押した入力によって開始される Click イベントと、フォーカス時にボタンを呼び出すことができる Enter キーなどのキーの処理などの他の入力モードによって発生するためです。 Button のクラス設計の目的上、生の入力イベントは概念的に処理され、ユーザー コードなどのクラス コンシューマーは代わりにコントロール関連の Click イベントと対話できます。 Windows ランタイム API リファレンスの特定のコントロール クラスに関するトピックでは、多くの場合、クラスが実装するイベント処理の動作に注意してください。 場合によっては、OnEvent メソッドをオーバーライドすることで動作を変更できます。 たとえば、Control.OnKeyDown をオーバーライドすることで、TextBox 派生クラスがキー入力にどのように反応するかを変更できます。

既に処理されているルーティング イベントのハンドラーの登録

前述のように、Handledtrue に設定すると、ほとんどのハンドラーが呼び出されなくなります。 ただし、AddHandler メソッドは、ルートの前の他のハンドラーが共有イベント データで Handledtrue に設定している場合でも、ルートに対して常に呼び出されるハンドラーをアタッチできる手法を提供します。 この手法は、使用しているコントロールが内部合成またはコントロール固有のロジックでイベントを処理した場合に便利です。 ただし、コントロール インスタンスまたはアプリ UI から応答する必要があります。 ただし、この手法は Handled の目的と矛盾し、コントロールの意図した操作を中断する可能性があるため、注意して使用してください。

識別子は AddHandler メソッドの必須入力であるため、AddHandler イベント処理手法を使用できるのは、対応するルーティング イベント識別子を持つルーティング イベントだけです。 使用可能なルーティング イベント識別子を持つイベントのリストについては、AddHandler のリファレンス ドキュメントを参照してください。 ほとんどの場合、これは前に示したルーティング イベントのリストと同じです。 例外は、リストの最後の 2 つである GotFocusLostFocus にはルーティング イベント識別子がないため、これらに対して AddHandler を使用することはできません。

ビジュアル ツリーの外部のルーティング イベント

特定のオブジェクトは、概念的には、メインビジュアルの上にオーバーレイを持つようなプライマリ ビジュアル ツリーとの関係に参加します。 これらのオブジェクトは、すべてのツリー要素をビジュアル ルートに接続する通常の親子関係の一部ではありません。 これは、表示されるPopupまたはToolTipに当てはまります。 Popup または ToolTip からのルーティング イベントを処理する場合は、Popup または ToolTip 要素自体ではなく、Popup または ToolTip 要素内にある特定の UI 要素にハンドラーを配置します。 Popup または ToolTip コンテンツに対して実行される合成内のルーティングに依存しないでください。 これは、ルーティング イベントのイベント ルーティングは、メインビジュアル ツリーに沿ってのみ機能するためです。 Popup または ToolTip は、補助 UI 要素の親とは見なされず、入力イベントのキャプチャ領域として Popup の既定の背景のようなものを使用しようとしても、ルーティング イベントを受け取ることはありません。

ヒット テストと入力イベント

UI 内で要素がマウス、タッチ、スタイラスの入力に表示されるかどうか、およびどこに表示されるかを判断することは、ヒット テストと呼ばれます。 タッチ アクションの場合や、タッチ アクションの結果となる操作固有のイベントや操作イベントの場合、イベント ソースとしてアクションに関連付けられているイベントを発生させるには、要素をヒット テストで表示する必要があります。 それ以外の場合、アクションは、その入力と対話できるビジュアル ツリー内の基になる要素または親要素に要素を渡します。 ヒット テストに影響を与える要因はいくつかありますが、特定の要素が IsHitTestVisible プロパティをチェックすることで入力イベントを発生できるかどうかを判断できます。 このプロパティは、要素が次の 条件を満たしている場合にのみ true を返します。

  • 要素の Visibility プロパティ値は Visible です。
  • 要素の Background または Fill プロパティの値が null ではありません。 nullBrush 値を指定すhると、透明になり、ヒット テストが非表示になります。 (要素を透明にしながらテスト可能にするには、null の代わりにTransparent ブラシを使用します。)

注:BackgroundFillUIElement によって定義されず、代わりに Control Shape などの別の派生クラスによって定義されます。 ただし、前景プロパティおよび背景プロパティに使用するブラシの意味は、どのサブクラスがプロパティを実装していても、ヒット テストと入力イベントでも同じです。

  • 要素がコントロールの場合、その IsEnabled プロパティ値は true. である必要があります。
  • 要素には、レイアウト内の実際のディメンションが必要です。 ActualHeightActualWidth が 0 である要素では、入力イベントは発生しません。

一部のコントロールには、ヒット テスト用の特別なルールがあります。 たとえば、TextBlock には Background プロパティはありませんが、そのサイズの領域全体でヒット テストが可能です Image コントロールと MediaElement コントロールは、表示されるメディア ソース ファイル内のアルファ チャネルなどの透明なコンテンツに関係なく、定義された四角形の寸法に対してヒット テスト可能です。 WebView コントロールには、ホストされた HTML によって入力を処理し、スクリプト イベントを発生できるため、特殊なヒット テスト動作があります。

ほとんどの Panel クラスと Border は、独自のバックグラウンドではヒット テストできませんが、含まれている要素からルーティングされるユーザー入力イベントを引き続き処理できます。

要素がヒット テスト可能かどうかに関係なく、どの要素がユーザー入力イベントと同じ位置にあるかを判断できます。 これを行うには、FindElementsInHostCoordinates メソッドを呼び出します。 名前が示すように、このメソッドは、指定されたホスト要素に対する相対位置にある要素を検索します。 ただし、適用された変換とレイアウトの変更は、要素の相対座標系を調整できるため、特定の場所にある要素に影響を与えます。

コマンド実行

ごく一部の UI 要素がコマンド処理をサポートしています。 コマンド実行では、基になる実装で入力関連のルーティング イベントを使用し、1 つのコマンド ハンドラーを呼び出すことによって、関連する UI 入力 (特定のポインター アクション、特定のアクセラレータ キー) の処理を可能にします。 UI 要素でコマンド実行を使うことができる場合は、個々の入力イベントではなく、コマンド実行 API を使うことを検討してください。 通常は、データのビュー モデルを定義するクラスのプロパティに Binding 参照を使用します。 プロパティには、言語固有 の ICommand コマンド パターンを実装する名前付きコマンドが保持されます。 詳しくは、「ButtonBase.Command」をご覧ください。

Windows ランタイムのカスタム イベント

カスタム イベントを定義する目的で、イベントを追加する方法と、それがクラスデザインに対して何を意味するかは、使用しているプログラミング言語に大きく依存します。

  • C# と Visual Basic では、CLR イベントを定義します。 カスタム アクセサー (add/remove) を使用していない限り、標準の .NET イベント パターンを使用できます。 追加のヒント:
  • C++/CX については、「イベント (C++/CX)」を参照してください。
    • カスタム イベントを独自に使用する場合でも、名前付き参照を使用します。 カスタム イベントにはラムダを使用しないでください。循環参照を作成できます。

Windows ランタイムのカスタム ルーティング イベントを宣言することはできません。ルーティング イベントは、Windows ランタイムからのセットに限定されます。

カスタム イベントの定義は、通常、カスタム コントロールを定義する演習の一環として行われます。 プロパティが変更されたコールバックを持つ依存関係プロパティを持ち、一部またはすべてのケースで依存関係プロパティコールバックによって発生するカスタム イベントも定義するのが一般的なパターンです。 コントロールのコンシューマーは、定義したプロパティ変更コールバックにアクセスできませんが、通知イベントを使用できることは次に最適です。 詳細については、「カスタム依存関係プロパティ」を参照してください。