Treffer testen in de visuallaag
In dit onderwerp vindt u een overzicht van de hit testing-functionaliteit die door de visuallaag wordt geboden. Met ondersteuning voor hittests kunt u bepalen of een geometrie- of puntwaarde binnen de weergegeven inhoud van een Visualvalt, zodat u gebruikersinterfacegedrag zoals een selectierechthoek kunt implementeren om meerdere objecten te selecteren.
Scenario's voor hittesten
De UIElement-klasse biedt de InputHitTest methode, waarmee u kunt testen op een element met behulp van een bepaalde coördinaatwaarde. In veel gevallen biedt de InputHitTest methode de gewenste functionaliteit voor het implementeren van hittests van elementen. Er zijn echter verschillende scenario's waarin u mogelijk hittests op de visuallaag moet implementeren.
Wanneer u test op aanraakgevoeligheid van niet-UIElement objecten: Dit is relevant als u test op niet-UIElement objecten, zoals DrawingVisual of grafische objecten.
Hit-testen met behulp van een geometrie: Dit is van toepassing als u een hit-test moet doen met behulp van een geometrieobject in plaats van de coördinaatwaarde van een punt.
Hit testen tegen meerdere objecten: Dit is van toepassing wanneer je moet hit testen tegen meerdere objecten, zoals overlappende objecten. U kunt resultaten krijgen voor alle visuals die een geometrie of punt kruisen, niet alleen de eerste.
Negeren van UIElement beleid voor het testen van treffers: dit geldt wanneer u het beleid voor het testen van UIElement moet negeren, waarbij rekening wordt gehouden met factoren zoals of een element is uitgeschakeld of onzichtbaar is.
Notitie
Zie Hit Test met behulp van DrawingVisuals voorbeeld en Hit Test met Win32 Interoperability voorbeeldvoor een volledig codevoorbeeld dat het testen van treffers op de visuallaag illustreert.
Ondersteuning voor aanrakingsdetectie
Het doel van de HitTest methoden in de VisualTreeHelper klasse is om te bepalen of een geometrie- of puntcoördinaatwaarde zich in de gerenderde inhoud van een bepaald object bevindt, zoals een besturingselement of grafisch element. U kunt bijvoorbeeld hittests gebruiken om te bepalen of een muisklik binnen de begrenzingsrechthoek van een object binnen de geometrie van een cirkel valt. U kunt er ook voor kiezen om de standaard implementatie van hittests te overschrijven om uw eigen aangepaste hittestberekeningen uit te voeren.
In de volgende afbeelding ziet u de relatie tussen het gebied van een niet-rechthoekig object en de bijbehorende begrenzingsrechthoek.
Diagram van geldige treffertestregio
Hit Testing en Z-Order
De visuallaag WPF (Windows Presentation Foundation) biedt ondersteuning voor het testen van treffers voor alle objecten onder een punt of geometrie, niet alleen voor het meest bovenste object. Resultaten worden geretourneerd in z-volgorde. Het visuele object dat u als parameter doorgeeft aan de methode HitTest, bepaalt echter welk deel van de visuele boom zal worden getoetst. U kunt een test uitvoeren op de hele visualstructuur of een deel ervan.
In de volgende afbeelding bevindt het cirkelobject zich boven op zowel de vierkant- als driehoekobjecten. Als u alleen geïnteresseerd bent in het testen van het visuele object waarvan de z-orderwaarde het meest hoog is, kunt u de opsomming van de visual hittest instellen om Stop te retourneren uit de HitTestResultCallback om de doorkruising van de hittest na het eerste item te stoppen.
Diagram van de z-volgorde van een visuele boom
Als u alle visuele objecten onder een specifiek punt of geometrie wilt inventariseren, retourneert u Continue uit de HitTestResultCallback. Dit betekent dat u visuele objecten kunt testen die zich onder andere objecten bevinden, zelfs als ze volledig verborgen zijn. Zie de voorbeeldcode in de sectie "Using a Hit Test Results Callback" (Een callback van hittestresultaten gebruiken) voor meer informatie.
Notitie
Een visueel object dat transparant is, kan ook worden getest op botsing.
De standaardinstellingen voor hit testing gebruiken
U kunt bepalen of een punt zich in de geometrie van een visueel object bevindt met behulp van de methode HitTest om een visueel object en een puntcoördinaatwaarde op te geven waarop moet worden getest. De visuele objectparameter identificeert het beginpunt in de visuele boom voor de hittest-zoekactie. Als er een visueel object wordt gevonden in de visuele boom waarvan de geometrie de coördinaat bevat, wordt het ingesteld op de VisualHit-eigenschap van een HitTestResult-object. De HitTestResult wordt vervolgens geretourneerd vanuit de methode HitTest. Als het punt niet is opgenomen in de visuele substructuur waarop u test, retourneert HitTestnull
.
Notitie
Standaard raakdetectie retourneert altijd het bovenste object in de z-volgorde. Gebruik een callback voor hittestresultaten om alle visuele objecten te identificeren, zelfs objecten die gedeeltelijk of volledig verborgen kunnen zijn.
De coördinaatwaarde die u als puntparameter voor de HitTest methode doorgeeft, moet relatief zijn ten opzichte van de coördinaatruimte van het visuele object waarop u het testen uitvoert. Als u bijvoorbeeld geneste visuele objecten hebt gedefinieerd op (100, 100) in de coördinaatruimte van het ouder-element, dan is het uitvoeren van een raaktest op een onderliggend visueel object op (0, 0) gelijk aan een raaktest op (100, 100) in de coördinaatruimte van het ouder-element.
De volgende code laat zien hoe u muisgebeurtenishandlers instelt voor een UIElement-object dat wordt gebruikt om gebeurtenissen vast te leggen voor het hit-testen.
// 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
Hoe de visuele boom van invloed is op hit-testen
Het beginpunt in de visuele boom bepaalt welke objecten worden geretourneerd tijdens de opsomming van objecten voor hittesting. Als u meerdere objecten hebt die u wilt testen, moet het visuele object dat als uitgangspunt in de visualstructuur wordt gebruikt, de gemeenschappelijke voorouder van alle interessante objecten zijn. Als u bijvoorbeeld geïnteresseerd bent in het uitvoeren van een raaktest op zowel het knopelement als de tekenvisual in het volgende diagram, dan moet u het beginpunt in de visuele structuur instellen op de gemeenschappelijke voorouder van beide. In dit geval is het canvaselement de gemeenschappelijke voorouder van zowel het knopelement als de tekenvisual.
Diagram van een visuale boomstructuurhiërarchie
Notitie
Met de eigenschap IsHitTestVisible wordt een waarde opgehaald of ingesteld waarmee wordt aangegeven of een UIElement-afgeleide object mogelijk kan worden geretourneerd als een hittestresultaat van een deel van de weergegeven inhoud. Hiermee kunt u de visuele boom selectief wijzigen om vast te stellen welke visuele objecten betrokken zijn bij een hittest.
Een callback voor hittestresultaten gebruiken
U kunt alle visuele objecten in een visuele boom opsommen waarvan de geometrie een opgegeven coördinaatwaarde bevat. Hiermee kunt u alle visuele objecten identificeren, zelfs objecten die gedeeltelijk of volledig zijn verborgen door andere visuele objecten. Als u visuele objecten in een visuele boom wilt inventariseren, gebruikt u de HitTest-methode met een hittest-callbackfunctie. De callback-functie hittest wordt aangeroepen door het systeem wanneer de coördinaatwaarde die u opgeeft zich in een visueel object bevindt.
Tijdens de opsomming van de resultaten van de hittest moet u geen bewerkingen uitvoeren waarmee de visualstructuur wordt gewijzigd. Het toevoegen of verwijderen van een object uit de visuele structuur terwijl het wordt doorkruist, kan leiden tot onvoorspelbaar gedrag. U kunt de visuele boom veilig wijzigen nadat de methode HitTest retourneert. U kunt een gegevensstructuur, zoals een ArrayList, opgeven om waarden op te slaan tijdens de opsomming van de hittestresultaten.
// 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
Met de callbackmethode hit-test worden de acties gedefinieerd die u uitvoert wanneer een hit-test wordt gedetecteerd op een bepaald visueel object in de visuele structuur. Nadat u de acties hebt uitgevoerd, retourneert u een HitTestResultBehavior waarde die bepaalt of u de opsomming van andere visuele objecten wilt voortzetten of niet.
// 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
Notitie
De volgorde van opsomming van weergegeven visuele objecten is volgens z-index volgorde. Het visuele object op het hoogste z-volgordeniveau is het eerste object dat is geïnventariseerd. Alle andere opgesomde visuele objecten bevinden zich op een afnemend z-volgordeniveau. Deze volgorde van opsomming komt overeen met de weergavevolgorde van de visuals.
U kunt op elk gewenst moment de opsomming van visuele objecten stoppen door Stopte retourneren in de hittest-callbackfunctie.
// Set the behavior to stop enumerating visuals.
return HitTestResultBehavior.Stop;
' Set the behavior to stop enumerating visuals.
Return HitTestResultBehavior.Stop
Een callback-functie voor hittests gebruiken
U kunt een optioneel hittestfilter gebruiken om de objecten te beperken die worden doorgegeven aan de resultaten van de hittest. Hiermee kunt u delen van de visuele boom overslaan die u niet wilt verwerken in de resultaten van de hittest. Als u een treffertestfilter wilt implementeren, definieert u een callbackfunctie voor het trefferfilter en geeft u deze door als parameterwaarde wanneer u de methode HitTest aanroept.
// 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
Als u de optionele callbackfunctie voor hittestfilters niet wilt opgeven, geef dan een null
-waarde door als parameter voor de methode 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));
' 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.
Een visuele boom snoeien
Met de callback-functie hittestfilter kunt u alle visuals opsommen waarvan de weergegeven inhoud de coördinaten bevat die u opgeeft. U kunt echter bepaalde vertakkingen van de visuele structuur negeren die u niet wilt verwerken in de callback-functie voor hittestresultaten. De retourwaarde van de callbackfunctie voor het hittestfilter bepaalt welk type actie de enumeratie van de visuele objecten moet uitvoeren. Als u bijvoorbeeld de waarde retourneert, ContinueSkipSelfAndChildren, kunt u het huidige visuele object en de onderliggende elementen uit de opsomming met resultaten van de hittest verwijderen. Dit betekent dat de callback-functie voor hittestresultaten deze objecten niet in de opsomming ziet. Door de visuele boomstructuur van objecten te snoeien, wordt de hoeveelheid verwerking tijdens de opsomming van de resultaten van de hit-test verlaagd. In het volgende codevoorbeeld slaat het filter labels en hun subelementen over en worden hit-tests op al het overige uitgevoerd.
// 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
Notitie
De callback van het hittestfilter wordt soms aangeroepen in gevallen waarin de callback van de hittestresultaten niet wordt aangeroepen.
Standaardprocedure voor hittesten overschrijven
U kunt de standaardondersteuning voor het testen van treffers van een visueel object overschrijven door de methode HitTestCore te overschrijven. Dit betekent dat wanneer u de methode HitTest aanroept, uw overschreven implementatie van HitTestCore wordt aangeroepen. Uw overschreven methode wordt aangeroepen wanneer een hittest binnen de begrenzingsrechthoek van het visuele object valt, zelfs als de coördinaat buiten de weergegeven inhoud van het visuele object valt.
// 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
Het kan voorkomen dat u een test wilt uitvoeren op zowel de begrenzingsrechthoek als de gerenderde inhoud van een visueel object. Met de parameterwaarde PointHitTestParameters
in uw overschreven methode HitTestCore als invoer voor de basismethode HitTestCore, kunt u handelingen uitvoeren op basis van een treffer binnen de begrenzingsrechthoek van een visueel object en vervolgens een tweede hittest uitvoeren op de gerenderde inhoud van dat visuele object.
// 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
Zie ook
.NET Desktop feedback