Partager via


Test de positionnement dans la couche visuelle

Cette rubrique propose une vue d'ensemble de la fonctionnalité de test de positionnement fournie par la couche visuelle. La prise en charge du test de positionnement vous permet de déterminer si la valeur d'une géométrie ou d'un point tombe 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.

Cette rubrique comprend les sections suivantes.

  • Scénarios de test de positionnement
  • Prise en charge du test de positionnement
  • Test de positionnement et ordre de plan
  • Utilisation du test de positionnement par défaut
  • Utilisation d'un rappel des résultats du test de positionnement
  • Utilisation d'un rappel de filtre du test de positionnement
  • Substitution du test de positionnement par défaut
  • Rubriques connexes

Scénarios de test de positionnement

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

  • Test de positionnement sur des objets non UIElement : ce scénario est d'application si vous effectuez un test de positionnement sur des objets non UIElement, tels que DrawingVisual ou des objets graphiques.

  • Test de positionnement à l'aide d'une géométrie : ce scénario s'applique si vous devez effectuer un test de positionnement à l'aide d'un objet de géométrie plutôt que de la valeur de coordonnée d'un point.

  • Test de positionnement sur plusieurs objets : ce scénario est d'application lorsque vous devez effectuer un test de positionnement sur plusieurs objets, tels que des objets chevauchants. Vous pouvez obtenir des résultats pour tous les visuels croisant une géométrie ou un point, et pas seulement pour le premier.

  • Ignorer la stratégie de test de positionnement UIElement : ce scénario est d'application lorsque vous devez ignorer la stratégie de test de positionnement UIElement, qui prend en compte des facteurs tels que le fait qu'un élément est désactivé ou invisible.

RemarqueRemarque

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

Prise en charge du test de positionnement

Le but des méthodes HitTest dans la classe VisualTreeHelper est de déterminer si la valeur de coordonnée d'une géométrie ou d'un point est comprise dans le contenu rendu d'un objet donné, tel qu'un contrôle ou un élément graphique. Vous pouvez par exemple utiliser le test de positionnement pour déterminer si un clic de souris dans le rectangle englobant d'un objet tombe 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.

Diagramme de la région de test de positionnement valide

Diagramme de la région de test de positionnement valide

Test de positionnement et ordre de plan

La couche visuelle de Windows Presentation Foundation (WPF) prend en charge le test de positionnement sur tous les objets situés sous un point ou une géométrie, et pas seulement sur ceux de premier niveau. Les résultats sont retournés sous la forme d'un ordre de plan. L'objet visuel que vous passez en tant que paramètre à la méthode HitTest détermine toutefois la partie de l'arborescence visuelle qui sera soumise au test de positionnement. Vous pouvez effectuer le test de positionnement sur l'intégralité de l'arborescence visuelle ou sur une partie.

Dans l'illustration suivante, l'objet cercle est à la fois sur le carré et le triangle. Si vous souhaitez uniquement effectuer le test de positionnement sur l'objet visuel dont la valeur de l'ordre de plan est de premier niveau, vous pouvez définir l'énumération du test de positionnement visuelle pour qu'elle retourne Stop depuis HitTestResultCallback afin d'interrompre le parcours du test de positionnement après le premier élément.

Diagramme de l'ordre de plan d'une arborescence visuelle

Diagramme de l'ordre de plan d'une arborescence d'éléments visuels

Si vous souhaitez énumérer tous les objets visuels situés sous un point ou une géométrie spécifique, retournez Continue depuis 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. Consultez l'exemple de code dans la section « Utilisation d'un rappel des résultats du test de positionnement » pour plus d'informations.

RemarqueRemarque

Un objet visuel transparent peut également faire l'objet d'un test de positionnement.

Utilisation du test de positionnement par défaut

Vous pouvez déterminer si un point se trouve dans la géométrie d'un objet visuel en utilisant la méthode HitTest pour spécifier un objet visuel et la valeur de coordonnée d'un point sur lesquels effectuer le test. Le paramètre d'objet visuel identifie le point de départ au sein de l'arborescence visuelle pour la recherche de test de positionnement. Si un objet visuel dont la géométrie contient la coordonnée est retrouvé dans l'arborescence visuelle, il prend la valeur de la propriété VisualHit d'un objet HitTestResult. L'objet HitTestResult est ensuite retourné à partir de la méthode HitTest. Si le point n'est pas contenu dans la sous-arborescence visuelle sur laquelle vous effectuez le test de positionnement, HitTest retourne null.

RemarqueRemarque

Le test de positionnement par défaut retourne toujours l'objet de premier niveau dans l'ordre de plan.Pour identifier tous les objets visuels, y compris ceux masqués partiellement ou totalement, utilisez un rappel des résultats du test de positionnement.

La valeur de coordonnée que vous passez au paramètre du point pour la méthode HitTest doit être relative par rapport à l'espace de coordonnées de l'objet visuel qui fait l'objet du test de positionnement. Par exemple, si vous imbriquez des objets visuels définis à (100, 100) dans l'espace de coordonnées du parent, un test de positionnement d'un enfant visuel à (0, 0) équivaut à un test de positionnement à (100, 100) dans l'espace de coordonnées du parent.

Le code suivant montre comment configurer des gestionnaires d'événement de souris pour un objet UIElement utilisé pour capturer des événements utilisés pour le test de positionnement.

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

Impact de l'arborescence visuelle sur le test de positionnement

Le point de départ défini au sein de l'arborescence visuelle détermine les objets retournés lors de l'énumération du test de positionnement des objets. Si vous effectuez un test de positionnement sur plusieurs objets, l'objet visuel utilisé comme point de départ dans l'arborescence d'éléments visuels doit être l'ancêtre commun de tous les objets en question. Par exemple, si vous voulez effectuer un test de positionnement de l'élément bouton et du visuel du dessin dans le diagramme suivant, vous devez définir comme point de départ dans l'arborescence visuelle l'ancêtre commun de ces deux objets. Dans ce cas, l'élément zone de dessin est l'ancêtre commun de l'élément bouton et du visuel du dessin.

Diagramme d'une hiérarchie d'une arborescence visuelle

Diagramme d'une hiérarchie d'arborescence d'éléments visuels

RemarqueRemarque

La propriété IsHitTestVisible obtient ou définit une valeur qui déclare si un objet dérivé de UIElement peut être retourné en tant que résultat de test de positionnement depuis 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 concernés par un test de positionnement.

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

Vous pouvez énumérer tous les objets visuels d'une arborescence visuelle dont la géométrie contient une valeur de coordonnée spécifiée. Cela vous permet d'identifier tous les objets visuels, y compris ceux masqués totalement ou partiellement par d'autres. L'énumération des objets visuels d'une arborescence visuelle fait appel à la méthode HitTest associée à une fonction de rappel de test de positionnement. La fonction de rappel de test de positionnement est appelée par le système lorsque la valeur de coordonnée 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 modifiant l'arborescence visuelle. L'ajout ou la suppression d'un objet de l'arborescence visuelle pendant qu'elle est parcourue peut en effet déboucher sur un comportement imprévisible. Vous pouvez modifier l'arborescence visuelle en toute sécurité après que la méthode HitTest a été retournée. Vous pouvez fournir une structure de données, telle qu'une classe ArrayList, pour stocker des valeurs lors de 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 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);
    }
}

La méthode de rappel de test de positionnement définit les actions que vous exécutez lorsqu'un test de positionnement est identifié sur un objet visuel particulier dans l'arborescence visuelle. Après avoir exécuté les actions, vous retournez une valeur HitTestResultBehavior qui détermine si l'énumération d'autres objets visuels doit ou non se poursuivre.

        ' 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;
}
RemarqueRemarque

L'énumération des objets visuels atteints se fait selon l'ordre de plan.L'objet visuel de premier niveau dans l'ordre de plan est le premier objet énuméré.Les objets visuels restants sont ensuite énumérés dans l'ordre de plan décroissant.Cet ordre d'énumération correspond à l'ordre de rendu des visuels.

Vous pouvez arrêter l'énumération d'objets visuels à tout moment durant l'exécution de 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 pour restreindre les objets transmis aux résultats du test de positionnement. Cela vous permet d'ignorer les parties de l'arborescence visuelle que vous ne souhaitez pas traiter dans vos résultats de test de positionnement. Pour implémenter un filtre de test de positionnement, vous devez définir une fonction de rappel de filtre du test de positionnement et la passez en tant que valeur de paramètre lorsque vous appelez la méthode 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 vous ne souhaitez pas utiliser la fonction de rappel de filtre du test de positionnement, passez la valeur de paramètre null pour la méthode 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));

Nettoyage d'une arborescence visuelle

Élagage d'une arborescence d'éléments visuels à l'aide d'un filtre de test de positionnement

La fonction de rappel de filtre du test de positionnement vous permet d'énumérer tous les visuels dont le contenu rendu contient les coordonnées que vous spécifiez. Vous pouvez toutefois choisir d'ignorer certaines branches de l'arborescence visuelle que vous ne voulez pas traiter dans votre fonction de rappel des résultats du test de positionnement. La valeur de retour de la fonction de rappel du filtre du 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, ContinueSkipSelfAndChildren, vous 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 du test de positionnement ne verra pas ces objets dans son énumération. Le nettoyage de l'arborescence visuelle d'objets diminue le temps du traitement pendant le passe de l'énumération des résultats du test de positionnement. Dans l'exemple de code suivant, le filtre ignore certaines é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 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;
    }
}
RemarqueRemarque

Le rappel de filtre du test de positionnement est parfois appelé lorsque le rappel des résultats du test de positionnement ne l'est pas.

Substitution du test de positionnement par défaut

Vous pouvez substituer la prise en charge du test de positionnement par défaut d'un objet visuel en substituant la méthode HitTestCore. Cela signifie que lorsque vous appelez la méthode HitTest, votre implémentation substituée de HitTestCore est appelée. Votre méthode substituée est appelée lorsqu'un test de positionnement tombe dans le rectangle englobant de l'objet visuel, même si la coordonnée tombe en dehors du contenu rendu de l'objet visuel.

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

Il peut arriver que vous souhaitiez effectuer le test de positionnement en même temps sur le rectangle englobant et le contenu rendu d'un objet visuel. En utilisant la valeur de paramètre PointHitTestParameters dans votre méthode HitTestCore substituée en guise de paramètre pour la méthode de base HitTestCore, vous pouvez effectuer un test de positionnement sur le rectangle englobant d'un objet visuel, puis un deuxième test de positionnement sur le contenu rendu.

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

Voir aussi

Tâches

Comment : effectuer un test de positionnement avec Geometry dans un Visual

Comment : effectuer un test de positionnement à l'aide d'un conteneur hôte Win32

Référence

HitTest

HitTestResult

HitTestResultCallback

HitTestFilterCallback

IsHitTestVisible

Autres ressources

Test de positionnement à l'aide de DrawingVisuals, exemple (page éventuellement en anglais)

Test de positionnement avec interopérabilité Win32, exemple (page éventuellement en anglais)