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 se concentra na função da classe Visual para suporte à renderização no modelo WPF.
Função do objeto visual
A classe Visual é a abstração básica da qual cada objeto FrameworkElement deriva. Ele também serve como o ponto de entrada para escrever novos controles no WPF e, em muitos aspectos, pode ser considerado como o HWND (identificador de janela) no modelo de aplicativo Win32.
O objeto Visual é um objeto WPF principal, cuja função principal é fornecer suporte de renderização. Controles de interface do usuário, como Button e TextBox, derivam da classe Visual e usam-no para persistir seus dados de renderização. O objeto Visual 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 objeto Visual não inclui suporte para recursos que não são renderizados, como:
Manipulação de eventos
Esquema
Estilos
Vinculação de dados
Globalização
Visual é exposto como uma classe abstrata pública da qual classes filho devem ser derivadas. A ilustração a seguir mostra a hierarquia dos objetos visuais expostos no WPF.
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 seu desempenho de runtime. Por esse motivo, os desenhos são ideais para planos 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 objetos 2D Visual e Visual3D. A classe Visual3D é a classe base para todos os elementos visuais 3D. O Viewport3DVisual requer que você defina um valor Camera e um valor Viewport. A câmera permite que você veja 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 classe ContainerVisual é usada como um contêiner para uma coleção de objetos Visual. A classe DrawingVisual deriva da classe ContainerVisual, permitindo que ela contenha uma coleção de objetos visuais.
Desenho de conteúdo em objetos visuais
Um objeto Visual armazena seus dados de renderização como uma lista de instruções gráficas de vetor . 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 |
---|---|
Desenho vetorial | Representa dados gráficos de vetor e quaisquer informações de Brush e Pen associadas. |
Image | 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 o vídeo. |
O DrawingContext permite que você preencha um Visual com conteúdo visual. Ao usar os comandos de desenho de um objeto DrawingContext, você está 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, por exemplo, um Button, o controle implicitamente gera dados de renderização para desenhar-se. Por exemplo, definir a propriedade Content do Button faz com que o controle armazene uma representação de renderização de um glifo.
Um Visual descreve seu conteúdo como um ou mais objetos Drawing contidos em um DrawingGroup. Um 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 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 na qual as operações de DrawingGroup são aplicadas durante a sequência de renderização.
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, você pode obter um contexto de desenho de determinados métodos, como DrawingGroup.Open e DrawingVisual.RenderOpen. O exemplo a seguir recupera um DrawingContext de um 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 de seus outros usos, objetos Drawing também fornecem um modelo de objetos para enumerar o conteúdo de um Visual.
Nota
Ao enumerar o conteúdo do elemento visual, você está recuperando objetos Drawing, 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 os objetos visuais são usados para criar controles
Muitos dos objetos no WPF são compostos por outros objetos visuais, o que significa que eles podem conter hierarquias variadas de objetos descendentes. Muitos dos elementos de interface do usuário no WPF, como controles, são compostos por vários objetos visuais, representando diferentes tipos de elementos de renderização. Por exemplo, o controle Button pode conter vários outros objetos, incluindo ClassicBorderDecorator, ContentPresentere TextBlock.
O seguinte código mostra um controle Button definido em markup.
<Button Click="OnClick">OK</Button>
Se você enumerar os objetos visuais que compõem o controle de Button padrão, encontrará a hierarquia de objetos visuais ilustrada abaixo:
Diagrama
O controle Button contém um elemento ClassicBorderDecorator, que, por sua vez, contém um elemento ContentPresenter. O elemento ClassicBorderDecorator é responsável por desenhar uma borda e um plano de fundo para o Button. O elemento ContentPresenter é responsável por exibir o conteúdo do Button. Nesse caso, como você está exibindo texto, o elemento ContentPresenter contém um elemento TextBlock. O fato de o controle Button usar 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 é a ControlTemplate. Um modelo de controle especifica a hierarquia visual padrão para um controle. Ao referenciar explicitamente um controle, 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 da cor da tela de fundo do controle Button 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 de Botão e Modelos.
Um elemento de interface do usuário, como um controle Button, contém várias listas de instruções de elementos gráficos vetoriais que descrevem toda a definição de renderização de um controle. O código a seguir mostra um controle Button definido na marcação.
<Button Click="OnClick">
<Image Source="images\greenlight.jpg"></Image>
</Button>
Se você enumerar os objetos visuais e as listas de instruções gráficas de vetor que compõem o controle Button, você encontrará a hierarquia de objetos ilustrada abaixo:
O controle Button contém um elemento ClassicBorderDecorator, que, por sua vez, contém um elemento ContentPresenter. O elemento ClassicBorderDecorator é responsável por desenhar todos os elementos gráficos discretos que compõem a borda e a tela de fundo de um botão. O elemento ContentPresenter é responsável por exibir o conteúdo do Button. Nesse caso, como você está exibindo uma imagem, o elemento ContentPresenter contém um elemento Image.
Há vários pontos a serem observados sobre a hierarquia de objetos visuais e listas de instruções gráficas de vetor:
A ordenação 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 que não são de nó folha na hierarquia, tais 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 gráficas de vetor 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 grafo de cena, contendo todas as informações de renderização necessárias para compor a saída para o dispositivo de exibição. Essa árvore é o acúmulo de todos os elementos visuais criados diretamente pelo aplicativo, seja no código ou na 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 linguagem de marcação.
<StackPanel>
<Label>User name:</Label>
<TextBox />
<Button Click="OnClick">OK</Button>
</StackPanel>
Se você enumerar os objetos visuais que compõem o elemento StackPanel no exemplo de marcação, encontrará a hierarquia de objetos visuais ilustrada abaixo:
Ordem de renderização
A árvore visual determina a ordem de renderização de 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.
diagrama
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 é 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 Win32. Para obter mais informações, consulte Tutorial: Hospedando 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 da 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 corresponde de forma próxima às definições de marcação de um aplicativo. O código a seguir mostra um elemento DockPanel definido no código de marcação.
<DockPanel>
<ListBox>
<ListBoxItem>Dog</ListBoxItem>
<ListBoxItem>Cat</ListBoxItem>
<ListBoxItem>Fish</ListBoxItem>
</ListBox>
<Button Click="OnClick">OK</Button>
</DockPanel>
Se você enumerar os objetos lógicos que compõem o elemento DockPanel no exemplo de marcação, encontrará a hierarquia de objetos lógicos ilustrada abaixo:
Diagrama da árvore lógica
A árvore visual e a árvore lógica são sincronizadas com o conjunto atual de elementos de 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 ContentPresenter de um controle. 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
Para obter mais informações sobre a árvore lógica, consulte Trees in 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 como o conteúdo XAML é expandido em nós de árvore visual no painel Visual Tree Explorer do XamlPad.
Observe como os controles
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 avançada dos dados de desempenho mapeando diretamente para a árvore visual do aplicativo. Nessa tela, a seção Uso de CPU do Visual Profiler lhe dá um detalhamento preciso do uso de um objeto de serviços do WPF, assim como renderização e layout.
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: elementos gráficos de modo retido, elementos gráficos vetoriais e elementos gráficos independentes do dispositivo.
Gráficos em 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+ usa um sistema de gráficos 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 que altera sua aparência visual.
Por outro lado, 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 contar com o sistema para responder a solicitações de pintura. A vantagem de um sistema gráfico em modo retido é que as informações de desenho são sempre mantidas em um estado serializado pelo aplicativo, mas a responsabilidade de renderização é deixada para o sistema. O diagrama a seguir mostra como o aplicativo depende do WPF para responder a solicitações de pintura.
Diagrama
Redesenho inteligente
Um dos maiores benefícios no uso de elementos gráficos de modo retido é que o WPF pode otimizar com eficiência o que precisa ser redesenhado no aplicativo. Mesmo que você tenha uma cena complexa com diferentes níveis de opacidade, geralmente não é necessário escrever código de finalidade especial para otimizar o redesenho. Compare isso com a programação win32 na qual você pode gastar muito esforço para otimizar seu aplicativo minimizando a 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 envolvido na otimização do redesenho em aplicativos Win32.
Desenho vetorial
O WPF usa gráficos vetoriais como o seu formato de dados de renderização. Os elementos gráficos vetoriais , que incluem SVG (Gráficos vetoriais escalonáveis), metafiles 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 primitivos gráficos. 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 de 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 formatos gráficos de bitmap e vetor é a fidelidade à imagem de origem original. Por exemplo, quando o tamanho de uma imagem de origem é modificado, os sistemas gráficos bitmap ampliam a imagem, enquanto os sistemas gráficos vetoriais dimensionam a imagem, preservando a fidelidade da imagem.
A ilustração a seguir mostra uma imagem original que foi redimensionada em 300%. Observe as distorções que aparecem quando a imagem de origem é ampliada como uma imagem de gráfico bitmap em vez de dimensionada como uma imagem gráfica de vetor.
Diferenças
A marcação a seguir mostra dois elementos Path definidos. O segundo elemento usa um ScaleTransform para redimensionar em 300%as instruções de desenho do primeiro elemento. Observe que as instruções de desenho nos elementos Path 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 do sistema que determinam o tamanho do texto e dos elementos gráficos na tela: resolução e DPI. A resolução descreve o número de pixels que aparecem na tela. À medida que a resolução aumenta, os pixels ficam menores, fazendo com que os gráficos e o texto apareçam menores. Um gráfico exibido em um monitor definido como 1024 x 768 será 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 aumenta a polegada da tela; diminuir o DPI torna a polegada de 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 elementos gráficos e texto com reconhecimento de DPI tornam-se maiores porque você aumentou o tamanho da polegada da tela. Aumentar o DPI pode facilitar a leitura do texto, especialmente em altas resoluções.
Nem todos os aplicativos têm reconhecimento de DPI: alguns usam pixels de hardware como a unidade primária de medida; A alteração da 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, pois 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 o WPF.
O WPF dá suporte ao dimensionamento automático usando o pixel independente do dispositivo como sua unidade primária de medição, em vez dos pixels de hardware. Gráficos e textos são dimensionados corretamente sem nenhum trabalho extra do desenvolvedor. A ilustração a seguir mostra um exemplo de como os elementos gráficos e texto do WPF são exibidos em diferentes configurações de DPI.
Gráficos e texto em diferentes configurações de DPI
Classe VisualTreeHelper
A classe VisualTreeHelper é uma classe auxiliar estática que fornece funcionalidade de baixo nível para programação no nível do 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 da estrutura WPF de nível superior, como Canvas e TextBlock, oferecem maior flexibilidade e facilidade de uso.
Testes de clique
A classe VisualTreeHelper fornece métodos para teste de clique em objetos visuais quando o suporte padrão de teste de clique não atende às suas necessidades. Você pode usar os métodos HitTest na classe VisualTreeHelper para determinar se um valor de coordenada de geometria ou 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 do teste de clique para executar seus próprios cálculos de teste de clique personalizados.
Para obter mais informações sobre o teste de colisão, consulte Teste de Colisão na Camada Visual.
Enumerando a árvore visual
A classe VisualTreeHelper fornece funcionalidade para enumerar os membros de uma árvore visual. Para recuperar um pai, chame o método GetParent. 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 talvez você queira usar se estiver interessado em serializar todas as informações 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 da 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 Trees in 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)
Consulte também
.NET Desktop feedback