Sdílet prostřednictvím


Spuštění testování ve vizuální vrstvě

Toto téma obsahuje přehled funkcí testování, které poskytuje vizuální vrstva. Podpora testování hitů umožňuje určit, zda geometrie nebo bodová hodnota spadá do vykresleného obsahu objektu Visual, který umožňuje implementovat chování uživatelského rozhraní, jako je obdélník výběru pro výběr více objektů.

Scénáře testování hitů

Třída UIElement poskytuje metodu InputHitTest , která umožňuje použít test proti prvku pomocí dané souřadnicové hodnoty. V mnoha případech InputHitTest metoda poskytuje požadovanou funkci pro implementaci testování prvků. Existuje však několik scénářů, ve kterých možná budete muset implementovat testování hitů ve vizuální vrstvě.

  • Testování proti objektům, které nejsouUIElement : To platí, pokud testujete objektyUIElement , které nejsou objekty, jako DrawingVisual jsou nebo grafické objekty.

  • Testování pomocí geometrie: To platí, pokud potřebujete použít test pomocí objektu geometrie, nikoli souřadnicové hodnoty bodu.

  • Testování s více objekty: To platí, pokud potřebujete testovat na více objektech, například překrývající se objekty. Můžete získat výsledky pro všechny vizuály protínající geometrii nebo bod, ne jenom první vizuál.

  • Ignorování UIElement zásad testování: To platí, když potřebujete ignorovat zásady testování hitů UIElement , které berou v úvahu takové faktory, jako je to, jestli je prvek zakázaný nebo neviditelný.

Poznámka:

Kompletní vzorový kód ilustrující testování hitů ve vizuální vrstvě najdete v tématu Test hit Test Using DrawingVisuals Sample and Hit Test with Win32 Interoperation Sample.

Podpora testování hitů

Účelem HitTest metod ve VisualTreeHelper třídě je určit, zda je hodnota souřadnic geometrie nebo bodu v rámci vykresleného obsahu daného objektu, například ovládací prvek nebo grafický prvek. Pomocí testování stiskem můžete například určit, jestli kliknutí myší v ohraničujícím obdélníku objektu spadá do geometrie kruhu. Můžete se také rozhodnout, že přepíšete výchozí implementaci testování hitů a provedete vlastní výpočty testů hitů.

Následující obrázek znázorňuje vztah mezi neúhelníkovou oblastí objektu a jeho ohraničující obdélník.

Diagram of valid hit test region
Diagram platné oblasti testu dosažení

Hit Testing and Z-Order

Vizuální vrstva WpF (Windows Presentation Foundation) podporuje testování hitů proti všem objektům pod bodem nebo geometrií, nejen objektem nejvyšší úrovně. Výsledky se vrátí v pořadí z. Nicméně vizuální objekt, který předáte jako parametr HitTest metodě určuje, která část vizuálního stromu, která bude dosaženo testu. Test můžete použít pro celý vizuální strom nebo libovolnou jeho část.

Na následujícím obrázku je objekt kruhu nad čtvercovými i trojúhelníkovými objekty. Pokud vás zajímá pouze testování objektu vizuálu, jehož hodnota pořadí vykreslování je nejvyšší, můžete nastavit, aby se vizuál vrátil z výčtu HitTestResultCallback testů, aby se po první položce zastavil Stop procházení testu.

Diagram of the z-order of a visual tree
Diagram pořadí vykreslování stromu vizuálu

Chcete-li vytvořit výčet všech vizuálních objektů pod konkrétním bodem nebo geometrií, vraťte Continue se z objektu HitTestResultCallback. To znamená, že můžete použít test vizuálních objektů, které jsou pod jinými objekty, i když jsou zcela nejasné. Další informace najdete v ukázkovém kódu v části "Použití zpětného volání výsledků testu přístupů".

Poznámka:

Test lze provést také u vizuálního objektu, který je transparentní.

Použití výchozího testování hitů

Pomocí metody můžete určit, zda je bod v geometrii vizuálního objektu, pomocí HitTest metody určit vizuální objekt a hodnotu souřadnic bodu, která se má testovat. Parametr vizuálního objektu identifikuje výchozí bod ve stromu vizuálu pro hledání pomocí testu. Pokud je objekt vizuálu nalezen ve vizuálním stromu, jehož geometrie obsahuje souřadnici, je nastavena na VisualHit vlastnost objektu HitTestResult . Pak HitTestResult se vrátí z HitTest metody. Pokud bod není obsažen v podsíňovém vizuálu, který testujete, HitTest vrátí hodnotu null.

Poznámka:

Výchozí testování hitů vždy vrátí nejvyšší objekt v pořadí z. K identifikaci všech vizuálních objektů, i těch, které mohou být částečně nebo zcela nejasné, použijte zpětné volání výsledku testu hit.

Hodnota souřadnice, kterou předáte jako parametr bodu pro metodu HitTest , musí být relativní ke souřadnicovému prostoru objektu vizuálu, se kterou testujete. Pokud máte například vnořené vizuální objekty definované na (100, 100) v souřadnicovém prostoru nadřazeného objektu, je výsledek testování podřízeného vizuálu na (0, 0) ekvivalentní k dosažení testování (100, 100) v souřadnicovém prostoru nadřazeného objektu.

Následující kód ukazuje, jak nastavit obslužné rutiny událostí myši pro UIElement objekt, který se používá k zaznamenání událostí používaných k testování hitů.

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

Vliv vizuálního stromu na testování hitů

Výchozí bod ve stromu vizuálu určuje, které objekty se vrátí během testu dosažení testu výčtu objektů. Pokud máte více objektů, které chcete testovat, musí být vizuální objekt použitý jako výchozí bod ve vizuálním stromu společným nadřazeným prvkem všech objektů, které vás zajímají. Pokud byste například chtěli otestovat prvek tlačítka i vizuál kreslení v následujícím diagramu, museli byste nastavit výchozí bod ve vizuálním stromu na společný nadřazený prvek obojího. V tomto případě je prvek plátna společným nadřazeným prvkem prvku tlačítka i vizuálu výkresu.

Diagram of a visual tree hierarchy
Diagram hierarchie stromové struktury vizuálu

Poznámka:

Vlastnost IsHitTestVisible získá nebo nastaví hodnotu, která deklaruje, zda UIElement-odvozený objekt může být vrácen jako výsledek testu hitu z některé části jeho vykresleného obsahu. Díky tomu můžete selektivně změnit vizuální strom a určit, které vizuální objekty jsou součástí testu hitů.

Použití zpětného volání výsledku testu hitu

Můžete vytvořit výčet všech vizuálních objektů ve stromu vizuálu, jehož geometrie obsahuje zadanou hodnotu souřadnic. To vám umožní identifikovat všechny vizuální objekty, i ty, které mohou být částečně nebo zcela zakryté jinými vizuálními objekty. K vytvoření výčtu vizuálních objektů ve stromu vizuálu použijte HitTest metodu s funkcí zpětného volání testu. Funkce zpětného volání hitu je volána systémem, když hodnota souřadnic, kterou zadáte, je obsažena ve vizuálním objektu.

Během výčtu výsledků testu byste neměli provádět žádnou operaci, která upravuje strom vizuálu. Přidání nebo odebrání objektu z vizuálního stromu během procházení může způsobit nepředvídatelné chování. Po vrácení metody můžete bezpečně upravit vizuální strom HitTest . Můžete chtít zadat datovou strukturu, například ArrayList, pro uložení hodnot během výčtu výsledků testu.

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

Metoda zpětného volání hitu definuje akce, které provedete, když je test hitu identifikován u konkrétního vizuálního objektu ve vizuálním stromu. Po provedení akcí vrátíte HitTestResultBehavior hodnotu, která určuje, zda pokračovat v výčtu jiných vizuálních objektů, nebo ne.

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

Poznámka:

Pořadí výčtu objektů vizuálu hit je podle pořadí z. Objekt vizuálu na nejvyšší úrovni pořadí vykreslování je prvním objektem, který je výčtem. Všechny ostatní objekty vizuálu, které jsou výčty, jsou na nižší úrovni pořadí vykreslování. Toto pořadí výčtu odpovídá pořadí vykreslování vizuálů.

Výčty vizuálních objektů můžete kdykoli zastavit v funkci zpětného volání hit test vrácením Stop.

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

Použití zpětného volánífiltruho

Pomocí volitelného filtru testu hitu můžete omezit objekty, které jsou předány výsledkům testu. To vám umožní ignorovat části vizuálního stromu, které vás nezajímají při zpracování výsledků testu. Pokud chcete implementovat filtr testu, definujete funkci zpětného volání filtru testu a při volání metody ji předáte jako hodnotu parametru 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();
    }
}
' 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

Pokud nechcete zadat volitelnou null funkci zpětného volání filtru testu, předejte jako jeho parametr pro metodu HitTest hodnotu.

// 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
Vyřezávání vizuálního stromu

Funkce zpětného volání filtru hitů testu umožňuje zobrazit výčet všech vizuálů, jejichž vykreslený obsah obsahuje zadané souřadnice. Můžete ale chtít ignorovat určité větve vizuálního stromu, které vás zajímají o zpracování ve funkci zpětného volání výsledků testu. Návratová hodnota funkce zpětného volání filtru testu určuje, jaký typ akce má výčet objektů vizuálu provést. Pokud například vrátíte hodnotu, ContinueSkipSelfAndChildrenmůžete z výčtu výsledků testu odebrat aktuální objekt vizuálu a jeho podřízené položky. To znamená, že funkce zpětného volání výsledků testu při dosažení výsledků hledání neuvidí tyto objekty v jeho výčtu. Vyřazení vizuálního stromu objektů snižuje množství zpracování během úspěšného testu – výčet výsledků testu. V následujícím příkladu kódu filtr přeskočí popisky a jejich potomky a dosáhne testů všeho ostatního.

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

Poznámka:

Zpětné volání filtru testu se někdy volá v případech, kdy není volána zpětná volání výsledků testu.

Přepsání výchozího testování hitů

Výchozí podporu testování objektu vizuálu můžete přepsat přepsáním HitTestCore metody. To znamená, že při vyvolání HitTest metody je volána přepsaná implementace HitTestCore . Vaše přepsáná metoda je volána, když test hit spadá do ohraničující obdélník vizuálního objektu, i když souřadnice spadá mimo vykreslený obsah vizuálního objektu.

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

Někdy může docházet k tomu, že chcete testovat na ohraničující obdélník i vykreslený obsah objektu vizuálu. Pomocí hodnoty parametru PointHitTestParameters v přepsáné HitTestCore metodě jako parametr základní metody HitTestCoremůžete provádět akce na základě dosažení ohraničující obdélník vizuálního objektu a potom provést druhý test hitu na vykreslený obsah objektu vizuálu.

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

Viz také