Compartilhar via


Hit Testing in the Visual Layer

Este tópico fornece uma visão geral sobre funcionalidades relacionadas a testes de clique oferecidas pela camada visual. Suporte a teste de clique permite que você determine se um valor de geometria ou de ponto está dentro do conteúdo renderizado de um Visual, permitindo que você implemente comportamento de interface do usuário tal como um retângulo de seleção para selecionar vários objetos.

Este tópico contém as seguintes seções.

  • Situa?ões de teste de clique
  • Suporte a testes de clique
  • Teste de clique e ordem z
  • Usando o teste de clique padrão
  • Usando uma callback de resultados de teste de clique
  • Usando uma callback de filtro de teste de clique
  • Substituindo o teste de clique padrão
  • Tópicos relacionados

Situa?ões de teste de clique

A classe UIElement fornece o método InputHitTest, que permite que você teste contra um elemento usando um determinado valor de coordenada. Em muitos casos, o método InputHitTest fornece a funcionalidade desejada para a implementação de teste de clique sobre elementos. No entanto, há várias situações em que talvez você precise implementar teste de clique na camada de visual.

  • Visitas testes em relação a não-UIElement objetos: Isso se aplica se são atingidos testes não-UIElement objetos, sistema autônomo DrawingVisual ou objetos gráficos.

  • Teste usando uma geometria de ocorrências: Isso se aplica se você precisar de teste usando um objeto geometry em vez de valor de um ponto de coordenada de visitas.

  • Testes em vários objetos de ocorrências: Isso se aplica quando você precisar visitas teste em relação a vários objetos, tais sistema autônomo objetos sobrepostos. Você pode obter resultados para todos os elementos visuais em interseção com uma geometria ou ponto, não apenas o primeiro elemento visual.

  • Ignorando UIElement teste de diretiva de ocorrências: Isso se aplica quando você precisa ignorar o UIElement acertos diretiva teste, o que leva em consideração tais fatores sistema autônomo se um elemento é desabilitado ou invisível.

ObservaçãoObservação:

Para obter um exemplo de código completo que ilustra o teste visitas na camada do visual, consulte Teste usando o exemplo de DrawingVisuals de visitas e Teste com o exemplo de interoperação de Win32 de visitas.

Suporte a testes de clique

O objetivo dos métodos HitTest na classe VisualTreeHelper é determinar se uma geometria ou valor de ponto de coordenadas está dentro do conteúdo renderizado de um determinado objeto (p.ex., um controle ou elemento gráfico). Por exemplo, você poderia usar um teste de clique para determinar se um clique do mouse dentro do retângulo delimitador de um objeto caiu dentro da geometria de um círculo. Você também pode optar por substituir a implementação padrão do teste de clique para executar seus próprios cálculos personalizados.

A ilustração a seguir mostra a relação entre a região não retangular de um objeto e o retângulo delimitador.

Diagrama de região de teste de clique válida

Diagrama de região de teste de clique válida

Teste de clique e ordem z

A camada visual Windows Presentation Foundation (WPF) suporta teste de clique contra todos os objetos sob um ponto ou geometria, não apenas o objeto mais acima. Os resultados são retornados em ordem z. No entanto, o objeto visual que você passa como parâmetro para o método HitTest determina qual parte da árvore visual será testada. Você pode realizar testes de clique contra a árvore visual inteira, ou qualquer parte dela.

Na ilustração a seguir, o objeto circular está sobre os objetos quadrado e triangular. Se você só estiver interessado em fazer teste de clique no objeto visual cujo valor de ordem z é o mais alto, você pode definir a enumeração de teste de clique visual para retornar Stop a partir da HitTestResultCallback para interromper os testes após o primeiro item.

Diagrama da ordem z de uma árvore visual

Diagrama da ordem z de uma árvore visual

Se você desejar enumerar todos os objetos visuais em um ponto específico ou geometria, retorne Continue a partir da HitTestResultCallback. Isso significa que você pode fazer testes de clique sobre objetos visuais que estão sob outros objetos, mesmo que eles estejam totalmente encobertos. Ver o código de exemplo na seção "Usando uma callback de resultados de testes de cliques" para mais informações.

ObservaçãoObservação:

Um objeto visual que é transparente também pode ser atingido por um teste de clique.

Usando o teste de clique padrão

Não se pode identificar se um ponto está dentro da geometria de um objeto visual, usando o método HitTest para especificar o objeto visual e um valor de coordenadas de ponto contra o qual deve-se fazer o teste de clique. O parâmetro de objeto visual identifica o ponto de partida na árvore visual para a pesquisa de teste de clique. Se um objeto visual for encontrado na árvore visual cuja geometria contém a coordenada, ele será definido como a propriedade VisualHit de um objeto HitTestResult. O HitTestResult é, em seguida, retornado pelo método HitTest. Se o ponto não estiver contido na subárvore visual onde você está realizando o teste de clique, HitTest retorna null.

ObservaçãoObservação:

Acerto padrão testes sempre retorna o objeto superior na ordem-z. Para poder identificar todos os objetos visuais, mesmo aqueles que podem estar totalmente ou parcialmente encobertos, use uma callback de resultado de teste de clique.

O valor de coordenadas que você passar como o parâmetro de ponto para o método HitTest deve ser relativo ao espaço de coordenadas do objeto visual contra o qual você está realizando teste de clique. Por exemplo, se você tiver aninhado objetos visuaiss definidos em (100, 100) no espaço de coordenadas do pai, então um teste de clique sobre um visual-filho em (0, 0) é equivalente ao teste de clique em (100, 100) no espaço de coordenadas do pai.

O código a seguir mostra como configurar tratadores de eventos de mouse para um objeto UIElement que é usado para capturar eventos utilizados para teste de clique.

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

Como a árvore visual afeta testes de clique

O ponto de partida na árvore visual determina quais objetos são retornados durante a enumeração de teste de clique dos objetos. Se você tiver vários objetos sobre os quais você deseja fazer testes de clique, o objeto visual usado como o ponto de partida na árvore visual deve ser o ancestral comum de todos os objetos de interesse. Por exemplo, se você estivesse interessado em fazer testes de clique tanto o elemento de botão quanto o desenho visual no diagrama a seguir, você teria que definir o ponto de partida na árvore visual como o ancestral comum de ambos. Nesse caso, o elemento de tela (canvas) é o ancestral comum do elemento de botão e do desenho visual.

Diagrama de uma hierarquia de árvore visual

Diagrama de uma hierarquia de árvore visual

ObservaçãoObservação:

O IsHitTestVisible propriedade obtém ou define um valor que declara se um UIElement-objeto derivado possivelmente pode ser retornado sistema autônomo um resultado do teste de ocorrência de alguma parte do conteúdo processado. Isso permite que você altere seletivamente a árvore visual para determinar quais objetos visuais estão envolvidos em um teste de clique.

Usando uma callback de resultados de teste de clique

Você pode enumerar todos os objetos visuais em uma árvore visual cuja geometria contém um valor de coordenadas especificado. Isso permite que você identifique todos os objetos visuais, mesmo aqueles que podem estar totalmente ou parcialmente encobertos por outros objetos visuais. Para enumerar os objetos visual em uma árvore visual use o método HitTest com uma função callback de teste de clique. A função callback de teste de clique é chamada pelo sistema quando o valor de coordenadas especificado está contido em um objeto visual.

Durante a enumeração de resultados de teste de clique, você não deve executar qualquer operação que modifique a árvore visual. A inserção ou remoção de objetos da árvore visual enquanto ele está sendo percorrida pode resultar em comportamento imprevisível. Você pode modificar a árvore visual com segurança depois que o método HitTest retornar. Convém fornecer um estrutura de dados, tal como um ArrayList, para armazenar valores durante o a enumeração dos resultados de teste de clique.

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

O método callback de teste de clique define as ações executadas quando um teste de clique é identificado em um determinado objeto visual na árvore visual. Após executar as ações, você retorna um valor HitTestResultBehavior que determina se a enumeração de quaisquer outros objetos visuais deve continuar.

// 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;
}
ObservaçãoObservação:

A ordem de enumeração de objetos visuais visitas for por ordem-z. O objeto visual no nível de ordem z superior é o primeiro objeto enumerado. Quaisquer outros objetos visuais enumerados estão em níveis de ordem z decrescentes. Esta ordem de enumeração corresponde à ordem de renderização dos elementos visuais.

Você pode interromper a enumeração de objetos visuais a qualquer momento na função callback de teste de clique, retornando Stop.

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

Usando uma callback de filtro de teste de clique

Você pode usar um filtro de teste de clique opcional para restringir os objetos que são passados para os resultados do teste de clique. Isso permite que você ignore partes da árvore visual que você não tem interesse em processar em seus resultados de teste de clique. Para implementar um filtro de teste de clique, você define um função callback de filtro de teste de clique e passa-a como um valor do parâmetro quando você chamar o método 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();
    }
}

Se você não desejar fornecer a função callback de filtro de teste de clique opcional, passr um valor null como seu parâmetro para o método 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));

Podando uma árvore visual

Reduzindo uma árvore visual usando um filtro de teste de clique

A função callback de filtro de teste de clique permite que você enumere todos os elementos visuais cujo conteúdo renderizado contém as coordenadas que você especificar. No entanto, pode ser que você queira ignorar determinadas ramificações da árvore visual que você não está interessado em processar em sua função callback de resultados de teste de clique. A valor de retorno de função callback de filtro de teste de clique determina o tipo de ação que a enumeração dos objetos visuais deve tomar. Por exemplo, se você retornar o valor ContinueSkipSelfAndChildren, você pode remover o objeto visual atual e seus filhos da enumeração de resultados de teste de clique. Isso significa que a função callback de resultados de teste de clique não verá esses objetos em sua enumeração. A poda de objetos da árvore visual reduz a quantidade de processamento durante a passada de enumeração de resultados de teste de clique. Em exemplo de código a seguir, o filtro ignora os rótulos e seus descendentes e faz testes de clique sobre todo o resto.

// 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;
    }
}
ObservaçãoObservação:

A callback de filtro de teste de clique às vezes será chamada em casos onde a callback de resultados de teste de clique não é chamada.

Substituindo o teste de clique padrão

Você pode substituir o suporte padrão a testes de clique de um objeto visual substituindo o método HitTestCore. Isso significa que quando você chamar o método HitTest, sua implementação de HitTestCore substituída será chamada. O método substituído é chamado quando um teste de clique cair dentro do retângulo delimitador do objeto visual, mesmo se a coordenada ficar fora o conteúdo renderizado do objeto visual.

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

Pode haver ocasiões em que você deseje fazer testes de cliques contra o retângulo delimitador e o conteúdo renderizado de um objeto visual. Usando o valor do parâmetro PointHitTestParameters no seu método HitTestCore substituído como o parâmetro para o método HitTestCore de base, você pode executar ações com base em um acerto no retângulo delimitador de um objeto visual e, em seguida, executar um segundo teste de clique contra o conteúdo renderizado do objeto visual.

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

Consulte também

Tarefas

Teste usando o exemplo de DrawingVisuals de visitas

Teste com o exemplo de interoperação de Win32 de visitas

Como: Hit Test Geometry in a Visual

Como: Hit Test Using a Win32 Host Container

Referência

HitTest

HitTestResult

HitTestResultCallback

HitTestFilterCallback

IsHitTestVisible