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

Este tópico fornece uma visão geral da camada visual do WPF. Ele se concentra na função da Visual classe para renderizar suporte no modelo WPF.

Função 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 pensado como o identificador de janela (HWND) no modelo de aplicativo Win32.

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

  • Exibição de saída: renderização do conteúdo de desenho persistentes e serializado de um visual.

  • Transformações: Realizando transformações em um visual.

  • Recorte: dar suporte à área de recorte para um visual.

  • Teste de clique: determinar se uma coordenada ou geometria está contida dentro dos limites de um visual.

  • Cálculos de caixa delimitadora: determinar o retângulo delimitador de um visual.

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

  • Manipulação de eventos

  • Layout

  • Estilos

  • Vinculação de dados

  • Globalização

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

Diagram of classes derived from the Visual object

Classe DrawingVisual

O DrawingVisual é uma classe de desenho leve usada para renderizar formas, imagens ou texto. Essa classe é considerada leve porque não fornece layout ou manipulação de eventos, o que melhora o desempenho de runtime. Por esse motivo, desenhos são ideais para telas de fundo 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 valor e um ViewportCamera valor. A câmera permite que você exiba a cena. O visor estabelece o local para o qual 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.

Desenhar 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 e associadas BrushPen .
Imagem Representa uma imagem dentro de uma região definida por um Rectarquivo .
Glifo Representa um desenho que renderiza um , que é uma sequência de glifos de um GlyphRunrecurso de fonte especificado. Este é o modo pelo qual 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 objeto, você está realmente armazenando um DrawingContext conjunto de dados de renderização que serão usados posteriormente pelo sistema gráfico, você não está desenhando na 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 ContentButton propriedade do faz com que o controle armazene uma representação de renderização de um glifo.

A Visual descreve seu conteúdo como um ou mais Drawing objetos contidos em um DrawingGrouparquivo . 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. DrawingGroupAs operações são aplicadas na seguinte ordem quando o conteúdo é renderizado: OpacityMask, , , , e, em seguidaTransform, OpacityBitmapEffectClipGeometryGuidelineSet.

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

DrawingGroup order of operations
Ordem das operações do DrawingGroup

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

Conteúdo de desenho na camada visual

Você nunca instancia diretamente um , você pode, no entanto, adquirir um DrawingContextcontexto de desenho a partir de certos métodos, como DrawingGroup.Open e DrawingVisual.RenderOpen. O exemplo a seguir recupera um de a DrawingVisual e o usa para desenhar um DrawingContext 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

Enumerar conteúdo de desenho na camada visual

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

Observação

Quando você está enumerando o conteúdo do visual, você está recuperando Drawing objetos, 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 para recuperar o DrawingGroup valor de a VisualGetDrawing 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 compilar 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 na 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:

Diagram of visual tree hierarchy

O Button controle contém um elemento que, por sua vez, contém um ClassicBorderDecoratorContentPresenter elemento . O ClassicBorderDecorator elemento é responsável por desenhar uma borda e um plano de 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 fato de o Button controle usar um significa que o conteúdo pode ser representado por outros elementos, como uma ou uma Image geometria, como um ContentPresenterEllipseGeometry.

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 de um controle. Quando você referencia um controle explicitamente, você referencia implicitamente 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 controle para que ele use um valor de cor de gradiente linear em vez de um valor de Button cor sólida. Para obter mais informações, consulte Estilos e modelos de botão.

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

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

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

Diagram of visual tree and rendering data

O Button controle contém um elemento que, por sua vez, contém um ClassicBorderDecoratorContentPresenter elemento . O ClassicBorderDecorator elemento é responsável por desenhar todos os elementos gráficos discretos que compõem a borda e o plano de 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á diversos pontos a observar sobre a hierarquia de objetos visuais e listas de instruções de gráficos vetoriais:

  • A ordem na hierarquia representa a ordem de renderização das informações de desenho. Do elemento visual raiz, a ordem de renderização passa pelos elementos filho da esquerda para a direita, de cima para baixo. Se um determinado elemento tem elementos visuais filho, a ordem de renderização passa por eles antes de passar pelos irmãos desse elemento.

  • 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 contém uma lista de instruções de gráfico vetorial e filhos visuais, a lista de instruções no elemento visual pai é renderizada antes de desenhos em qualquer um dos objetos filho visuais.

  • 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. Já que um elemento visual contém informações de desenho persistentes, você pode pensar na árvore visual como um grafo de cena, contendo todas as informações de renderização necessárias para compor a saída para o dispositivo de vídeo. Esta árvore é o acúmulo de todos os elementos visuais criados diretamente pelo aplicativo, seja no código ou em marcação. A árvore visual também contém todos os elementos visuais criados pela expansão de modelo de elementos tais como controles e objetos de dados.

O código a seguir mostra um StackPanel elemento 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:

Diagram of visual tree hierarchy of a StackPanel control.

Ordem de renderização

A árvore visual determina a ordem de renderização dos objetos visuais e de desenho do WPF. A ordem de passagem inicia com o visual raiz, que é o nó mais alto na árvore visual. Em seguida, passa-se pelos filhos do visual raiz, da esquerda para a direita. Se um visual tiver filhos, a passagem por eles ocorrerá primeiro do que a passagem pelos irmãos do visual. Isso significa que o conteúdo de um visual filho é renderizado na frente do conteúdo do próprio visual.

Diagram of the visual tree rendering order

Visual raiz

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

Relacionamento 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 esta árvore diretamente, essa exibição do aplicativo é útil para entender a herança de propriedades 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 de modo muito próximo às definições de marcação de um aplicativo. O código a seguir mostra um DockPanel elemento 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:

Tree diagram
Diagrama de árvore lógica

A árvore visual e 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 diferentes exibições do aplicativo. Ao contrário da árvore visual, a árvore lógica não expande o elemento de ContentPresenter um controle. Isso significa que não há uma correspondência um para um direta entre uma árvore lógica e uma árvore visual para o mesmo conjunto de objetos. Na verdade, invocar o método do objeto LogicalTreeHelper e o método do GetChildGetChildren objeto VisualTreeHelper usando o mesmo elemento como um 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 atualmente. 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:

Visual Tree Explorer panel in XamlPad

Observe como o , e os Labelcontroles exibem uma hierarquia de objeto visual separada no painel Visual Tree Explorer do XamlPad.ButtonTextBox Isso ocorre porque os controles WPF têm um ControlTemplate que contém a árvore visual desse controle. Quando você referencia um controle explicitamente, você referencia implicitamente 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 aplicativo e determinar os tipos de otimizações de desempenho que você pode aplicar. A ferramenta Visual Profiler fornece uma exibição gráfica sofisticada de dados de desempenho, por meio do mapeamento 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.

Visual Profiler display output
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 sistemas gráficos de modo imediato e de modo retido. Um aplicativo Win32 padrão baseado em GDI ou GDI+ utiliza um sistema gráfico de modo imediato. Isso significa que o aplicativo é responsável por repintar a parte da área de cliente que for invalidada, devido a uma ação como um redimensionamento de janela ou a alteração da aparência visual de um objeto.

Diagram of Win32 rendering sequence

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. A partir do momento em que os dados de desenho são definidos, o sistema torna-se responsável por responder a todas as solicitações de repintura para renderizar os objetos de aplicativo. Mesmo em tempo de execução, você pode modificar ou criar objetos de aplicativo e, ainda assim, contar com o sistema para responder às solicitações e pintura. O poder existente em um sistema gráfico de modo retido é que informações de desenho sempre são persistentes em um estado serializado pelo aplicativo, mas a responsabilidade pela renderização é deixada para o sistema. O diagrama a seguir mostra como o aplicativo depende do WPF para responder a solicitações de pintura.

Diagram of WPF rendering sequence

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 diversos níveis de opacidade, você geralmente não precisa escrever código com propósito especial para otimizar o redesenho. Compare isso com programação em Win32, na qual você pode despender uma grande quantidade de esforço para otimizar seu aplicativo por meio da minimização da quantidade de redesenho na região de atualização. Consulte Redesenho na região de atualização para obter um exemplo do tipo de complexidade envolvida na otimização de redesenho em aplicativos Win32.

Gráficos vetoriais

WPF usa gráficos vetoriais como seu formato de dados de renderização. Gráficos vetoriais – que incluem SVG (Scalable Vector Graphics), metarquivos do Windows (.wmf) e fontes TrueType – armazenam dados de renderização e transmitem-nos como uma lista de instruções que descrevem como recriar uma imagem usando primitivos gráficos. Por exemplo, fontes TrueType são fontes geométricas 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.

Diferente de gráficos vetoriais, gráficos de bitmap armazenam dados de renderização como uma representação pixel por pixel de uma imagem, pré-renderizada para uma determinada resolução. Uma das principais diferenças entre formatos de gráficos de bitmap e vetoriais é a fidelidade à imagem original. Por exemplo, quando o tamanho de uma imagem de origem é modificado, sistemas de gráficos de bitmap alongam a imagem, ao passo que sistemas de gráficos vetoriais redimensionam a imagem, preservando sua fidelidade.

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

Differences between raster and vector graphics

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 Path instruções de desenho nos 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 elementos gráficos independentes de resolução e de dispositivo

Há dois fatores de sistema que determinam o tamanho do texto e de elementos gráficos na sua tela: resolução e DPI. A resolução descreve o número de pixels que aparecem na tela. Conforme a resolução aumenta, os pixels ficam menores, fazendo com que elementos gráficos e texto apareçam menores. Um elemento gráfico exibido em um monitor definido para 1024 x 768 aparecerá bem menor quando a resolução for alterada para 1600 x 1200.

A configuração de 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 de tela maior; diminuir o DPI torna a polegada de tela menor. Isso significa que uma polegada de tela não é do mesmo tamanho que uma polegada real; na maioria dos sistemas, provavelmente não é. Conforme você aumenta o DPI, texto e gráficos com reconhecimento de DPI se tornam maiores porque você aumentou o tamanho da polegada de tela. Aumentar o DPI pode tornar o texto mais fácil de ler, especialmente em resoluções altas.

Nem todos os aplicativos realizam reconhecimento de DPI: alguns utilizam pixels de hardware como a unidade principal de medida; alterar o DPI do sistema não tem nenhum efeito nesses aplicativos. Muitos outros aplicativos usam unidades com reconhecimento de DPI para descrever os tamanhos da fonte, mas utilizam pixels para descrever todo o resto. Tornar o DPI muito grande ou muito pequeno pode causar problemas de layout para esses aplicativos; o motivo disso é que o texto do aplicativo é dimensionado de acordo com a configuração de DPI do sistema, enquanto a interface do usuário 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 unidade de medida primária, 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 elementos gráficos do WPF são exibidos em diferentes configurações de DPI.

Graphics and text at different DPI settings
Elementos gráficos e texto em diferentes configurações de DPI

Classe VisualTreeHelper

A VisualTreeHelper classe é uma classe auxiliar estática que fornece funcionalidade de baixo nível para programação no nível de objeto visual, 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 , oferecem maior flexibilidade e TextBlockfacilidade de uso.

Testes de clique

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

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

Enumerar 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 GetChild método. 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 talvez você queira usar caso esteja interessado em serializar a informação de renderização de uma hierarquia de objetos visuais.

// 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 propriedades 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 VisualTreeHelper classe 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)

Confira também