Test de positionnement dans la couche visuelle

Cette rubrique fournit une vue d’ensemble de la fonctionnalité de test de positionnement fournie par la couche visuelle. La prise en charge des tests de positionnement vous permet de déterminer si une valeur géométrique ou de point se trouve dans le contenu rendu d’un Visual, ce qui vous permet d’implémenter un comportement d’interface utilisateur tel qu’un rectangle de sélection pour sélectionner plusieurs objets.

Scénarios de test de positionnement

La UIElement classe fournit la InputHitTest méthode, qui vous permet d’effectuer un test sur un élément à l’aide d’une valeur de coordonnée donnée. Dans de nombreux cas, la InputHitTest méthode fournit les fonctionnalités souhaitées pour implémenter le test de positionnement des éléments. Toutefois, il existe plusieurs scénarios dans lesquels vous devrez peut-être implémenter le test de positionnement sur la couche visuelle.

  • Test d’accès sur des objets non-objetsUIElement : cela s’applique si vous testez des objets non-objetsUIElement , tels que DrawingVisual des objets graphiques.

  • Test de positionnement à l’aide d’une géométrie : cela s’applique si vous avez besoin d’effectuer un test de positionnement à l’aide d’un objet géométrique plutôt que la valeur des coordonnées d’un point.

  • Test de positionnement sur plusieurs objets : cela s’applique lorsque vous devez effectuer un test de positionnement sur plusieurs objets, tels que des objets superposés. Vous pouvez obtenir des résultats pour tous les objets visuels croisant une géométrie ou un point, pas seulement le premier.

  • Ignorer la stratégie de test de UIElement positionnement : cela s’applique lorsque vous devez ignorer la stratégie de test de positionnement, ce qui prend en compte des facteurs tels que la désactivation ou l’invisible UIElement d’un élément.

Remarque

Pour un exemple de code complet illustrant le test de positionnement sur la couche visuelle, consultez Test de positionnement à l’aide de l’exemple DrawingVisuals et Test de positionnement avec l’exemple Interopérabilité Win32.

Prise en charge du test de positionnement

L’objectif des HitTest méthodes de la VisualTreeHelper classe est de déterminer si une valeur de coordonnée de géométrie ou de point se trouve dans le contenu rendu d’un objet donné, tel qu’un contrôle ou un élément graphique. Par exemple, vous pouvez utiliser le test de positionnement pour déterminer si un clic de souris dans le rectangle englobant d’un objet se trouve dans la géométrie d’un cercle. Vous pouvez également choisir de substituer l’implémentation par défaut du test de positionnement pour effectuer vos propres calculs de test de positionnement personnalisés.

L’illustration suivante montre la relation entre la région d’un objet non rectangulaire et son rectangle englobant.

Diagram of valid hit test region
Diagramme de la région de test de positionnement valide

Test de positionnement et ordre de plan

La couche visuelle WPF (Windows Presentation Foundation) prend en charge les tests de positionnement sur tous les objets sous un point ou une géométrie, pas seulement l’objet le plus haut. Les résultats sont retournés dans l’ordre de plan. Toutefois, l’objet visuel que vous passez en tant que paramètre à la HitTest méthode détermine la partie de l’arborescence visuelle qui sera testée. Vous pouvez effectuer un test de positionnement sur l’arborescence visuelle entière ou une portion de celle-ci.

Dans l’illustration suivante, l’objet cercle est au-dessus des objets carré et triangle. Si vous n’êtes intéressé que par le test de positionnement de l’objet visuel dont la valeur z-order est la plus élevée, vous pouvez définir l’énumération du test d’accès visuel pour retourner Stop à partir de la HitTestResultCallback traversée du test d’accès après le premier élément.

Diagram of the z-order of a visual tree
Diagramme de l’ordre de plan d’une arborescence d’éléments visuels

Si vous souhaitez énumérer tous les objets visuels sous un point ou une géométrie spécifique, retournez Continue à partir du HitTestResultCallback. Cela signifie que vous pouvez effectuer un test de positionnement pour des objets visuels situés sous d’autres objets, même s’ils sont complètement masqués. Pour plus d’informations, consultez l’exemple de code dans la section « Utilisation du rappel des résultats d’un test de positionnement ».

Remarque

Un objet visuel transparent peut également être l’objet d’un test de positionnement.

Utilisation du test de positionnement par défaut

Vous pouvez identifier si un point se trouve dans la géométrie d’un objet visuel, à l’aide de la HitTest méthode pour spécifier un objet visuel et une valeur de coordonnée de point à tester. Le paramètre de l’objet visuel identifie le point de départ dans l’arborescence visuelle pour la recherche du test de positionnement. Si un objet visuel se trouve dans l’arborescence visuelle dont la géométrie contient la coordonnée, elle est définie sur la VisualHit propriété d’un HitTestResult objet. Il HitTestResult est ensuite retourné à partir de la HitTest méthode. Si le point n’est pas contenu avec la sous-arborescence visuelle que vous testez, HitTest retourne null.

Remarque

Le test de positionnement par défaut retourne toujours l’objet de plus haut niveau dans l’ordre de plan. Afin d’identifier tous les objets visuels, y compris ceux partiellement ou entièrement cachés, utilisez un rappel des résultats du test de positionnement.

La valeur de coordonnée que vous passez en tant que paramètre de point pour la HitTest méthode doit être relative à l’espace de coordonnées de l’objet visuel sur lequel vous effectuez des tests. Par exemple, si vous avez imbriqué des objets visuels définis sur (100, 100) dans l’espace des coordonnées du parent, alors le test de positionnement sur un objet visuel enfant à (0, 0) est équivalent au test de positionnement sur (100, 100) dans l’espace des coordonnées du parent.

Le code suivant montre comment configurer des gestionnaires d’événements de souris pour un UIElement objet utilisé pour capturer des événements utilisés pour les tests de positionnement.

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

Impact de l’arborescence visuelle sur le test de positionnement

Le point de départ dans l’arborescence visuelle détermine quels objets sont retournés lors de l’énumération du test de positionnement des objets. Si vous avez plusieurs objets sur lesquels vous voulez effectuer un test de positionnement, l’objet visuel utilisé comme point de départ de l’arborescence visuelle doit être l’ancêtre commun de tous les objets concernés. Par exemple, si vous voulez effectuer un test de positionnement sur l’élément bouton et l’objet visuel de dessin dans le diagramme suivant, vous devez définir le point de départ dans l’arborescence visuelle sur l’ancêtre commun des deux. Dans ce cas, l’élément canevas est l’ancêtre commun de l’élément bouton et de l’objet visuel de dessin.

Diagram of a visual tree hierarchy
Diagramme d’une hiérarchie d’arborescence d’éléments visuels

Remarque

La IsHitTestVisible propriété obtient ou définit une valeur qui déclare si un UIElementobjet dérivé peut éventuellement être retourné en tant que résultat de test de positionnement à partir d’une partie de son contenu rendu. Cela vous permet de modifier de manière sélective l’arborescence visuelle afin de déterminer les objets visuels impliqués dans un test de positionnement.

Utilisation d’un rappel des résultats du test de positionnement

Vous pouvez énumérer tous les objets visuels dans une arborescence visuelle dont la géométrie contient une valeur des coordonnées spécifiée. Cela vous permet d’identifier tous les objets visuels, y compris ceux partiellement ou entièrement cachés par d’autres objets visuels. Pour énumérer des objets visuels dans une arborescence visuelle, utilisez la HitTest méthode avec une fonction de rappel de test de positionnement. La fonction de rappel du test de positionnement est appelée par le système lorsque la valeur des coordonnées que vous spécifiez est contenue dans un objet visuel.

Lors de l’énumération des résultats du test de positionnement, vous ne devez effectuer aucune opération susceptible de modifier l’arborescence visuelle. L’ajout ou la suppression d’un objet dans l’arborescence visuelle pendant qu’il est parcouru peut entraîner un comportement imprévisible. Vous pouvez modifier en toute sécurité l’arborescence visuelle une fois la HitTest méthode retournée. Vous pouvez fournir une structure de données, telle qu’un ArrayList, pour stocker des valeurs pendant l’énumération des résultats du test de positionnement.

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

La méthode de rappel du test de positionnement définit les actions que vous effectuez lorsqu’un test de positionnement est identifié sur un objet visuel particulier dans l’arborescence visuelle. Après avoir effectué les actions, vous retournez une HitTestResultBehavior valeur qui détermine s’il faut continuer l’énumération d’autres objets visuels ou non.

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

Remarque

L’ordre d’énumération des objets visuels de positionnement se fait selon l’ordre de plan. L’objet visuel au niveau de l’ordre de plan le plus élevé est le premier objet énuméré. Les autres objets visuels énumérés le sont dans l’ordre de plan décroissant. Cet ordre d’énumération correspond à l’ordre de rendu des objets visuels.

Vous pouvez arrêter l’énumération des objets visuels à tout moment dans la fonction de rappel de test de positionnement en retournant Stop.

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

Utilisation d’un rappel de filtre du test de positionnement

Vous pouvez utiliser un filtre de test de positionnement facultatif pour restreindre les objets transmis aux résultats du test de positionnement. Ceci vous permet d’ignorer les parties de l’arborescence d’éléments visuels que vous ne souhaitez pas traiter dans vos résultats de test de positionnement. Pour implémenter un filtre de test de positionnement, vous définissez une fonction de rappel de filtre de test de positionnement et transmettez-la en tant que valeur de paramètre lorsque vous appelez la HitTest méthode.

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

Si vous ne souhaitez pas fournir la fonction de rappel de filtre de test de positionnement facultative, transmettez une null valeur en tant que paramètre pour la HitTest méthode.

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

Pruning a visual tree using a hit test filter
Élagage d’une arborescence visuelle

La fonction de rappel de filtre de test de positionnement permet d’énumérer tous les objets visuels dont le contenu rendu contient les coordonnées que vous spécifiez. Toutefois, vous pouvez ignorer certaines branches de l’arborescence d’éléments visuels que vous ne souhaitez pas traiter dans votre fonction de rappel des résultats de test de positionnement. La valeur de retour de la fonction de rappel de filtre de test de positionnement détermine le type d’action que l’énumération des objets visuels doit prendre. Par exemple, si vous retournez la valeur, ContinueSkipSelfAndChildrenvous pouvez supprimer l’objet visuel actuel et ses enfants de l’énumération des résultats du test de positionnement. Cela signifie que la fonction de rappel des résultats de test de positionnement ne verra pas ces objets dans son énumération. L’élagage des objets dans l’arborescence visuelle diminue la quantité de traitement au cours de la passe de l’énumération des résultats de test de positionnement. Dans l’exemple de code suivant, le filtre ignore les étiquettes et leurs descendants et effectue un test de positionnement sur tout le reste.

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

Remarque

Le rappel de filtre du test de positionnement est parfois appelé dans les cas où le rappel des résultats du test d’atteinte n’est pas appelé.

Substitution du test de positionnement par défaut

Vous pouvez remplacer la prise en charge des tests d’accès par défaut d’un objet visuel en remplaçant la HitTestCore méthode. Cela signifie que lorsque vous appelez la HitTest méthode, votre implémentation HitTestCore substituée est appelée. Votre méthode substituée est appelée lorsqu’un test de positionnement se situe dans le rectangle englobant de l’objet visuel, même si les coordonnées se situent en dehors du contenu rendu de l’objet visuel.

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

Vous voudrez parfois effectuer un nouveau test de positionnement sur le rectangle englobant et le contenu rendu d’un objet visuel. En utilisant la valeur du PointHitTestParameters paramètre dans votre méthode substituée HitTestCore comme paramètre de la méthode HitTestCorede base, vous pouvez effectuer des actions en fonction d’un résultat du rectangle englobant d’un objet visuel, puis effectuer un deuxième test d’accès sur le contenu rendu de l’objet visuel.

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

Voir aussi