このトピックでは、ビジュアル レイヤーによって提供されるヒット テスト機能の概要について説明します。 ヒット テストのサポートを使用すると、ジオメトリまたはポイント値が Visualのレンダリングされたコンテンツ内にあるかどうかを判断できます。これにより、複数のオブジェクトを選択する選択四角形などのユーザー インターフェイスの動作を実装できます。
ヒット テストのシナリオ
UIElement クラスは、InputHitTest メソッドを提供します。これにより、指定した座標値を使用して要素に対してヒット テストを実行できます。 多くの場合、InputHitTest メソッドは、要素のヒット テストを実装するために必要な機能を提供します。 ただし、ビジュアル レイヤーでヒット テストを実装する必要があるシナリオがいくつかあります。
UIElement 以外のオブジェクトに対するヒット テスト: これは、UIElement やグラフィックス オブジェクトなど、DrawingVisual 以外のオブジェクトをヒット テストする場合に適用されます。
ジオメトリを使用したヒット テスト: これは、ポイントの座標値ではなく、ジオメトリ オブジェクトを使用してヒット テストを実行する必要がある場合に適用されます。
複数のオブジェクトに対するヒット テスト: 重複するオブジェクトなど、複数のオブジェクトに対してヒット テストを実行する必要がある場合に適用されます。 最初のビジュアルだけでなく、ジオメトリまたはポイントと交差するすべてのビジュアルの結果を取得できます。
UIElementのヒットテストポリシーを無視: これは、UIElementのヒットテストポリシーを無視する必要がある場合に適用されます。これは、その要素が無効化されているか、非表示かなどの要因を考慮に入れます。
注
ビジュアル レイヤーでのヒット テストを示す完全なコード サンプルについては、「
ヒット テストのサポート
HitTest クラスの VisualTreeHelper メソッドの目的は、ジオメトリまたはポイント座標値が、コントロールやグラフィック要素などの特定のオブジェクトのレンダリングされたコンテンツ内にあるかどうかを判断することです。 たとえば、ヒットテストを使用して、オブジェクトの外接矩形内におけるマウスクリックが円の形状内にあるかどうかを判断できます。 ヒット テストの既定の実装をオーバーライドして、独自のカスタム ヒット テスト計算を実行することもできます。
次の図は、四角形以外のオブジェクトの領域とその外接する四角形の関係を示しています。
有効なヒットテスト領域の図解
ヒット テストと z オーダー
Windows Presentation Foundation (WPF) ビジュアル レイヤーは、最上位のオブジェクトだけでなく、ポイントまたはジオメトリの下にあるすべてのオブジェクトに対するヒット テストをサポートします。 結果は z オーダーで返されます。 ただし、パラメーターとして HitTest メソッドに渡すビジュアル オブジェクトによって、ヒット テストするビジュアル ツリーの部分が決まります。 ビジュアル ツリー全体またはその一部に対してテストを実行できます。
次の図では、円オブジェクトは四角形オブジェクトと三角形オブジェクトの両方の上にあります。 z オーダー値が最上位のビジュアル オブジェクトのヒット テストのみに関心がある場合は、ビジュアル ヒット テスト列挙体を設定して、最初の項目の後にヒット テストトラバーサルを停止するように Stop から HitTestResultCallback を返すことができます。
ビジュアル ツリーの z オーダーの図
特定の点またはジオメトリの下にあるすべてのビジュアル オブジェクトを列挙する場合は、Continueから HitTestResultCallback を返します。 つまり、完全に隠されているものも含めて、他のオブジェクトの下にあるすべてのビジュアル オブジェクトに対してヒット テストを行うことができます。 詳細については、「ヒット テスト結果コールバックの使用」セクションのサンプル コードを参照してください。
注
透明なビジュアル オブジェクトもヒットテストが可能です。
既定のヒット テストの使用
HitTest メソッドを使用して、ビジュアル オブジェクトとテスト対象の点座標値を指定することで、ポイントがビジュアル オブジェクトのジオメトリ内にあるかどうかを識別できます。 ビジュアル オブジェクト パラメーターは、ヒット テスト検索のビジュアル ツリー内の開始点を識別します。 ジオメトリに座標が含まれるビジュアル オブジェクトがビジュアル ツリー内に見つかった場合は、VisualHit オブジェクトの HitTestResult プロパティに設定されます。
HitTestResult は、HitTest メソッドから返されます。 ヒットテスト中のビジュアルサブツリーにそのポイントが含まれていない場合、HitTest は null
を返します。
注
既定のヒット テストでは、常に z オーダーで最上位のオブジェクトが返されます。 一部または完全に隠れている可能性のあるすべてのビジュアル オブジェクトを識別するには、ヒット テストの結果コールバックを使用します。
HitTest メソッドのポイント パラメーターとして渡す座標値は、ヒット テスト対象のビジュアル オブジェクトの座標空間を基準とする必要があります。 たとえば、親の座標空間で (100, 100) で定義された入れ子になったビジュアル オブジェクトがある場合、(0, 0) で子ビジュアルをヒット テストすることは、親の座標空間の (100, 100) でのヒット テストと同じです。
次のコードは、ヒット テストに使用されるイベントをキャプチャするために使用される UIElement オブジェクトのマウス イベント ハンドラーを設定する方法を示しています。
// 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.
}
}
' Respond to the left mouse button down event by initiating the hit test.
Private Overloads Sub OnMouseLeftButtonDown(ByVal sender As Object, ByVal e As MouseButtonEventArgs)
' Retrieve the coordinate of the mouse position.
Dim pt As Point = e.GetPosition(CType(sender, UIElement))
' Perform the hit test against a given portion of the visual object tree.
Dim result As HitTestResult = VisualTreeHelper.HitTest(myCanvas, pt)
If result IsNot Nothing Then
' Perform action on hit visual object.
End If
End Sub
ヒット テストに対するビジュアル ツリーの影響
ビジュアル ツリーの開始点は、オブジェクトのヒット テスト列挙中に返されるオブジェクトを決定します。 ヒット テストを実行するオブジェクトが複数ある場合、ビジュアル ツリーの開始点として使用されるビジュアル オブジェクトは、対象となるすべてのオブジェクトの共通の先祖である必要があります。 たとえば、次の図でボタン要素と描画ビジュアルの両方のヒット テストに関心がある場合は、ビジュアル ツリーの開始点を両方の共通の先祖に設定する必要があります。 この場合、キャンバス要素は、ボタン要素と描画ビジュアルの両方の共通の先祖です。
ビジュアル ツリー階層の図
注
IsHitTestVisible プロパティは、レンダリングされたコンテンツの一部からヒット テスト結果として UIElement派生オブジェクトを返すことができるかどうかを宣言する値を取得または設定します。 これにより、ビジュアル ツリーを選択的に変更して、ヒット テストに関係するビジュアル オブジェクトを決定できます。
ヒット テスト結果のコールバックの使用
ジオメトリに指定した座標値が含まれるビジュアル ツリー内のすべてのビジュアル オブジェクトを列挙できます。 これにより、他のビジュアル オブジェクトによって部分的または完全に隠れている可能性があるビジュアル オブジェクトであっても、すべてのビジュアル オブジェクトを識別できます。 ビジュアル ツリー内のビジュアル オブジェクトを列挙するには、ヒット テスト コールバック関数と共に HitTest メソッドを使用します。 指定した座標値がビジュアル オブジェクトに含まれている場合、ヒット テスト コールバック関数がシステムによって呼び出されます。
ヒット テスト結果の列挙中は、ビジュアル ツリーを変更する操作を実行しないでください。 走査中にビジュアル ツリーからオブジェクトを追加または削除すると、予期しない動作が発生する可能性があります。 HitTest メソッドが戻った後は、ビジュアル ツリーを安全に変更できます。 ヒット テスト結果の列挙中に値を格納するために、ArrayListなどのデータ構造を指定できます。
// 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);
}
}
' Respond to the right mouse button down event by setting up a hit test results callback.
Private Overloads Sub OnMouseRightButtonDown(ByVal sender As Object, ByVal e As MouseButtonEventArgs)
' Retrieve the coordinate of the mouse position.
Dim pt As Point = e.GetPosition(CType(sender, UIElement))
' 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, Nothing, New HitTestResultCallback(AddressOf MyHitTestResult), New PointHitTestParameters(pt))
' Perform actions on the hit test results list.
If hitResultsList.Count > 0 Then
Console.WriteLine("Number of Visuals Hit: " & hitResultsList.Count)
End If
End Sub
ヒット テスト コールバック メソッドは、ビジュアル ツリー内の特定のビジュアル オブジェクトでヒット テストが識別されたときに実行するアクションを定義します。 アクションを実行すると、他のビジュアル オブジェクトの列挙を続行するかどうかを決定する HitTestResultBehavior 値が返されます。
// 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.
return HitTestResultBehavior.Continue;
}
' Return the result of the hit test to the callback.
Public Function MyHitTestResult(ByVal result As HitTestResult) As HitTestResultBehavior
' 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.
Return HitTestResultBehavior.Continue
End Function
注
ヒットしたビジュアル オブジェクトの列挙の順序は z オーダーです。 最上位の z オーダー レベルのビジュアル オブジェクトは、列挙された最初のオブジェクトです。 列挙されたその他のビジュアル オブジェクトは、降順のz順序レベルに配置されます。 この列挙の順序は、ビジュアルのレンダリング順序に対応します。
ヒット テスト コールバック関数でビジュアル オブジェクトの列挙をいつでも停止するには、Stopを返します。
// Set the behavior to stop enumerating visuals.
return HitTestResultBehavior.Stop;
' Set the behavior to stop enumerating visuals.
Return HitTestResultBehavior.Stop
ヒット テスト フィルターのコールバックの使用
オプションのヒット テスト フィルターを使用して、ヒット テスト結果に渡されるオブジェクトを制限できます。 これにより、ヒット テストの結果で処理する必要のないビジュアル ツリーの部分を無視することができます。 ヒット テスト フィルターを実装するには、ヒット テスト フィルターコールバック関数を定義し、HitTest メソッドを呼び出すときにパラメーター値として渡します。
// 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();
}
}
' Respond to the mouse wheel event by setting up a hit test filter and results enumeration.
Private Overloads Sub OnMouseWheel(ByVal sender As Object, ByVal e As MouseWheelEventArgs)
' Retrieve the coordinate of the mouse position.
Dim pt As Point = e.GetPosition(CType(sender, UIElement))
' 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(AddressOf MyHitTestFilter), New HitTestResultCallback(AddressOf MyHitTestResult), New PointHitTestParameters(pt))
' Perform actions on the hit test results list.
If hitResultsList.Count > 0 Then
ProcessHitTestResultsList()
End If
End Sub
オプションのヒット テスト フィルター コールバック関数を指定しない場合は、null
メソッドのパラメーターとして HitTest 値を渡します。
// 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));
' Set up a callback to receive the hit test result enumeration,
' but no hit test filter enumeration.
VisualTreeHelper.HitTest(myCanvas, Nothing, New HitTestResultCallback(AddressOf MyHitTestResult), New PointHitTestParameters(pt)) ' No hit test filtering.
を使用してビジュアル ツリーを剪定する
ビジュアル ツリーの簡略化
ヒット テスト フィルターコールバック関数を使用すると、レンダリングされたコンテンツに指定した座標が含まれるすべてのビジュアルを列挙できます。 ただし、ヒット テストの結果のコールバック関数で、ビジュアル ツリーの一部の分岐を処理する必要がない場合、これらの分岐を無視できます。 ヒット テスト フィルターコールバック関数の戻り値によって、ビジュアル オブジェクトの列挙が実行するアクションの種類が決まります。 たとえば、ContinueSkipSelfAndChildren値を返した場合、ヒット テスト結果の列挙から現在のビジュアル オブジェクトとその子を削除できます。 つまり、ヒット テストの結果コールバック関数では、列挙体にこれらのオブジェクトが表示されません。 オブジェクトのビジュアル ツリーを排除すると、ヒット テスト結果の列挙パス中の処理量が減少します。 次のコード例では、フィルターはラベルとその子孫をスキップし、他のすべてをヒット テストします。
// 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.
return HitTestFilterBehavior.ContinueSkipSelfAndChildren;
}
else
{
// Visual object is part of hit test results enumeration.
return HitTestFilterBehavior.Continue;
}
}
' Filter the hit test values for each object in the enumeration.
Public Function MyHitTestFilter(ByVal o As DependencyObject) As HitTestFilterBehavior
' Test for the object value you want to filter.
If o.GetType() Is GetType(Label) Then
' Visual object and descendants are NOT part of hit test results enumeration.
Return HitTestFilterBehavior.ContinueSkipSelfAndChildren
Else
' Visual object is part of hit test results enumeration.
Return HitTestFilterBehavior.Continue
End If
End Function
注
ヒット テストの結果コールバックが呼び出されない場合、ヒット テスト フィルターコールバックが呼び出されることがあります。
既定のヒット テストのオーバーライド
HitTestCore メソッドをオーバーライドすることで、ビジュアル オブジェクトの既定のヒット テスト サポートをオーバーライドできます。 つまり、HitTest メソッドを呼び出すと、オーバーライドされた HitTestCore の実装が呼び出されます。 座標がビジュアル オブジェクトの描画されるコンテンツの外側にあっても、ビジュアル オブジェクトの外接する四角形内でヒット テストが実行されると、オーバーライドされたメソッドが呼び出されます。
// 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);
}
' Override default hit test support in visual object.
Protected Overrides Overloads Function HitTestCore(ByVal hitTestParameters As PointHitTestParameters) As HitTestResult
Dim pt As Point = 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(Me, pt)
End Function
ビジュアル オブジェクトの外接する四角形と描画されるコンテンツの両方に対してヒット テストを行う必要が生じる場合もあります。 オーバーライドされた PointHitTestParameters
メソッドの HitTestCore パラメーター値を基本メソッド HitTestCoreのパラメーターとして使用すると、ビジュアル オブジェクトの外接する四角形のヒットに基づいてアクションを実行し、ビジュアル オブジェクトのレンダリングされたコンテンツに対して 2 回目のヒット テストを実行できます。
// 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);
}
' Override default hit test support in visual object.
Protected Overrides Overloads Function HitTestCore(ByVal hitTestParameters As PointHitTestParameters) As HitTestResult
' 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 MyBase.HitTestCore(hitTestParameters)
End Function
こちらも参照ください
.NET Desktop feedback