Поделиться через


Проверка попадания на визуальном уровне

Обновлен: Ноябрь 2007

В этом разделе представлены общиесведения о функциональных возможностях проверки попадания, предоставляемых на визуальном уровне. Поддержка проверки попадания позволяет определить, попадает ли геометрический объект или точка в отображаемое содержимое Visual, что позволяет реализовать поведение пользовательского интерфейса, например выделение прямоугольником для выбора нескольких объектов.

В этом разделе содержатся следующие подразделы.

  • Сценарии проверки попадания
  • Поддержка проверки попадания
  • Проверка попадания и z-порядок
  • Использование проверки попадания по умолчанию
  • Использование обратного вызова результатов проверки попадания
  • Использование обратного вызова фильтра проверки попадания
  • Переопределение проверки попадания по умолчанию
  • Связанные разделы

Сценарии проверки попадания

В классе UIElement представлен метод InputHitTest, который позволяет проверить попадание элемента с использованием заданного значения координат. Метод InputHitTest в большинстве случаях обеспечивает реализацию проверки попадания элементов. Однако в некоторых сценариях может потребоваться реализация проверки попадания на визуальном уровне.

  • Проверка попадания для объектов, не принадлежащих классу UIElement. Применяется при проверке попадания объектов, не принадлежащих классу UIElement, например DrawingVisual или графических объектов.

  • Проверка попадания с использованием геометрического объекта. Применяется для проверки попадания с использованием геометрического объекта вместо значения координат точки.

  • Проверка попадания для нескольких объектов. Применяется при проверке попадания для нескольких, например перекрывающихся, объектов. Можно получить результаты для всех визуальных объектов, пересекающихся с геометрическим объектом или точкой (а не только для первого из них).

  • Игнорирование политики проверки попадания класса UIElement. Применяется, если необходимо игнорировать политику проверки попадания класса UIElement, в которой учитываются такие факторы, как отключение или невидимость элемента.

ms752097.alert_note(ru-ru,VS.90).gifПримечание.

Полный пример кода, иллюстрирующего проверку попадания на визуальном уровне, см. в разделах Пример проверки нажатия с помощью DrawingVisuals и Пример проверки нажатий, включающий взаимодействие с Win32.

Поддержка проверки попадания

Методы HitTest класса VisualTreeHelper используются, чтобы определить, попадает ли геометрический объект или значение координат точки в отображаемое содержимое заданного объекта, например элемента управления или графического элемента. Например, можно использовать проверку попадания, чтобы определить, попадает ли точка, в которой нажата кнопка мыши в ограничивающем прямоугольнике, в геометрический объект «круг». Можно также переопределить реализацию проверки попадания по умолчанию для выполнения собственных вычислений по проверке попадания.

На следующем рисунке показана связь между областью непрямоугольного объекта и его ограничивающим прямоугольником.

Допустимая область проверки попадания
Допустимая область проверки попадания

Проверка попадания и z-порядок

На визуальном уровне в Windows Presentation Foundation (WPF) поддерживается проверка попадания для всех объектов, расположенных под точкой или геометрическим объектом, а не только для объекта верхнего уровня. Результаты возвращаются в виде z-порядка. Однако визуальный объект, передаваемый в качестве параметра для метода HitTest, определяет, для какой части визуального дерева будет проведена проверка попадания. Можно провести проверку попадания для всего визуального дерева или любой его части.

На следующем рисунке объект круг расположен поверх квадрата и треугольника. Чтобы выполнить проверку попадания только для визуального объекта, имеющего максимальное значение z-порядка, установите нумерацию проверки попадания визуальных объектов, чтобы возвращать Stop из HitTestResultCallback для остановки прохождения проверки попадания после первого элемента.

Z-порядок для визуального дерева
Z-порядок для визуального дерева

Если необходимо перечислить все визуальные объекты, расположенные под определенной точкой или геометрическим объектом, необходимо возвращать Continue из HitTestResultCallback. Это означает, что можно проводить проверку попадания для визуальных объектов, находящихся под другими объектами, даже если они полностью не видны. Дополнительные сведения см. в примере кода в разделе «Использование обратного вызова результатов проверки попадания».

ms752097.alert_note(ru-ru,VS.90).gifПримечание.

Для прозрачного визуального объекта также может быть проведена проверка попадания.

Использование проверки попадания по умолчанию

Чтобы определить, расположена ли точка внутри визуального объекта, используйте метод HitTest для указания визуального объекта и значения координат точки, которые следует проверить. Параметр визуального объекта определяет начальную точку в визуальном дереве для поиска при проверке попадания. При обнаружении в визуальном дереве объекта, геометрическая форма которого включает координату, этот объект присваивается свойству VisualHit объекта HitTestResult. После этого значение HitTestResult возвращается из метода HitTest. Если точка не содержится в проверяемом визуальном поддереве, метод HitTest возвращает null.

ms752097.alert_note(ru-ru,VS.90).gifПримечание.

Проверка попадания по умолчанию всегда возвращает самый верхний объект в 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.
    }
}

Влияние визуального дерева на проверку попадания

Начальная точка в визуальном дереве определяет, какие объекты возвращаются во время перечисления объектов проверки попадания. Если проверка попадания проводится для нескольких объектов, визуальный объект, используемый в качестве начальной точки в визуальном дереве, должен быть общим предком всех проверяемых объектов. Например, если необходимо проверить элемент «кнопка» и визуальный объект, представленные на следующем рисунке, в качестве начальной точки в визуальном дереве следует установить объект, являющийся общим предком для обоих элементов. В этом случае элемент полотна является общим предком как для элемента «кнопка», так и для визуального объекта.

Иерархия визуального дерева
Иерархия визуального дерева

ms752097.alert_note(ru-ru,VS.90).gifПримечание.

В свойстве 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);
    }
}

Метод обратного вызова проверки попадания определяет действия, которые выполняются при определении проверки попадания для конкретного визуального объекта в визуальном дереве. После выполнения этих действий возвращается значение 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;
}
ms752097.alert_note(ru-ru,VS.90).gifПримечание.

Перечисление визуальных объектов выполняется в соответствии с z-порядком. Визуальный объект с максимальным значением z-порядка является первым объектом в перечислении. Остальные визуальные объекты перечисляются по убыванию значения z-порядка. Этот порядок перечисления соответствует порядку отрисовки визуальных объектов.

Чтобы остановить перечисление визуальных объектов в любое время, следует возвратить 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();
    }
}

Если не требуется использовать необязательную функцию обратного вызова фильтра проверки попадания, передайте значение 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));

Упрощение визуального дерева
Создание визуального дерева, используя фильтр проверки нажатия

Функция обратного вызова фильтра проверки попадания позволяет перечислять все визуальные объекты, отображаемое содержимое которых содержит указанные координаты. Однако может потребоваться пропуск некоторых ветвей визуального дерева, которые не нужно обрабатывать в функции обратного вызова результатов проверки попадания. Возвращаемое значение функции обратного вызова фильтра проверки попадания определяет, какие действия следует предпринять при перечислении визуальных объектов. Например, если возвращается значение 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;
    }
}
ms752097.alert_note(ru-ru,VS.90).gifПримечание.

Обратный вызов фильтра проверки попадания иногда происходит в тех случаях, когда не произведен обратный вызов результатов проверки попадания.

Переопределение проверки попадания по умолчанию

Чтобы переопределить поддержку проверки попадания по умолчанию для визуального объекта, переопределите метод 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);
}

Может возникнуть необходимость проверки попадания и для ограничивающего прямоугольника, и для отображаемого содержимого визуального объекта. Используя значение параметра PointHitTestParameters в переопределенном методе HitTestCore в качестве параметра для базового метода 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);
}

См. также

Задачи

Пример проверки нажатия с помощью DrawingVisuals

Пример проверки нажатий, включающий взаимодействие с Win32

Практическое руководство. Проверка попадания курсора Geometry визуальном объекте

Практическое руководство. Проверка попадания курсора с помощью вложенного контейнера Win32

Ссылки

HitTest

HitTestResult

HitTestResultCallback

HitTestFilterCallback

IsHitTestVisible