Partilhar via


Visão geral da renderização de gráficos do WPF

Este tópico fornece uma visão geral da camada visual do WPF. Ele concentra-se no papel da classe Visual para suporte de renderização no modelo WPF.

Papel do objeto visual

A Visual classe é a abstração básica da qual todo FrameworkElement objeto deriva. Ele também serve como o ponto de entrada para escrever novos controles no WPF e, de muitas maneiras, pode ser considerado como o identificador de janela (HWND) no modelo de aplicativo Win32.

O objeto Visual é um objeto WPF principal, cuja função principal é fornecer suporte à renderização. Os controles da interface do usuário, como Button e TextBox, derivam da classe Visual e a usam para persistir seus dados de renderização. O Visual objeto fornece suporte para:

  • Exibição de resultados: renderização do conteúdo de desenho persistente e serializado de uma visualização.

  • Transformações: Realizar transformações num visual.

  • Recorte: Fornece suporte de região de recorte para um visual.

  • Teste de colisão: Determinar se uma coordenada ou geometria está contida dentro dos limites de um elemento visual.

  • Os cálculos da caixa delimitadora: Determinar o retângulo delimitador de um elemento visual.

No entanto, o Visual objeto não inclui suporte para recursos que não são de renderização, como:

  • Tratamento de eventos

  • Esquema

  • Estilos

  • Vinculação de dados

  • Globalização

Visual é exposto como uma classe abstrata pública a partir da qual subclasses devem ser derivadas. A ilustração a seguir mostra a hierarquia dos objetos visuais expostos no WPF.

Diagrama de classes derivadas do objeto Visual

Classe DrawingVisual

O DrawingVisual é uma classe de desenho leve que é usada para renderizar formas, imagens ou texto. Essa classe é considerada leve porque não fornece layout ou manipulação de eventos, o que melhora seu desempenho em tempo de execução. Por esta razão, os desenhos são ideais para fundos e clip-art. O DrawingVisual pode ser usado para criar um objeto visual personalizado. Para obter mais informações, consulte Usando objetos DrawingVisual.

Classe Viewport3DVisual

O Viewport3DVisual fornece uma ponte entre 2D Visual e Visual3D objetos. A Visual3D classe é a classe base para todos os elementos visuais 3D. O Viewport3DVisual requer que você defina um Camera valor e um Viewport valor. A câmera permite que você veja a cena. A janela de visualização estabelece onde a projeção é mapeada na superfície 2D. Para obter mais informações sobre 3D no WPF, consulte Visão geral de gráficos 3D.

Classe ContainerVisual

A ContainerVisual classe é usada como um contêiner para uma coleção de Visual objetos. A DrawingVisual classe deriva da ContainerVisual classe, permitindo que ela contenha uma coleção de objetos visuais.

Desenhando conteúdo em objetos visuais

Um Visual objeto armazena seus dados de renderização como uma lista de instruções de gráficos vetoriais. Cada item na lista de instruções representa um conjunto de baixo nível de dados gráficos e recursos associados em um formato serializado. Há quatro tipos diferentes de dados de renderização que podem conter conteúdo de desenho.

Tipo de conteúdo de desenho Descrição
Gráficos vetoriais Representa dados de gráficos vetoriais e quaisquer informações associadas Brush e Pen.
Imagem Representa uma imagem dentro de uma região definida por um Rect.
Glifo Representa um desenho que renderiza um GlyphRun, que é uma sequência de glifos de um recurso de fonte especificado. É assim que o texto é representado.
Vídeo Representa um desenho que renderiza vídeo.

O DrawingContext permite que você preencha um Visual com conteúdo visual. Quando você usa os comandos de desenho de um DrawingContext objeto, você está na verdade armazenando um conjunto de dados de renderização que serão usados posteriormente pelo sistema gráfico, você não está desenhando para a tela em tempo real.

Quando você cria um controle WPF, como um Button, o controle gera implicitamente dados de renderização para o próprio desenho. Por exemplo, definir a propriedade Content do Button faz com que o controle armazene uma representação de renderização de um glifo.

A Visual descreve o seu conteúdo como um ou mais objetos Drawing contidos dentro de um DrawingGroup. A DrawingGroup também descreve máscaras de opacidade, transformações, efeitos de bitmap e outras operações que são aplicadas ao seu conteúdo. DrawingGroup As operações são aplicadas na seguinte ordem quando o conteúdo é renderizado: OpacityMask, Opacity, BitmapEffect, ClipGeometry, GuidelineSete, em seguida Transform, .

A ilustração a seguir mostra a ordem em que DrawingGroup as operações são aplicadas durante a sequência de renderização.

Ordem de operações do DrawingGroup
Ordem das operações do DrawingGroup

Para obter mais informações, consulte Visão geral de objetos de desenho.

Desenhando conteúdo na camada visual

Você nunca instancia diretamente um DrawingContext; no entanto, pode adquirir um contexto de desenho a partir de certos métodos, como DrawingGroup.Open e DrawingVisual.RenderOpen. O exemplo a seguir recupera a DrawingContext de a DrawingVisual e o usa para desenhar um retângulo.

// Create a DrawingVisual that contains a rectangle.
private DrawingVisual CreateDrawingVisualRectangle()
{
    DrawingVisual drawingVisual = new DrawingVisual();

    // Retrieve the DrawingContext in order to create new drawing content.
    DrawingContext drawingContext = drawingVisual.RenderOpen();

    // Create a rectangle and draw it in the DrawingContext.
    Rect rect = new Rect(new System.Windows.Point(160, 100), new System.Windows.Size(320, 80));
    drawingContext.DrawRectangle(System.Windows.Media.Brushes.LightBlue, (System.Windows.Media.Pen)null, rect);

    // Persist the drawing content.
    drawingContext.Close();

    return drawingVisual;
}
' Create a DrawingVisual that contains a rectangle.
Private Function CreateDrawingVisualRectangle() As DrawingVisual
    Dim drawingVisual As New DrawingVisual()

    ' Retrieve the DrawingContext in order to create new drawing content.
    Dim drawingContext As DrawingContext = drawingVisual.RenderOpen()

    ' Create a rectangle and draw it in the DrawingContext.
    Dim rect As New Rect(New Point(160, 100), New Size(320, 80))
    drawingContext.DrawRectangle(Brushes.LightBlue, CType(Nothing, Pen), rect)

    ' Persist the drawing content.
    drawingContext.Close()

    Return drawingVisual
End Function

Enumerando conteúdo de desenho na camada visual

Além dos seus outros usos, os objetos Drawing também fornecem um modelo de objeto para enumerar o conteúdo de um Visual.

Observação

Ao enumerar os conteúdos do elemento visual, está a recuperar objetos Drawing e não a representação subjacente dos dados de renderização como uma lista de instruções de gráficos vetoriais.

O exemplo a seguir usa o método GetDrawing para recuperar o valor DrawingGroup de um Visual e enumerá-lo.

public void RetrieveDrawing(Visual v)
{
    DrawingGroup drawingGroup = VisualTreeHelper.GetDrawing(v);
    EnumDrawingGroup(drawingGroup);
}

// Enumerate the drawings in the DrawingGroup.
public void EnumDrawingGroup(DrawingGroup drawingGroup)
{
    DrawingCollection dc = drawingGroup.Children;

    // Enumerate the drawings in the DrawingCollection.
    foreach (Drawing drawing in dc)
    {
        // If the drawing is a DrawingGroup, call the function recursively.
        if (drawing is DrawingGroup group)
        {
            EnumDrawingGroup(group);
        }
        else if (drawing is GeometryDrawing)
        {
            // Perform action based on drawing type.
        }
        else if (drawing is ImageDrawing)
        {
            // Perform action based on drawing type.
        }
        else if (drawing is GlyphRunDrawing)
        {
            // Perform action based on drawing type.
        }
        else if (drawing is VideoDrawing)
        {
            // Perform action based on drawing type.
        }
    }
}

Como objetos visuais são usados para criar controles

Muitos dos objetos no WPF são compostos de outros objetos visuais, o que significa que eles podem conter hierarquias variadas de objetos descendentes. Muitos dos elementos da interface do usuário no WPF, como controles, são compostos de vários objetos visuais, representando diferentes tipos de elementos de renderização. Por exemplo, o Button controle pode conter vários outros objetos, incluindo ClassicBorderDecorator, ContentPresentere TextBlock.

O código a seguir mostra um Button controle definido no código de marcação.

<Button Click="OnClick">OK</Button>

Se você enumerasse os objetos visuais que compõem o controle padrão Button , encontraria a hierarquia de objetos visuais ilustrada abaixo:

Diagrama da hierarquia da árvore visual

O Button controle contém um ClassicBorderDecorator elemento , que, por sua vez, contém um ContentPresenter elemento . O ClassicBorderDecorator elemento é responsável por desenhar uma borda e um fundo para o Button. O ContentPresenter elemento é responsável por exibir o conteúdo do Button. Nesse caso, como você está exibindo texto, o ContentPresenter elemento contém um TextBlock elemento . O facto de o Button controlo utilizar um ContentPresenter significa que o conteúdo pode ser representado por outros elementos, como um Image ou uma geometria, como um EllipseGeometry.

Modelos de controle

A chave para a expansão de um controle em uma hierarquia de controles é o ControlTemplate. Um modelo de controle especifica a hierarquia visual padrão para um controle. Quando você faz referência explícita a um controle, você implicitamente faz referência à sua hierarquia visual. Você pode substituir os valores padrão de um modelo de controle para criar uma aparência visual personalizada para um controle. Por exemplo, você pode modificar o valor de cor de plano de fundo do Button controle para que ele use um valor de cor de gradiente linear em vez de um valor de cor sólida. Para obter mais informações, consulte Estilos e modelos de botão.

Um elemento de interface do usuário, como um Button controle, contém várias listas de instruções de gráficos vetoriais que descrevem toda a definição de renderização de um controle. O código a seguir mostra um Button controle definido no código de marcação.

<Button Click="OnClick">
  <Image Source="images\greenlight.jpg"></Image>
</Button>

Se você fosse enumerar os objetos visuais e listas de instruções de gráficos vetoriais que compõem o Button controle, você encontraria a hierarquia de objetos ilustrada abaixo:

Diagrama de árvore visual e dados de renderização

O Button controle contém um ClassicBorderDecorator elemento , que, por sua vez, contém um ContentPresenter elemento . O ClassicBorderDecorator elemento é responsável por desenhar todos os elementos gráficos discretos que compõem a borda e o fundo de um botão. O ContentPresenter elemento é responsável por exibir o conteúdo do Button. Nesse caso, como você está exibindo uma imagem, o ContentPresenter elemento contém um Image elemento .

Há uma série de pontos a observar sobre a hierarquia de objetos visuais e listas de instruções de gráficos vetoriais:

  • A ordenação na hierarquia representa a ordem de renderização das informações do desenho. A partir do elemento visual raiz, os elementos filho são percorridos, da esquerda para a direita, de cima para baixo. Se um elemento tem elementos filhos visuais, eles são percorridos antes dos elementos irmãos.

  • Elementos de nó não folha na hierarquia, como ContentPresenter, são usados para conter elementos filho — eles não contêm listas de instruções.

  • Se um elemento visual contiver uma lista de instruções de gráficos vetoriais e objetos visuais filhos, a lista de instruções no elemento visual pai será renderizada antes dos desenhos nos objetos visuais filhos.

  • Os itens na lista de instruções de gráficos vetoriais são renderizados da esquerda para a direita.

Árvore Visual

A árvore visual contém todos os elementos visuais usados na interface do usuário de um aplicativo. Como um elemento visual contém informações de desenho persistentes, você pode pensar na árvore visual como um gráfico de cena, contendo todas as informações de renderização necessárias para compor a saída para o dispositivo de exibição. Esta árvore é o acúmulo de todos os elementos visuais criados diretamente pelo aplicativo, seja em código ou em marcação. A árvore visual também contém todos os elementos visuais criados pela expansão do modelo de elementos como controles e objetos de dados.

O código a seguir mostra um elemento StackPanel definido na marcação.

<StackPanel>
  <Label>User name:</Label>
  <TextBox />
  <Button Click="OnClick">OK</Button>
</StackPanel>

Se você enumerasse os objetos visuais que compõem o StackPanel elemento no exemplo de marcação, encontraria a hierarquia de objetos visuais ilustrada abaixo:

Diagrama da hierarquia da árvore visual de um controle StackPanel.

Ordem de renderização

A árvore visual determina a ordem de renderização dos objetos visuais e de desenho do WPF. A ordem de travessia começa com o visual raiz, que é o nó superior na árvore visual. Os filhos do visual raiz são então percorridos, da esquerda para a direita. Se um elemento visual tem filhos, os seus filhos são percorridos antes dos irmãos do elemento visual. Isso significa que o conteúdo de um elemento visual secundário é renderizado por cima do próprio conteúdo do visual.

Diagrama da ordem de renderização da árvore visual

Visual Raiz

O raiz visual é o elemento superior na hierarquia de uma árvore visual. Na maioria dos aplicativos, a classe base do visual raiz é ou Window ou NavigationWindow. No entanto, se você estivesse hospedando objetos visuais em um aplicativo Win32, o visual raiz seria o visual mais alto que você estava hospedando na janela do Win32. Para obter mais informações, consulte Tutorial: Hospedagem de objetos visuais em um aplicativo Win32.

Relação com a Árvore Lógica

A árvore lógica no WPF representa os elementos de um aplicativo em tempo de execução. Embora você não manipule essa árvore diretamente, essa exibição do aplicativo é útil para entender a herança de propriedade e o roteamento de eventos. Ao contrário da árvore visual, a árvore lógica pode representar objetos de dados não visuais, como ListItem. Em muitos casos, a árvore lógica mapeia muito proximamente as definições de marcação de uma aplicação. O código a seguir mostra um elemento DockPanel definido na marcação.

<DockPanel>
  <ListBox>
    <ListBoxItem>Dog</ListBoxItem>
    <ListBoxItem>Cat</ListBoxItem>
    <ListBoxItem>Fish</ListBoxItem>
  </ListBox>
  <Button Click="OnClick">OK</Button>
</DockPanel>

Se você enumerasse os objetos lógicos que compõem o DockPanel elemento no exemplo de marcação, encontraria a hierarquia de objetos lógicos ilustrada abaixo:

Diagrama de árvore
Diagrama da árvore lógica

Tanto a árvore visual quanto a árvore lógica são sincronizadas com o conjunto atual de elementos do aplicativo, refletindo qualquer adição, exclusão ou modificação de elementos. No entanto, as árvores apresentam visões diferentes da aplicação. Ao contrário da árvore visual, a árvore lógica não expande o elemento ContentPresenter de um controlo. Isso significa que não há uma correspondência direta um-para-um entre uma árvore lógica e uma árvore visual para o mesmo conjunto de objetos. Na verdade, invocar o método do objeto GetChildren e o método do objeto GetChild usando o mesmo elemento como parâmetro produz resultados diferentes.

Para obter mais informações sobre a árvore lógica, consulte Árvores no WPF.

Exibindo a árvore visual com XamlPad

A ferramenta WPF, XamlPad, fornece uma opção para exibir e explorar a árvore visual que corresponde ao conteúdo XAML definido no momento. Clique no botão Mostrar árvore visual na barra de menus para exibir a árvore visual. O seguinte ilustra a expansão do conteúdo XAML em nós de árvore visual no painel Visual Tree Explorer do XamlPad:

Painel Visual Tree Explorer em XamlPad

Observe como os Labelcontroles , TextBox, e Button exibem uma hierarquia de objetos visuais separada no painel Visual Tree Explorer do XamlPad. Isso ocorre porque os controles WPF têm um ControlTemplate que contém a árvore visual desse controle. Quando você faz referência explícita a um controle, você implicitamente faz referência à sua hierarquia visual.

Criação de perfil de desempenho visual

O WPF fornece um conjunto de ferramentas de criação de perfil de desempenho que permitem analisar o comportamento em tempo de execução do seu aplicativo e determinar os tipos de otimizações de desempenho que você pode aplicar. A ferramenta Visual Profiler fornece uma exibição gráfica rica de dados de desempenho mapeando diretamente para a árvore visual do aplicativo. Nesta captura de tela, a seção Uso da CPU do Visual Profiler fornece um detalhamento preciso do uso de serviços WPF por um objeto, como renderização e layout.

Saída de exibição do Visual Profiler
Saída de exibição do Visual Profiler

Comportamento de renderização visual

O WPF apresenta vários recursos que afetam o comportamento de renderização de objetos visuais: gráficos de modo retido, gráficos vetoriais e gráficos independentes de dispositivo.

Gráficos de modo retido

Uma das chaves para entender o papel do objeto Visual é entender a diferença entre os sistemas gráficos de modo imediato e modo retido . Um aplicativo Win32 padrão baseado em GDI ou GDI+ usa um sistema gráfico de modo imediato. Isso significa que o aplicativo é responsável por repintar a parte da área do cliente que é invalidada, devido a uma ação como uma janela sendo redimensionada ou um objeto alterando sua aparência visual.

Diagrama da sequência de renderização do Win32

Em contraste, o WPF usa um sistema de modo retido. Isso significa que os objetos de aplicativo que têm uma aparência visual definem um conjunto de dados de desenho serializados. Uma vez que os dados de desenho são definidos, o sistema é responsável por responder a todas as solicitações de repintura para renderizar os objetos do aplicativo. Mesmo em tempo de execução, você pode modificar ou criar objetos de aplicativo e ainda confiar no sistema para responder a solicitações de pintura. O poder em um sistema gráfico em modo retido é que as informações de desenho são sempre mantidas em formato serializado pela aplicação, deixando a responsabilidade de renderização ao sistema. O diagrama a seguir mostra como o aplicativo depende do WPF para responder a solicitações de pintura.

Diagrama da sequência de renderização do WPF

Redesenho inteligente

Um dos maiores benefícios no uso de gráficos de modo retido é que o WPF pode otimizar eficientemente o que precisa ser redesenhado no aplicativo. Mesmo que você tenha uma cena complexa com vários níveis de opacidade, geralmente não precisa escrever código para fins especiais para otimizar o redesenho. Compare isso com a programação do Win32, na qual você pode gastar um grande esforço na otimização do seu aplicativo, minimizando a quantidade de redesenho na região de atualização. Consulte Redesenhar na região de atualização para obter um exemplo do tipo de complexidade envolvida na otimização do redesenho em aplicativos Win32.

Gráficos vetoriais

WPF usa gráficos vetoriais como seu formato de dados de renderização. Os gráficos vetoriais, que incluem SVG (Scalable Vetor Graphics), metarquivos do Windows (.wmf) e fontes TrueType, armazenam dados de renderização e os transmitem como uma lista de instruções que descrevem como recriar uma imagem usando primitivas gráficas. Por exemplo, fontes TrueType são fontes de contorno que descrevem um conjunto de linhas, curvas e comandos, em vez de uma matriz de pixels. Um dos principais benefícios dos gráficos vetoriais é a capacidade de dimensionar para qualquer tamanho e resolução.

Ao contrário dos gráficos vetoriais, os gráficos bitmap armazenam dados de renderização como uma representação pixel a pixel de uma imagem, pré-renderizada para uma resolução específica. Uma das principais diferenças entre os formatos gráficos vetoriais e de bitmap é a fidelidade à imagem de origem original. Por exemplo, quando o tamanho de uma imagem de origem é modificado, os sistemas gráficos de bitmap esticam a imagem, enquanto os sistemas de gráficos vetoriais dimensionam a imagem, preservando a fidelidade da imagem.

A ilustração a seguir mostra uma imagem de origem que foi redimensionada em 300%. Observe as distorções que aparecem quando a imagem de origem é esticada como uma imagem de gráficos de bitmap em vez de dimensionada como uma imagem de gráficos vetoriais.

Diferenças entre gráficos raster e vetoriais

A marcação a seguir mostra dois Path elementos definidos. O segundo elemento usa a ScaleTransform para redimensionar as instruções de desenho do primeiro elemento em 300%. Observe que as instruções de desenho nos Path elementos permanecem inalteradas.

<Path
  Data="M10,100 C 60,0 100,200 150,100 z"
  Fill="{StaticResource linearGradientBackground}"
  Stroke="Black"
  StrokeThickness="2" />

<Path
  Data="M10,100 C 60,0 100,200 150,100 z"
  Fill="{StaticResource linearGradientBackground}"
  Stroke="Black"
  StrokeThickness="2" >
  <Path.RenderTransform>
    <ScaleTransform ScaleX="3.0" ScaleY="3.0" />
  </Path.RenderTransform>
</Path>

Sobre a resolução e os gráficos Device-Independent

Existem dois fatores de sistema que determinam o tamanho do texto e dos gráficos na tela: resolução e DPI. Resolução descreve o número de pixels que aparecem na tela. À medida que a resolução fica mais alta, os pixels ficam menores, fazendo com que os gráficos e o texto pareçam menores. Um gráfico exibido em um monitor definido como 1024 x 768 aparecerá muito menor quando a resolução for alterada para 1600 x 1200.

A outra configuração do sistema, DPI, descreve o tamanho de uma polegada de tela em pixels. A maioria dos sistemas Windows tem um DPI de 96, o que significa que uma polegada de tela é de 96 pixels. Aumentar a configuração de DPI torna a polegada da tela maior; diminuir o DPI torna a polegada da tela menor. Isso significa que uma polegada de tela não tem o mesmo tamanho de uma polegada do mundo real; na maioria dos sistemas, provavelmente não é. À medida que você aumenta o DPI, os gráficos e o texto com reconhecimento de DPI ficam maiores porque você aumentou o tamanho da polegada da tela. Aumentar o DPI pode tornar o texto mais fácil de ler, especialmente em altas resoluções.

Nem todas as aplicações reconhecem DPI: algumas usam pixels de hardware como a principal unidade de medida; alterar o DPI do sistema não tem efeito sobre esses aplicativos. Muitos outros aplicativos usam unidades com reconhecimento de DPI para descrever tamanhos de fonte, mas usam pixels para descrever todo o resto. Tornar o DPI muito pequeno ou muito grande pode causar problemas de layout para esses aplicativos, porque o texto dos aplicativos é dimensionado com a configuração de DPI do sistema, mas a interface do usuário dos aplicativos não. Esse problema foi eliminado para aplicativos desenvolvidos usando WPF.

O WPF suporta dimensionamento automático usando o pixel independente do dispositivo como sua principal unidade de medida, em vez de pixels de hardware; gráficos e texto dimensionados corretamente sem qualquer trabalho extra do desenvolvedor do aplicativo. A ilustração a seguir mostra um exemplo de como o texto e os gráficos do WPF são exibidos em diferentes configurações de DPI.

Gráficos e texto em diferentes configurações de DPI
Gráficos e texto em diferentes configurações de DPI

VisualTreeHelper Classe

A VisualTreeHelper classe é uma classe auxiliar estática que fornece funcionalidade de baixo nível para programação no nível de objeto visual, o que é útil em cenários muito específicos, como o desenvolvimento de controles personalizados de alto desempenho. Na maioria dos casos, os objetos de estrutura WPF de nível superior, como Canvas e TextBlock, oferecem maior flexibilidade e facilidade de uso.

Teste de Colisão

A VisualTreeHelper classe fornece métodos para testes de ocorrências em objetos visuais quando o suporte padrão a testes de ocorrências não atende às suas necessidades. Você pode usar os HitTest métodos na VisualTreeHelper classe para determinar se uma geometria ou valor de coordenada de ponto está dentro do limite de um determinado objeto, como um controle ou elemento gráfico. Por exemplo, poderás usar o teste de colisão para determinar se um clique do rato dentro do retângulo delimitador de um objeto está dentro da geometria de um círculo. Também poderás optar por substituir a implementação padrão do teste de colisão para executar os teus próprios cálculos personalizados de teste de colisão.

Para obter mais informações sobre testes de acertos, consulte Teste de acertos na camada visual.

Enumerando a árvore visual

A VisualTreeHelper classe fornece funcionalidade para enumerar os membros de uma árvore visual. Para recuperar um pai, chame o GetParent método. Para recuperar um filho, ou descendente direto, de um objeto visual, chame o método GetChild. Esse método retorna um filho Visual do pai no índice especificado.

O exemplo a seguir mostra como enumerar todos os descendentes de um objeto visual, que é uma técnica que você pode querer usar se estiver interessado em serializar todas as informações de renderização de uma hierarquia de objeto visual.

// Enumerate all the descendants of the visual object.
static public void EnumVisual(Visual myVisual)
{
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(myVisual); i++)
    {
        // Retrieve child visual at specified index value.
        Visual childVisual = (Visual)VisualTreeHelper.GetChild(myVisual, i);

        // Do processing of the child visual object.

        // Enumerate children of the child visual object.
        EnumVisual(childVisual);
    }
}
' Enumerate all the descendants of the visual object.
Public Shared Sub EnumVisual(ByVal myVisual As Visual)
    For i As Integer = 0 To VisualTreeHelper.GetChildrenCount(myVisual) - 1
        ' Retrieve child visual at specified index value.
        Dim childVisual As Visual = CType(VisualTreeHelper.GetChild(myVisual, i), Visual)

        ' Do processing of the child visual object.

        ' Enumerate children of the child visual object.
        EnumVisual(childVisual)
    Next i
End Sub

Na maioria dos casos, a árvore lógica é uma representação mais útil dos elementos em um aplicativo WPF. Embora você não modifique a árvore lógica diretamente, essa exibição do aplicativo é útil para entender a herança de propriedade e o roteamento de eventos. Ao contrário da árvore visual, a árvore lógica pode representar objetos de dados não visuais, como ListItem. Para obter mais informações sobre a árvore lógica, consulte Árvores no WPF.

A classe VisualTreeHelper fornece métodos para retornar o retângulo delimitador de objetos visuais. Você pode retornar o retângulo delimitador de um objeto visual chamando GetContentBounds. Você pode retornar o retângulo delimitador de todos os descendentes de um objeto visual, incluindo o próprio objeto visual, chamando GetDescendantBounds. O código a seguir mostra como você calcularia o retângulo delimitador de um objeto visual e todos os seus descendentes.

// Return the bounding rectangle of the parent visual object and all of its descendants.
Rect rectBounds = VisualTreeHelper.GetDescendantBounds(parentVisual);
' Return the bounding rectangle of the parent visual object and all of its descendants.
Dim rectBounds As Rect = VisualTreeHelper.GetDescendantBounds(parentVisual)

Ver também