Compartir a través de


Realizar pruebas de posicionamiento en la capa visual

En este tema se proporciona información general sobre la funcionalidad de prueba de posicionamiento que proporciona la capa visual. La compatibilidad con la prueba de posicionamiento permite determinar si el valor de una geometría o de un punto pertenece al contenido representado de un objeto Visual, lo que permite implementar comportamientos de interfaz de usuario tal como un rectángulo de selección para seleccionar varios objetos.

Este tema contiene las secciones siguientes.

  • Escenarios de pruebas de posicionamiento
  • Compatibilidad con la prueba de posicionamiento
  • Prueba de posicionamiento y orden z
  • Usar la prueba de posicionamiento predeterminada
  • Utilizar una devolución de llamada de resultados de prueba de posicionamiento
  • Utilizar una devolución de llamada de filtro de prueba de posicionamiento
  • Invalidar la prueba de posicionamiento predeterminada
  • Temas relacionados

Escenarios de pruebas de posicionamiento

La clase UIElement proporciona el método InputHitTest, que permite realizar pruebas de posicionamiento frente a un elemento utilizando un valor de coordenadas determinado. En muchos casos, el método InputHitTest proporciona la funcionalidad deseada para implementar las pruebas de posicionamiento de elementos. Sin embargo, hay varios escenarios en los que puede necesitar implementar pruebas de posicionamiento en la capa visual.

  • Pruebas de posicionamiento frente a objetos que no sean UIElement: esto se aplica si se está realizando pruebas de posicionamiento para objetos que no sean UIElement, tales como objetos DrawingVisual u objetos gráficos.

  • Pruebas de posicionamiento usando una geometría: esto se aplica si necesita realizar una prueba de posicionamiento usando un objeto de geometría en lugar del valor de coordenadas de un punto.

  • Pruebas de posicionamiento frente a varios objetos: esto se aplica cuando se necesita realizar pruebas de posicionamiento frente a varios objetos, tales como objetos superpuestos. Puede obtener resultados para todos los elementos visuales que corten una geometría o un punto, no solamente para el primero.

  • Omitir la directiva de prueba de posicionamiento de UIElement: esto se aplica cuando se necesita omitir la directiva de prueba de posicionamiento de UIElement, la que tiene en cuenta factores tales como si un elemento está deshabilitado o no visible.

NotaNota

Para obtener un ejemplo de código completo que muestra la prueba de posicionamiento en la capa visual, vea Hit Test Using DrawingVisuals Sample y Hit Test with Win32 Interoperation Sample.

Compatibilidad con la prueba de posicionamiento

El propósito de los métodos HitTest de la clase VisualTreeHelper es determinar si una geometría o un valor de coordenadas de punto está dentro del contenido representado de un objeto determinado, tal como un control o un elemento gráfico. Por ejemplo, podría utilizar la prueba de posicionamiento para determinar si un clic del mouse dentro del rectángulo delimitador de un objeto pertenece a la geometría de un círculo. También puede decidir invalidar la implementación predeterminada de la prueba de posicionamiento, para realizar cálculos propios en las pruebas de posicionamiento.

La ilustración siguiente muestra la relación entre la región de un objeto no rectangular y su rectángulo delimitador.

Diagrama de la región válida para la prueba de posicionamiento

Diagrama de región de prueba de posicionamiento válida

Prueba de posicionamiento y orden z

La capa visual de Windows Presentation Foundation (WPF) admite la prueba de posicionamiento frente a todos los objetos situados bajo un punto o una geometría, no solamente para el objeto de nivel superior. Los resultados se devuelven en un orden z. Sin embargo, el objeto visual que se pasa como parámetro al método HitTest determina qué parte del árbol visual se someterá a la prueba de posicionamiento. Puede realizar la prueba de posicionamiento frente al árbol visual completo o frente a cualquier parte de él.

En la ilustración siguiente, el objeto de círculo está encima del objeto cuadrado y del triangular. Si solamente le interesa la prueba de posicionamiento del objeto visual cuyo valor de orden z es el superior, puede configurar la enumeración de prueba de posicionamiento visual para que devuelva Stop de HitTestResultCallback para detener la exploración transversal de la prueba de posicionamiento después del primer elemento.

Diagrama del orden z de un árbol visual

Diagrama del orden z de un árbol visual

Si desea enumerar todos los objetos visuales bajo un punto o geometría concretos, devuelva Continue desde HitTestResultCallback. Esto significa que puede realizar pruebas de posicionamiento para objetos visuales que estén bajo otros objetos, aunque estén completamente ocultos. Vea el ejemplo de código en la sección "Utilizar una devolución de llamada de resultados de prueba de posicionamiento" para obtener más información.

NotaNota

Un objeto visual transparente también se puede someter a una prueba de posicionamiento.

Usar la prueba de posicionamiento predeterminada

Puede identificar si un punto está dentro de la geometría de un objeto visual utilizando el método HitTest para especificar un objeto visual y un valor de coordenadas de punto para la prueba. El parámetro de objeto visual identifica el punto inicial en el árbol visual para la búsqueda de la prueba de posicionamiento. Si un objeto visual se encuentra en el árbol visual cuya geometría contiene las coordenadas, se establece en la propiedad VisualHit de un objeto HitTestResult. A continuación, se devuelve HitTestResult desde el método HitTest. Si el punto no está contenido en el subárbol visual que se está sometiendo a la prueba de posicionamiento, HitTest devuelve null.

NotaNota

La prueba de posicionamiento predeterminada devuelve el objeto de nivel superior en el orden z.Para identificar todos los objetos visuales, incluso aquéllos que puedan estar ocultos, en parte o completamente, utilice una devolución de llamada de resultado de prueba de posicionamiento.

El valor de coordenadas que pase como parámetro de punto para el método HitTest debe ser relativo al espacio de coordenadas del objeto visual para el que se esté realizando la prueba de posicionamiento. Por ejemplo, si ha anidado objetos visuales definidos en (100, 100) en el espacio de coordenadas del elemento primario, la prueba de posicionamiento de un elemento secundario visual en (0, 0) es equivalente a la prueba de posicionamiento en (100, 100) en el espacio de coordenadas del elemento primario.

El código siguiente muestra cómo configurar controladores de eventos del mouse para un objeto UIElement que se utiliza para capturar eventos utilizados para la prueba de posicionamiento.

        ' 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
// 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.
    }
}

Cómo afecta el árbol visual a la prueba de posicionamiento

El punto inicial en el árbol visual determina qué objetos se devuelven durante la enumeración de objetos de la prueba de posicionamiento. Si tiene varios objetos que desea someter a la prueba de posicionamiento, el objeto visual utilizado como punto inicial en el árbol visual debe ser el antecesor común de todos los objetos de interés. Por ejemplo, si estuviera interesado en la prueba de posicionamiento tanto del elemento de botón como del elemento visual de dibujo del diagrama siguiente, tendría que establecer el punto inicial del árbol visual en el antecesor común de ambos. En este caso, el elemento de lienzo es el antecesor común del elemento de botón y del elemento visual de dibujo.

Diagrama de jerarquía del árbol visuial

Diagrama de una jerarquía de árbol visual

NotaNota

La propiedad IsHitTestVisible obtiene o establece un valor que declara si un objeto derivado de UIElement se puede devolver como un resultado de prueba de posicionamiento de alguna parte de su contenido representado.Esto permite modificar selectivamente el árbol visual para determinar qué objetos visuales están implicados en una prueba de posicionamiento.

Utilizar una devolución de llamada de resultados de prueba de posicionamiento

Puede enumerar todos los objetos visuales de un árbol visual cuya geometría contenga un valor de coordenadas especificado. Esto permite identificar todos los objetos visuales, incluso aquéllos que puedan estar ocultos, en parte o completamente, por otros objetos visuales. Enumerar los objetos visuales de un árbol visual, utilice el método HitTest con una función de devolución de llamada de la prueba de posicionamiento. El sistema llama a la función de devolución de llamada de la prueba de posicionamiento cuando el valor de coordenadas especificado esté contenido en un objeto visual.

Durante la enumeración de resultados de la prueba de posicionamiento no se debe realizar ninguna operación que modifique el árbol visual. Agregar o quitar un objeto del árbol visual mientras se está recorriendo puede producir un comportamiento imprevisible. Puede modificar sin ningún riesgo el árbol visual una vez que vuelva el método HitTest. Quizá desee proporcionar una estructura de datos, tal como un objeto ArrayList, para almacenar los valores durante la enumeración de resultados de la prueba de posicionamiento.

        ' 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
// 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);
    }
}

El método de devolución de llamada de la prueba de posicionamiento define las acciones que se realizan cuando se identifica una prueba de posicionamiento en un objeto visual determinado del árbol visual. Después de realizar las acciones, se devuelve un valor de HitTestResultBehavior que determina si debe continuar la enumeración de los demás objetos visuales.

        ' 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
// 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;
}
NotaNota

El orden de enumeración de los objetos visuales de la posición es el orden z.El objeto visual de orden z de nivel superior es el primer objeto enumerado.Los demás objetos visuales enumerados están en orden z decreciente.Este orden de enumeración corresponde al orden de representación de elementos visuales.

Puede detener la enumeración de objetos visuales en cualquier momento de la función de devolución de llamada de la prueba de posicionamiento devolviendo Stop.

            ' Set the behavior to stop enumerating visuals.
            Return HitTestResultBehavior.Stop
// Set the behavior to stop enumerating visuals.
return HitTestResultBehavior.Stop;

Utilizar una devolución de llamada de filtro de prueba de posicionamiento

Puede utilizar un filtro opcional de la prueba de posicionamiento para restringir los objetos que se pasan en los resultados de la prueba de posicionamiento. Esto permite omitir, en los resultados de la prueba de posicionamiento, las partes del árbol visual que no se desee procesar. Para implementar un filtro de prueba de posicionamiento, defina una función de devolución de llamada de filtro de prueba de posicionamiento y páselo como un valor de parámetro al llamar al método HitTest.

        ' 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
// 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();
    }
}

Si no desea proporcionar la función opcional de devolución de llamada de filtro de prueba de posicionamiento, pase un valor null como parámetro para el método HitTest.

            ' 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.
// 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));

Eliminar objetos de un árbol visual

Restringir un árbol visual usando un filtro de prueba de posicionamiento

La función de devolución de llamada de filtro de prueba de posicionamiento permite enumerar todos los objetos visuales cuyo contenido representado contenga las coordenadas que especifique. No obstante, es posible que desee omitir determinadas bifurcaciones del árbol visual, porque no le interese procesarlas en la función de devolución de llamada de la prueba de posicionamiento. El valor devuelto de la función de devolución de llamada del filtro de la prueba de posicionamiento determina el tipo de acción que deben realizar los objetos visuales. Por ejemplo, si devuelve el valor ContinueSkipSelfAndChildren, podrá quitar el objeto visual actual y sus derivados de la enumeración de los resultados de la prueba de posicionamiento. Esto significa que la función de devolución de llamada de los resultados de la prueba de posicionamiento no verá estos objetos en su enumeración. Cuando se elimina objetos del árbol visual, se reduce el número de procesos durante el paso de enumeración de resultados de la prueba de posicionamiento. En el ejemplo de código siguiente, el filtro omite las etiquetas y sus descendientes y realiza pruebas de posicionamiento con todos los demás objetos.

        ' 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
// 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;
    }
}
NotaNota

Se llamará a la devolución de llamada de filtro de la prueba de posicionamiento en aquellos casos en los que no se llame a la devolución de llamada de resultados de la prueba de posicionamiento.

Invalidar la prueba de posicionamiento predeterminada

Puede invalidar la compatibilidad con la prueba de posicionamiento predeterminada de un objeto visual invalidando el método HitTestCore. Esto significa que, al invocar el método HitTest, se llamaría a la implementación de invalidación de HitTestCore. Se llama al método de invalidación cuando una prueba de posicionamiento está dentro del rectángulo delimitador del objeto visual, aunque las coordenadas estén fuera del contenido representado de dicho objeto.

        ' 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
// 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);
}

Quizá haya ocasiones en las que desee realizar la prueba de posicionamiento tanto respecto al rectángulo delimitador como respecto al contenido representado de un objeto visual. Utilizando el valor del parámetro PointHitTestParameters valor del método HitTestCore de reemplazo como parámetro para HitTestCore del método base, puede realizar acciones basadas en un posicionamiento en el rectángulo delimitador de un objeto visual y, a continuación, realizar una segunda prueba de posicionamiento respecto al contenido representado del objeto visual.

        ' 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
// 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);
}

Vea también

Tareas

Cómo: Geometría de una prueba de seguimiento en un objeto visual

Cómo: Realizar pruebas de posicionamiento mediante un contenedor host Win32

Referencia

HitTest

HitTestResult

HitTestResultCallback

HitTestFilterCallback

IsHitTestVisible

Otros recursos

Hit Test Using DrawingVisuals Sample

Hit Test with Win32 Interoperation Sample