Home > C# > 目的別資料 > Visualレイヤー・プログラミング > msdnドキュメント > Visualレイヤーのヒット・テスト

Visualレイヤーのヒット・テスト

新規作成日 2020-10-08
最終更新日

Hit Testing in the Visual Layer

このトピックでは、ビジュアル・レイヤーに提供されるヒット・テスト機能の概要を説明します。

ヒット・テストのサポートにより、ジオメトリや点の値が、Visualのレンダリングされたコンテンツ内にあるかどうかを判断でき、あなたが、複数のオブジェクトを選択する選択長方形のような、ユーザー・インターフェイスの動作を実装できます。

ヒット・テストのシナリオ

Hit Testing Scenarios

UIElementクラスは、あなたが、与えられた座標値を使用して、要素にヒット・テストできるInputHitTestメソッドを提供します。多くの場合、InputHitTestメソッドは、要素のヒットテストを実装するために必要な機能を提供します。しかしながら、あなたが、ビジュアル・レイヤーで、ヒット・テストを実装する必要がある、いくつかのシナリオがあります。

  • UIElementではないオブジェクトに対するヒット・テスト:

    これは、あなたが、DrawingVisualや図形オブジェクトのような、UIElementではないオブジェクトのヒットテストを行う場合に適用します。

  • ジオメトリを使用したヒットテスト:

    これは、点の座標値ではなく、ジオメトリ・オブジェクトを使用して、ヒット・テストする必要がある場合に適用します。

  • 複数のオブジェクトに対するヒット・テスト:

    これは、あなたが、重なり合うオブジェクトのような、複数のオブジェクトに対してヒットテストを行う必要がある場合に適用します。

    あなたは、最初のビジュアルだけでなく、ジオメトリや点と交差するすべてのビジュアルの結果を取得できます。

  • UIElementのヒット・テスト・ポリシーを無視する:

    あなたが、要素が、無効や非表示などの要因を考慮に入れ、UIElementのヒット・テスト・ポリシーを無視する必要がある時、適用します。

注意

ビジュアル・レイヤーで、ヒット・テストを例示している完全なコード・サンプルのために、DrawingVisualsサンプルを使用したヒットテスト、および、Win32相互運用サンプルを使用したヒットテストを参照してください。

ヒット・テスト・サポート

Hit Testing Support

VisualTreeHelperクラスのHitTestメソッドの目的は、コントロールやグラッフィク要素のような、ジオメトリや点の座標値が、特定のオブジェクトのレンダリングされたコンテンツ内にあるかどうかを判断することです。たとえば、あなたは、マウス・クリックが、オブジェクトの取り囲む四角形が、円のジオメトリの範囲内にあるかどうかに関係なく、ヒットテストを使用することができます。あなたは、独自のカスタム・ヒット・テストの計算を実行するためのヒット・テストのデフォルトの実装をオーバーライドするために、選択することもできます。

次の図は、長方形ではないオブジェクトの領域と外接する長方形との関係を示しています。

有効なヒット・テスト領域の図
有効なヒット・テスト領域の図

境界の矩形

Visualオブジェクト

ヒット・テストが、成功した。

ヒット・テストが、失敗した。

ヒット・テストとz-order

Hit Testing and Z-Order

Windows Presentation Foundation (WPF)のビジュアル・レイヤーは、点やジオメトリーの下にあるすべてのオブジェクトに対して、ヒット・テストをサポートします。最上位のオブジェクトだけではありません。結果は、z-orderで返されています。しかしながら、あなたが、HitTestメソッドに、パラメーターとして渡すビジュアル・オブジェクトは、ビジュアル・ツリーの一部が、ヒット・テストされるかどうかを決定します。あなたは、ビジュアル・ツリー全体、あるいは、その一部に対してヒット・テストを行うことができます。

次の図では、円オブジェクトは、あなたが、z-order値が最上位であるビジュアル・オブジェクトのヒット・テストだけに興味があるある場合、正方形と三角形オブジェクトの上にあります。あなたは、1つ目の項目の後、ヒット・テストの横断を停止するために、HitTestResultCallbackからStopを返すために、ビジュアル・ヒット・テスト列挙体を設定できます。

ビジュアル・ツリーのz-orderの図
ビジュアル・ツリーのz-orderの図

オブジェクトのzオーダー(上から下)

円、正方形、三角形

ヒットのx:y座標

ヒットのz-orderの図

あなたが、特定の点やジオメトリーの下にある、すべてのビジュアル・オブジェクトを列挙する必要がある場合、HitTestResultCallbackから、Continueを返します。あなたが、完全に隠されている場合でも、他のオブジェクトの下にあるビジュアル・オブジェクトのために、ヒット・テストができることを示しています。詳細については、「ヒットテスト結果のコールバックの使用」のセクションで、サンプルコードを参照してください。

注意

透明なビジュアル・オブジェクトも、ヒット・テストできます。

デフォルトのヒット・テストを使用する

Using Default Hit Testing

あなたは、テストするためのビジュアル・オブジェクトと点の座標値を指定するために、HitTestメソッドを使用して、点が、ビジュアル・オブジェクトのジオメトリーの中にあるかどうか、識別することができます。ビジュアル・オブジェクトのパラメータは、ヒット・テストを検索するためのビジュアル・ツリーの開始点を示します。ジオメトリに、座標が含まれているビジュアル・ツリーで、ビジュアル・オブジェクトが見つかった場合、HitTestResultオブジェクトのVisualHitプロパティに設定されます。HitTestResultは、続いて、HitTestメソッドから返されます。点が、あなたがヒット・テストするビジュアル・サブツリーに含まれていない場合、HitTestは、nullを返します。

注意

デフォルトのヒットテストでは、常に、z-orderの最上位のオブジェクトが返されます。すべてのビジュアル・オブジェクトを識別するために、部分的、あるいは、全体が隠されている可能性ものも含めて、ヒット・テスト結果のコールバックを使用します。

HitTestメソッドの点のパラメータとして渡す座標値は、あなたが、ヒットテストを行うビジュアル・オブジェクトの座標空間を基準にする必要があります。たとえば、あなたが、親の座標空間内の(100, 100)で定義されるビジュアル・オブジェクトを入れ子にした場合、続いて、(0, 0)での、子のビジュアルのヒット・テストは、(100, 100)での、親の座標空間のヒット・テストと同等です。

次のコードは、UIElementオブジェクトのマウス・イベント・ハンドラーを設定する方法を示しています。これは、ヒット・テストに使用されるイベントをキャプチャするために使用されます。

C#
// Respond to the left mouse button down event by initiating the hit test.
// ヒット・テストを開始して、マウスの左ボタン・ダウン・イベントを開始します。
private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    // Retrieve the coordinate of the mouse position.
    // マウスの位置の座標を取得します。
    Point pt = e.GetPosition((UIElement)sender);

    // Perform the hit test against a given portion of the visual object tree.
    // ビジュアル・オブジェクト・ツリーの特定の部分に対して、ヒット・テストを実行します。
    HitTestResult result = VisualTreeHelper.HitTest(myCanvas, pt);

    if (result != null)
    {
        // Perform action on hit visual object.
        // ヒットしたビジュアル・オブジェクトに対して動作を実行します。
    }
}

ビジュアル・ツリーは、どのようにヒット・テストに影響を及ぼすのでしょうか

How the Visual Tree Affects Hit Testing

ビジュアルツリーの開始点によって、オブジェクトのヒットテストの列挙中に返されるオブジェクトが決まります。あなたが、ヒット・テストを実行したいオブジェクトを複数持っている場合、ビジュアル・ツリーの開始点として使用されるビジュアル・オブジェクトは、対象となるすべてのオブジェクトの共通の祖先である必要があります。たとえば、あなたが、次の図の中のボタン要素と描画ビジュアルの両方が、ヒット・テストすることに興味を持っている場合、あなたは、ビジュアル・ツリーの開始点を設定するために、両方の共通の祖先に持っている必要があります。この場合、キャンバス要素は、ボタン要素と描画ビジュアルの両方に共通の祖先です。

ビジュアル・ツリー階層の図
ビジュアル・ツリー階層の図

注意

IsHitTestVisibleプロパティは、描画されたコンテンツのいくつかの部分から、ヒット・テストの結果として、UIElementから派生したオブジェクトを返すことができるかどうかを宣言する値を取得、あるいは、設定します。これは、あなたが、あとで、ビジュアル・ツリーを選択的に、どのビジュアル・オブジェクトが、ヒット・テストに関与しているかを判断できます。

ヒット・テスト結果のコールバックを使用する

Using a Hit Test Result Callback

あなたは、ジオメトリーが、指定した座標値が含まれるビジュアル・ツリー内のすべてのビジュアル・オブジェクトを列挙できます。これにより、他のビジュアル・オブジェクトによって、部分的、あるいは、全体的に隠されている可能性があるものも含め、すべてのビジュアル・オブジェクトを識別できます。ビジュアル・ツリーのビジュアル・オブジェクトを列挙するために、ヒット・テスト・コールバック関数を持つ、HitTestメソッドを使用します。あなたが指定する座標値が、ビジュアル・オブジェクトに含まれているとき、ヒット・テスト・コールバック関数は、システムによって呼び出されます。

ヒット・テスト結果の列挙中に、あなたは、ビジュアル・ツリーを変更する、いかなる操作も行うべきでありません。走査されている間、それは、予測できない動作を発生する、ビジュアル・ツリーからオブジェクトを追加、あるいは、削除します。あなたは、HitTestメソッドが返ったあと、ビジュアル・ツリーを安全に変更することができます。ヒット・テスト結果の列挙体の中の値を格納するために、あなたは、ArrayListのような、データ構造を提供したいかもしれません。

C#
// Respond to the right mouse button down event by setting up a hit test results callback.
// ヒット・テスト結果のコールバックを設定することで、マウスの右ボタン・ダウン・イベントに応答します。
private void OnMouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
    // Retrieve the coordinate of the mouse position.
    // マウス位置の座標を取り出します。
    Point pt = e.GetPosition((UIElement)sender);

    // Clear the contents of the list used for hit test results.
    // ヒット・テスト結果のために使用されるリストのコンテンツをクリアします。
    hitResultsList.Clear();

    // Set up a callback to receive the hit test result enumeration.
    // ヒット・テスト結果の列挙体を受け取るために、コールバックを設定します。
    VisualTreeHelper.HitTest(myCanvas, null,
        new HitTestResultCallback(MyHitTestResult),
        new PointHitTestParameters(pt));

    // Perform actions on the hit test results list.
    // ヒット・テスト結果のリストで、動作を実行します。
    if (hitResultsList.Count > 0)
    {
        Console.WriteLine("Number of Visuals Hit: " + hitResultsList.Count);
    }
}

ヒット・テスト・コールバック・メソッドは、あなたが実行する動作を定義します。ヒット・テストが、ビジュアル・ツリー内の特定のビジュアル・オブジェクトで、識別されたとき、あなたが、動作を実行したあと、あなたは、他のビジュアル・オブジェクトの列挙を続行するかどうかを決定するHitTestResultBehavior値を返します。

C#
// Return the result of the hit test to the callback.
// コールバックに、ヒット・テストの結果を返します。
public HitTestResultBehavior MyHitTestResult(HitTestResult result)
{
    // Add the hit test result to the list that will be processed after the enumeration.
    // 列挙の後で処理される、ヒット・テストの結果を、リストに追加します。
    hitResultsList.Add(result.VisualHit);

    // Set the behavior to return visuals at all z-order levels.
    // すべてのz-order・レベルで、ビジュアルを返すように、動作を設定します。
    return HitTestResultBehavior.Continue;
}
注意

ヒットしたビジュアル・オブジェクトの列挙の順序は、z-orderです。最上位のz-orderレベルのビジュアル・オブジェクトは、最初に列挙されるオブジェクトです。列挙されている他のビジュアル・オブジェクトは、z-orderレベルが減少していきます。この列挙の順序は、ビジュアルのレンダリング順序に対応しています。

あなたは、ヒット・テスト・コールバック関数内で、Stopを返すことにより、いつでもビジュアル・オブジェクトの列挙を停止できます。

C#
// Set the behavior to stop enumerating visuals.
// ビジュアルの列挙を停止する動作を設定します。
return HitTestResultBehavior.Stop;

ヒット・テスト・フィルタ・コールバックを使用する

Using a Hit Test Filter Callback

あなたは、ヒット・テストの結果に渡されるオブジェクトを制限するために、オプションのヒット・テスト・フィルタを使用することができます。あなたは、ヒットテスト結果の処理に関心を持っていないビジュアル・ツリーの一部を無視することができます。ヒット・テスト・フィルタを実装するために、あなたは、ヒット・テスト・フィルタのコールバック関数を定義し、あなたが、HitTestメソッドを呼び出すとき、パラメーター値として、渡します。

C#
// Respond to the mouse wheel event by setting up a hit test filter and results enumeration.
// ヒット・テスト・フィルタと結果の列挙を設定して、マウス・ホイール・イベントに応答します。
private void OnMouseWheel(object sender, MouseWheelEventArgs e)
{
    // Retrieve the coordinate of the mouse position.
    // マウス位置の座標を取り出します。
    Point pt = e.GetPosition((UIElement)sender);

    // Clear the contents of the list used for hit test results.
    // ヒット・テスト結果のために使用されるリストのコンテンツをクリアします。
    hitResultsList.Clear();

    // Set up a callback to receive the hit test result enumeration.
    // ヒット・テスト結果の列挙体を受け取るために、コールバックを設定します。
    VisualTreeHelper.HitTest(myCanvas,
                      new HitTestFilterCallback(MyHitTestFilter),
                      new HitTestResultCallback(MyHitTestResult),
                      new PointHitTestParameters(pt));

    // Perform actions on the hit test results list.
    // ヒット・テスト結果のリストで、動作を実行します。
    if (hitResultsList.Count > 0)
    {
        ProcessHitTestResultsList();
    }
}

あなたが、オプションのヒット・テスト・フィルタ・コールバック関数を提供したくない場合、HitTestメソッドのパラメーターとして、null値を渡します。

C#
// Set up a callback to receive the hit test result enumeration,
// but no hit test filter enumeration.
// ヒット・テスト結果の列挙体を受け取るために、コールバックを設定しますが、
// ヒット・テスト・フィルタ列挙体ではありません。
VisualTreeHelper.HitTest(myCanvas,
                  null,  // No hit test filtering.
                         //ヒット・テスト・フィルタリングを使用しない
                  new HitTestResultCallback(MyHitTestResult),
                  new PointHitTestParameters(pt));
ビジュアル・ツリーを簡素化する
ビジュアル・ツリーを簡素化する

ヒット・テスト・フィルタのコールバック関数は、あなたが、レンダリングされたコンテンツが、指定する座標が含まれるすべてのビジュアルを列挙できます。しかしながら、あなたが、ヒットテスト結果のコールバック関数の処理に関心を持っていない、ビジュアル・ツリーの特定のブランチを無視することをお勧めします。値を返すヒット・テスト・フィルタのコールバック関数は、ビジュアル・オブジェクトの列挙が実行する必要のある動作の種類を判断します。たとえば、あなたが、ContinueSkipSelfAndChildrenの値を返す場合、あなたは、現在のビジュアル・オブジェクト、そして、ヒット・テスト結果の列挙から、その子供たちを削除することができます。これは、ヒットテスト結果のコールバック関数が、これらのオブジェクトを列挙に表示しないことを示しています。オブジェクトのビジュアル・ツリーを簡素化すると、ヒットテスト結果の列挙パス内の処理量が減少します。次のコードの例では、フィルタは、ラベルとその子孫をスキップし、他のすべてをヒットテストします。

C#
// Filter the hit test values for each object in the enumeration.
// 列挙内のそれぞれのオブジェクトのヒットテスト値をフィルタリングします。
public HitTestFilterBehavior MyHitTestFilter(DependencyObject o)
{
    // Test for the object value you want to filter.
    // あなたが、フィルタリングするオブジェクト値をテストします。
    if (o.GetType() == typeof(Label))
    {
        // Visual object and descendants are NOT part of hit test results enumeration.
        // Visualオブジェクトと子孫は、ヒット・テスト結果の列挙体のNOT部分です。
        return HitTestFilterBehavior.ContinueSkipSelfAndChildren;
    }
    else
    {
        // Visual object is part of hit test results enumeration.
        // Visualオブジェクトは、ヒットテスト結果の列挙の一部です。
        return HitTestFilterBehavior.Continue;
    }
}
参照

ヒット・テスト・フィルタ・コールバックは、ヒットテスト結果のコールバックが、呼び出されない場合、呼び出されることがあります。

デフォルトのヒット・テストをオーバーライドする

Overriding Default Hit Testing

あなたは、HitTestCoreメソッドをオーバーライドすることで、ビジュアル・オブジェクトのデフォルトのヒット・テスト・サポートをオーバーライドすることができます。これは、あなたが、HitTestメソッドを呼び出すとき、あなたのHitTestCoreのオーバーライドされた実装が、呼び出されることを示しています。座標が、ビジュアル・オブジェクトのレンダリングされたコンテンツの外にある場合でも、ヒット・テストが、ビジュアル・オブジェクトの境界の矩形に入るとき、あなたのオーバーライドされたメソッドが、呼び出されます。

C#
// Override default hit test support in visual object.
// ビジュアル・オブジェクトで、デフォルトの
// ヒット・テスト・サポートをオーバーライドします。
protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters)
{
    Point pt = hitTestParameters.HitPoint;

    // Perform custom actions during the hit test processing,
    // which may include verifying that the point actually
    // falls within the rendered content of the visual.
    // ヒット・テスト処理の間、点が、実際に、
    // ビジュアルのレンダリングされたコンテンツあるか
    // 検証が含まれている場合があるカスタム動作を実行します。

    // Return hit on bounding rectangle of visual object.
    // ビジュアル・オブジェクトに境界の矩形のヒットを返します。
    return new PointHitTestResult(this, pt);
}

あなたが、基本メソッドHitTestCoreのパラメーターとして、あなたのオーバーライドされたHitTestCoreメソッドのPointHitTestParametersパラメータ値を使用することで、境界の矩形とビジュアル・オブジェクトのレンダリングされたコンテンツに対して、ヒット・テストしたい場合があります。あなたは、ビジュアル・オブジェクトの境界の矩形のヒットに基づいて、動作を実行することができます。続いて、ビジュアル・オブジェクトのレンダリングされたコンテンツに対して、2つ目のヒット・テストを実行します。

C#
// Override default hit test support in visual object.
// ビジュアル・オブジェクトで、デフォルトの
// ヒット・テスト・サポートをオーバーライドします。
protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters)
{
    // Perform actions based on hit test of bounding rectangle.
    // 境界の矩形のヒット・テストに基づいて、動作を実行します。
    // ...

    // Return results of base class hit testing,
    // which only returns hit on the geometry of visual objects.
    // ビジュアル・オブジェクトのジオメトリーのヒットだけを返す、
    // 基底クラスのヒットテストの結果を返します。
    return base.HitTestCore(hitTestParameters);
}

こちらもご覧ください

このエントリーをはてなブックマークに追加

Home PC C# Illustration

Copyright (C) 2011 Horio Kazuhiko(kukekko) All Rights Reserved.
kukekko@gmail.com
ご連絡の際は、お問い合わせページのURLの明記をお願いします。
「掲載内容は私自身の見解であり、所属する組織を代表するものではありません。」