시각적 계층에서 적중 테스트

이 항목에서는 시각적 계층에서 제공하는 적중 테스트 기능의 개요를 제공합니다. 적중 테스트 지원을 사용하여 기하 도형 또는 점 값이 Visual의 렌더링된 콘텐츠 내에 속하는지 여부를 확인할 수 있으며, 선택 직사각형과 같은 사용자 인터페이스 동작을 구현하여 여러 개체를 선택할 수 있습니다.

적중 테스트 시나리오

UIElement 클래스에서는 주어진 좌표 값을 사용하여 요소를 상대로 적중 테스트를 수행할 수 있는 InputHitTest 메서드를 제공합니다. 대부분의 경우 InputHitTest 메서드는 요소의 적중 테스트를 구현하기 위한 적절한 기능을 제공합니다. 그러나 시각적 계층에서 적중 테스트를 구현해야 하는 몇 가지 시나리오가 있습니다.

  • UIElement가 아닌 요소에 대한 적중 테스트: 이 테스트는 DrawingVisual 또는 그래픽 개체 같은 UIElement가 아닌 개체를 적중 테스트할 때 적용됩니다.

  • 기하 도형을 사용하는 적중 테스트: 점의 좌표 값이 아닌 기하 도형 개체를 사용하여 적중 테스트를 수행해야 하는 경우에 적용됩니다.

  • 여러 개체에 대한 적중 테스트: 겹치는 개체와 같은 여러 개체에 대해 적중 테스트를 수행해야 하는 경우에 적용됩니다. 단지 첫 번째 개체만이 아니라 기하 도형 또는 점을 교차하는 모든 시각적 개체에 대한 결과를 얻을 수 있습니다.

  • UIElement 적중 테스트 정책 무시: UIElement 적중 테스트 정책을 무시하고 요소가 해제되어 있거나 보이지 않는지 등의 요인을 고려하는 경우에 적용됩니다.

참고

시각적 계층의 적중 테스트를 보여 주는 전체 코드 샘플에 대해서는 DrawingVisuals를 사용하는 적중 테스트 샘플Win32 상호 운용성을 사용하는 적중 테스트 샘플을 참조하세요.

적중 테스트 지원

VisualTreeHelper 클래스의 HitTest 메서드의 목적은 기하 도형 또는 점 좌표 값이 컨트롤 또는 그래픽 요소와 같은 지정된 개체의 렌더링된 콘텐츠 내에 있는지를 확인하는 것입니다. 예를 들어 적중 테스트를 사용하여 개체의 경계 사각형 내부를 마우스로 클릭할 경우 기하 도형 원 내에 포함되는지 여부를 확인할 수 있습니다. 또한 적중 테스트의 기본 구현을 재정의하여 사용자 고유의 적중 테스트 계산을 사용자 지정하도록 선택할 수도 있습니다.

다음 그림은 사각형이 아닌 개체의 영역 및 해당 경계 사각형 간 관계를 보여 줍니다.

유효한 적중 테스트 지역 다이어그램
유효한 적정 테스트 영역의 다이어그램

적중 테스트 및 Z 순서

WPF(Windows Presentation Foundation) 시각적 계층은 단지 최상위 개체만이 아니라 점 또는 기하 도형 아래의 모든 개체에 대한 적중 테스트를 지원합니다. 결과는 Z 순서대로 반환됩니다. 그러나 HitTest 메서드에 매개 변수로 전달하는 시각적 개체는 적중 테스트가 수행될 시각적 트리의 부분을 결정합니다. 시각적 트리 전체 또는 일부에 대해 적중 테스트를 수행할 수 있습니다.

다음 그림에서 원 개체는 사각형 및 삼각형 개체 위에 있습니다. z 순서 값이 최상위에 있는 시각적 개체에 대해서만 적중 테스트를 수행하려는 경우 HitTestResultCallback에서 Stop를 반환하여 첫 번째 항목 이후에 적중 테스트 통과를 중지하도록 시각적 적중 테스트 열거형을 설정할 수 있습니다.

시각적 개체 트리의 z 순서의 다이어그램
시각적 트리의 z 순서 다이어그램

특정 지점이나 기하 도형에서 모든 시각적 개체를 열거하고 싶다면, HitTestResultCallback에서 Continue를 반환하세요. 즉 전체가 가려진 경우에도 다른 개체 아래에 있는 시각적 개체에 대한 적중 테스트를 수행할 수 있습니다. 자세한 내용은 "적중 테스트 결과 콜백 사용" 섹션의 샘플 코드를 참조하세요.

참고

투명한 시각적 개체에 대해서도 적중 테스트를 수행할 수 있습니다.

기본 적중 테스트 사용

HitTest 메서드를 사용하여 테스트를 수행할 시각적 개체 및 지점 좌표 값을 지정하면 한 지점이 시각적 개체의 기하 도형 내에 있는지 여부를 확인할 수 있습니다. 시각적 개체 매개 변수는 시각적 트리에서 적중 테스트 검색의 시작점을 식별합니다. 기하 도형에 좌표가 있는 시각적 개체가 시각적 트리에서 발견된다면, HitTestResult 개체의 VisualHit 속성으로 설정됩니다. 그러면 HitTestResultHitTest 메서드에서 반환됩니다. 지점이 적중 테스트를 수행 중인 시각적 하위 트리에 포함되지 않는다면, 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

시각적 트리가 적중 테스트에 미치는 영향

시각적 트리의 시작점은 개체의 적중 테스트 열거 동안 반환되는 개체를 결정합니다. 여러 개체에 대해 적중 테스트를 수행하려는 경우 시각적 트리에서 시작점으로 사용되는 시각적 개체는 관심 있는 모든 개체의 공통 상위 항목이어야 합니다. 예를 들어 다음 다이어그램에서 button 요소 및 drawing visual 요소 둘 다에 대해 적중 테스트를 수행하려는 경우 시각적 트리의 시작점을 두 요소의 공통 상위 항목으로 설정해야 합니다. 이 경우 canvas 요소는 button 요소 및 drawing visual의 공통 상위 항목입니다.

시각적 개체 트리 계층 다이어그램
시각적 트리 계층 구조의 다이어그램

참고

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

시각적 개체의 경계 사각형과 렌더링된 콘텐츠 둘 다에 대해 적중 테스트를 수행하려는 경우가 있을 수 있습니다. 재정의된 HitTestCore 메서드의 PointHitTestParameters 매개 변수 값을 기본 메서드 HitTestCore의 매개 변수로 사용하면, 시각적 개체의 경계 사각형 적중에 따라 작업을 수행하고 시각적 개체의 렌더링된 콘텐츠를 대상으로 두 번째 적중 테스트를 수행할 수 있습니다.

// 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

참고 항목