Test d'atteinte dans la couche visuelle

Mise à jour : novembre 2007

Cette rubrique propose une vue d'ensemble de la fonctionnalité de test d'atteinte fournie par la couche visuelle. La prise en charge du test d'atteinte 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 d'atteinte
  • Prise en charge du test d'atteinte
  • Test d'atteinte et ordre de plan
  • Utilisation du test d'atteinte par défaut
  • Utilisation d'un rappel des résultats du test d'atteinte
  • Utilisation d'un rappel de filtre du test d'atteinte
  • Substitution du test d'atteinte par défaut
  • Rubriques connexes

Scénarios de test d'atteinte

La classe UIElement fournit la méthode InputHitTest, qui vous permet d'effectuer un test d'atteinte 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 d'atteinte d'éléments. Cependant, dans plusieurs scénarios, vous devrez peut-être implémenter le test d'atteinte au niveau de la couche visuelle.

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

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

  • Test d'atteinte sur plusieurs objets : ce scénario est d'application lorsque vous devez effectuer un test d'atteinte 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 d'atteinte UIElement : ce scénario est d'application lorsque vous devez ignorer la stratégie de test d'atteinte UIElement, qui prend en compte des facteurs tels que le fait qu'un élément est désactivé ou invisible.

Remarque :

Pour un exemple de code complet illustrant le test d'atteinte au niveau la couche visuelle, consultez Test d'atteinte à l'aide de DrawingVisuals, exemple et Test d'atteinte avec interopérabilité Win32, exemple.

Prise en charge du test d'atteinte

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 d'atteinte 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 d'atteinte pour effectuer vos propres calculs de test d'atteinte 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 d'atteinte valide

Diagramme de la région de test de positionnement valide

Test d'atteinte et ordre de plan

La couche visuelle de Windows Presentation Foundation (WPF) prend en charge le test d'atteinte 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 d'atteinte. Vous pouvez effectuer le test d'atteinte 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 d'atteinte 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 d'atteinte visuelle pour qu'elle retourne Stop depuis HitTestResultCallback afin d'interrompre le parcours du test d'atteinte 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 d'atteinte 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 d'atteinte" pour plus d'informations.

Remarque :

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

Utilisation du test d'atteinte 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 d'atteinte. 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 d'atteinte, HitTest retourne null.

Remarque :

Le test d'atteinte 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 d'atteinte.

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 d'atteinte. Par exemple, si vous imbriquez des objets visuels définis à (100, 100) dans l'espace de coordonnées du parent, un test d'atteinte d'un enfant visuel à (0, 0) équivaut à un test d'atteinte à (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 d'atteinte.

// 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 d'atteinte

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 d'atteinte des objets. Si vous effectuez un test d'atteinte 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 d'atteinte 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

Remarque :

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 d'atteinte 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 d'atteinte.

Utilisation d'un rappel des résultats du test d'atteinte

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 d'atteinte. La fonction de rappel de test d'atteinte 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 d'atteinte, 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 d'atteinte.

// 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 d'atteinte définit les actions que vous exécutez lorsqu'un test d'atteinte 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 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;
}
Remarque :

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 d'atteinte en retournant Stop.

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

Utilisation d'un rappel de filtre du test d'atteinte

Vous pouvez utiliser un filtre de test d'atteinte pour restreindre les objets transmis aux résultats du test d'atteinte. Cela vous permet d'ignorer les parties de l'arborescence visuelle que vous ne souhaitez pas traiter dans vos résultats de test d'atteinte. Pour implémenter un filtre de test d'atteinte, vous devez définir une fonction de rappel de filtre du test d'atteinte 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 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 d'atteinte, 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,
                  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 d'atteinte 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 d'atteinte. La valeur de retour de la fonction de rappel de filtre du test d'atteinte détermine le type d'action que l'énumération des objets visuels doit exécuter. 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 d'atteinte. Cela signifie que la fonction de rappel des résultats du test d'atteinte 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 d'atteinte. Dans l'exemple de code suivant, le filtre ignore certaines étiquettes et leurs descendants et effectue un test d'atteinte 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;
    }
}
Remarque :

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

Substitution du test d'atteinte par défaut

Vous pouvez substituer la prise en charge du test d'atteinte 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 d'atteinte 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 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 d'atteinte 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 d'atteinte sur le rectangle englobant d'un objet visuel, puis un deuxième test d'atteinte sur le contenu rendu.

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

Test d'atteinte à l'aide de DrawingVisuals, exemple

Test d'atteinte avec interopérabilité Win32, exemple

Comment : effectuer un test d'atteinte avec Geometry dans un Visual

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

Référence

HitTest

HitTestResult

HitTestResultCallback

HitTestFilterCallback

IsHitTestVisible