Para ver el artículo en inglés, active la casilla Inglés. También puede ver el texto en inglés en una ventana emergente si pasa el puntero del mouse por el texto.
Traducción
Inglés

Información general sobre la representación de gráficos en WPF

 

Publicado: junio de 2016

En este tema se proporciona información general sobre la capa visual de WPF. Se centra en el rol de la clase Visual para admitir la representación del modelo de WPF.

La clase Visual es la abstracción básica de la que se derivan todos los objetos FrameworkElement. También actúa como punto de entrada para escribir nuevos controles en WPF, y en muchos sentidos se puede considerar como el identificador de ventana (HWND) del modelo de aplicaciones de Win32.

El objeto Visual es un objeto básico de WPF, cuyo rol principal es proporcionar la compatibilidad con la representación. Los controles de interfaz de usuario, tales como Button y TextBox, se derivan de la clase Visual y la utilizan para conservar sus datos de representación. El objeto Visual proporciona compatibilidad con:

  • Presentación de salida: representación del contenido conservado y serializado de un elemento visual.

  • Transformaciones: ejecución de las transformaciones de un elemento visual.

  • Recorte: compatibilidad con la zona de recorte para un elemento visual.

  • Pruebas de posicionamiento: determinación de si una coordenada o geometría está contenida dentro de los límites de un elemento visual.

  • Cálculos del rectángulo de selección: determinación del rectángulo delimitador de un elemento visual.

Sin embargo, el objeto Visual no incluye compatibilidad con características que no son de representación, tales como:

  • Control de eventos

  • Diseño

  • Estilos

  • Enlace de datos

  • Globalización

Visual se expone como una clase abstracta pública de la que se deben derivar las clases secundarias. En la ilustración siguiente se muestra la jerarquía de los objetos visuales que se exponen en WPF.

Diagrama de clases derivadas del objeto Visual

Jerarquía de la clase Visual

DrawingVisual es una clase de dibujo ligera que se utiliza para representar formas, imágenes o texto. Esta clase se considera ligera porque no proporciona administración del diseño ni control de eventos, lo que mejora su rendimiento en tiempo de ejecución. Por esta razón, los dibujos son idóneos para fondos e imágenes prediseñadas. DrawingVisual se puede utilizar para crear un objeto visual personalizado. Para obtener más información, consulte Usar objetos DrawingVisual.

Viewport3DVisual proporciona un puente entre los objetos 2D Visual y Visual3D. La clase Visual3D es la clase base para los elementos visuales 3D. Viewport3DVisual requiere que se defina un valor Camera y un valor Viewport. La cámara permite ver la escena. La ventanilla establece dónde se asigna la proyección a la superficie 2D. Para obtener más información sobre 3D en WPF, vea Información general sobre gráficos 3D.

La clase ContainerVisual se utiliza como contenedor de una colección de objetos Visual. La clase DrawingVisual se deriva de la clase ContainerVisual, lo que le permite contener una colección de objetos visuales.

Un objeto Visual almacena sus datos de representación como una lista de instrucciones de gráficos vectoriales. Cada elemento de la lista de instrucciones representa un conjunto de bajo nivel de datos de los gráficos y de recursos asociados en un formato serializado. Hay cuatro tipos diferentes de datos de representación que pueden incluir contenido de dibujo.

Tipo de contenido de los dibujos

Descripción

Gráficos vectoriales

Representa datos de gráficos vectoriales y e información de cualquier Brush y Pen asociado.

Image

Representa una imagen dentro de una región definida por un Rect.

Glifo

Representa un dibujo que representa un GlyphRun, que es una secuencia de glifos de un recurso de fuente especificado. Así es como se representa el texto.

Vídeo

Representa un dibujo que representa el vídeo.

DrawingContext permite rellenar un objeto Visual con contenido visual. Cuando se utilizan los comandos de dibujo de un objeto DrawingContext, en realidad se está almacenando un conjunto de datos de representación que el sistema de gráficos utilizará más adelante; no se dibuja en la pantalla en tiempo real.

Al crear un control WPF, como Button, el control genera implícitamente datos de representación para dibujarse a sí mismo. Por ejemplo, al establecer la propiedad Content de Button hace que el control almacene una representación de la representación de un glifo.

Un objeto Visual describe su contenido como uno o más objetos Drawing contenidos dentro de un DrawingGroup. Un objeto DrawingGroup también describe las máscaras de opacidad, las transformaciones, los efectos de imagen y otras operaciones que se aplican a su contenido. Las operaciones de DrawingGroup se aplican en el orden siguiente al representar contenido: OpacityMask, Opacity, BitmapEffect, ClipGeometry, GuidelineSet y, a continuación, Transform.

En la ilustración siguiente se muestra el orden en el que se aplican las operaciones de DrawingGroup durante la secuencia de representación.

Orden de operaciones de DrawingGroup

Orden de las operaciones de DrawingGroup

Para obtener más información, vea Información general sobre objetos Drawing.

Nunca se crea directamente una instancia de DrawingContext; sin embargo, se puede adquirir un contexto de dibujo a partir de determinados métodos, como DrawingGroup.Open y DrawingVisual.RenderOpen. En el ejemplo siguiente se recupera un objeto DrawingContext de un objeto DrawingVisual y se utiliza para dibujar un rectá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;
}

Además de sus otros usos, los objetos Drawing también proporcionan un modelo de objetos para enumerar el contenido de Visual.

System_CAPS_noteNota

Al enumerar el contenido del elemento visual, se recuperan objetos Drawing, no la representación subyacente de los datos de representación como una lista de instrucciones de gráficos vectoriales.

En el ejemplo siguiente se utiliza el método GetDrawing para recuperar el valor de DrawingGroup de un objeto Visual y enumerarlo.

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

}

 // 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.GetType() == typeof(DrawingGroup))
         {
             EnumDrawingGroup((DrawingGroup)drawing);
         }
         else if (drawing.GetType() == typeof(GeometryDrawing))
         {
             // Perform action based on drawing type.  
         }
         else if (drawing.GetType() == typeof(ImageDrawing))
         {
             // Perform action based on drawing type.
         }
         else if (drawing.GetType() == typeof(GlyphRunDrawing))
         {
             // Perform action based on drawing type.
         }
         else if (drawing.GetType() == typeof(VideoDrawing))
         {
             // Perform action based on drawing type.
         }
     }
 }

Muchos de los objetos de WPF están compuestos de otros objetos visuales, lo que significa que pueden contener diversas jerarquías de objetos descendientes. Muchos de los elementos de interfaz de usuario de WPF, como los controles, están compuestos de varios objetos visuales, que constituyen diferentes tipos de de representar los elementos. Por ejemplo, el control Button puede contener varios otros objetos, incluso ClassicBorderDecorator, ContentPresenter y TextBlock.

En el ejemplo de código siguiente se muestra un control Button definido en el marcado.

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

Si enumerase los objetos visuales que comprenden el control Button predeterminado, hallaría la jerarquía de objetos visuales ilustrada a continuación:

Diagrama de jerarquía de árbol visual

Diagrama de jerarquía de árbol de elementos visuales

El control Button contiene un elemento ClassicBorderDecorator que, a su vez, contiene un elemento ContentPresenter. El elemento ClassicBorderDecorator es responsable de dibujar un borde y un fondo para Button. El elemento ContentPresenter es responsable de mostrar el contenido de Button. En este caso, puesto que se muestra texto, el elemento ContentPresenter contiene un elemento TextBlock. El hecho de que el control Button utilice ContentPresenter quiere decir que el contenido podría representarse por otros elementos, como Image o por una geometría, como EllipseGeometry.

La clave para la expansión de un control en una jerarquía de controles es ControlTemplate. Una plantilla de control especifica la jerarquía visual predeterminada de un control. Al hacer referencia explícitamente a un control, se hace referencia implícitamente a su jerarquía visual. Puede invalidar los valores predeterminados de una plantilla a fin de crear un aspecto visual personalizado para un control. Por ejemplo, podría modificar el valor de color de fondo del control Button de modo que utilice un valor de color de degradado lineal en lugar de un valor de color sólido. Para obtener más información, vea Estilos y plantillas de Button.

Un elemento de interfaz de usuario, como un control Button, contiene varias listas de instrucciones de gráficos vectoriales que describen la definición de representación completa de un control. En el ejemplo de código siguiente se muestra un control Button definido en el marcado.

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

Si enumerase los objetos visuales y las listas de instrucciones de gráficos vectoriales que comprenden el control Button, hallaría la jerarquía de objetos ilustrada a continuación:

Diagrama de árbol visual y datos de representación

Diagrama de árbol visual y datos de representación

El control Button contiene un elemento ClassicBorderDecorator que, a su vez, contiene un elemento ContentPresenter. El elemento ClassicBorderDecorator es responsable de dibujar todos los elementos gráficos discretos que constituyen el borde y el fondo de un botón. El elemento ContentPresenter es responsable de mostrar el contenido de Button. En este caso, puesto que se muestra una imagen, el elemento ContentPresenter contiene un elemento Image.

Deben tenerse en cuenta varios puntos sobre la jerarquía de objetos visuales y las listas de instrucciones de gráficos vectoriales:

  • El orden en la jerarquía representa el orden de representación de la información de dibujo. Partiendo del elemento visual raíz, los elementos secundarios se recorren de izquierda a derecha y de arriba abajo. Si un elemento tiene elementos visuales secundarios, se recorren antes que los elementos del mismo nivel.

  • Los elementos de nodos que no sean de hoja de la jerarquía, tales como ContentPresenter, se utilizan para contener elementos secundarios, no contienen listas de instrucciones.

  • Si un elemento visual contiene una lista de instrucciones de gráficos vectoriales y elementos visuales secundarios, la lista de instrucciones del elemento visual primario se representará antes que los dibujos de cualquiera de los objetos visuales secundarios.

  • Los elementos de la lista de instrucciones de gráficos vectoriales se representan de izquierda a derecha.

El árbol visual contiene todos los elementos visuales utilizados en la interfaz de usuario de una aplicación. Puesto que un elemento visual contiene información de dibujo conservada, puede considerar el árbol visual como una representación gráfica de la escena, que contiene toda la información de representación necesaria para crear la salida al dispositivo de pantalla. Este árbol es la acumulación de todos los elementos visuales creados directamente por la aplicación, ya sea en el código o en el marcado. El árbol visual también contiene todos los elementos visuales creados por la expansión de la plantilla de elementos tales como controles y objetos de datos.

En el ejemplo de código siguiente se muestra un elemento StackPanel definido en el marcado.

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

Si enumerase los objetos visuales que comprenden el elemento StackPanel del ejemplo de marcado, hallaría la jerarquía de objetos visuales ilustrada a continuación:

Diagrama de jerarquía de árbol visual

Diagrama de jerarquía de árbol de elementos visuales

El árbol visual determina el orden de representación de los objetos visuales y de dibujo de WPF. El orden del recorrido comienza en el elemento visual raíz, que es el nodo del nivel superior del árbol visual. A continuación se recorren los elementos secundarios del elemento visual raíz, de izquierda a derecha. Si un elemento visual tiene elementos secundarios, éstos últimos se recorren antes que los elementos que están en el mismo nivel que el elemento visual. Esto significa que el contenido de un elemento visual secundario se representa delante del propio contenido del elemento visual.

Diagrama de orden de representación de árbol visual

Diagrama del orden de representación del árbol visual

El elemento visual raíz es el elemento de nivel superior de la jerarquía de un árbol visual. En la mayoría de las aplicaciones, la clase base del elemento visual raíz es Window o NavigationWindow. Sin embargo, si hospedase objetos visuales en una aplicación de Win32, el elemento visual raíz sería el elemento visual de nivel superior que hospedase en la ventana de Win32. Para obtener más información, vea Tutorial: Hospedar objetos visuales en una aplicación Win32.

El árbol lógico de WPF representa los elementos de una aplicación en tiempo de ejecución. Aunque no se manipula directamente este árbol, esta vista de la aplicación es útil para entender la herencia de propiedades y el enrutamiento de eventos. A diferencia del árbol visual, el árbol lógico puede representar objetos de datos no visuales, tales como ListItem. En muchos casos, el árbol lógico se corresponde muy estrechamente con las definiciones de marcado de una aplicación. En el ejemplo de código siguiente se muestra un elemento DockPanel definido en el marcado.

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

Si enumerase los objetos lógicos que comprenden el elemento DockPanel del ejemplo de marcado, hallaría la jerarquía de objetos lógicos ilustrada a continuación:

Diagrama de árbol

Diagrama de árbol lógico

El árbol visual y el árbol lógico se sincronizan con el conjunto actual de elementos de aplicación, con lo que se refleja cualquier adición, eliminación o modificación de elementos. Sin embargo, los árboles presentan vistas diferentes de la aplicación. A diferencia del árbol visual, el árbol lógico no expande el elemento ContentPresenter de un control. Esto significa que no existe una correspondencia unívoca directa entre un árbol lógico y un árbol visual para el mismo conjunto de objetos. De hecho, al invocar el método GetChildren del objeto LogicalTreeHelper y el método GetChildVisualTreeHelper del objeto utilizando el mismo elemento como parámetro se obtienen resultados diferentes.

Para obtener más información sobre el árbol lógico, vea Árboles en WPF.

La herramienta XamlPad de WPF proporciona una opción para ver y explorar el árbol visual que corresponde al contenido de XAML actualmente definido. Haga clic en el botón Show Visual Tree en la barra de menús para mostrar el árbol visual. A continuación se ilustra la expansión del contenido de XAML en los nodos del árbol visual en el panel Visual Tree Explorer de XamlPad:

Panel del explorador de árbol visual en XamlPad

Panel del explorador de árboles visuales de XamlPad

Observe que cada uno de los controles Label, TextBox y Button muestra una jerarquía de objetos visuales independiente en el panel Visual Tree Explorer de XamlPad. Esto se debe a que los controles de WPF tienen una ControlTemplate que contiene el árbol visual de ese control. Al hacer referencia explícitamente a un control, se hace referencia implícitamente a su jerarquía visual.

WPF proporciona un conjunto de herramientas de generación de perfiles de rendimiento que permiten analizar el funcionamiento de la aplicación en tiempo de ejecución y determinar los tipos de optimización de rendimiento que se pueden aplicar. La herramienta generador de perfiles de Visual proporciona una vista gráfica y completa de los datos de rendimiento a través de una asignación directa al árbol visual de la aplicación. En esta captura de pantalla, la sección CPU Usage de Visual Profiler ofrece un desglose preciso del uso, por parte de un objeto, de servicios de WPF tales como la representación y el diseño.

Resultados del generador de perfiles de Visual

Salida de la presentación de Visual Profiler

WPF introduce varias características que afectan al comportamiento de representación de los objetos visuales: gráficos de modo retenido, gráficos vectoriales y gráficos independientes del dispositivo.

Una de las claves para entender el rol de los objetos visuales es comprender la diferencia entre los sistemas de gráficos de modo inmediato y de modo retenido. Una aplicación de Win32 estándar basada en GDI o GDI+ utiliza un sistema de gráficos de modo inmediato. Esto significa que la aplicación es responsable de volver a dibujar la parte del área cliente que se ha invalidado, ya sea debido a una acción como el cambio de tamaño de una ventana, o a la modificación del aspecto visual de un objeto.

Diagrama de secuencia de representación de Win32

Diagrama de la secuencia de representación de Win32

En cambio, WPF utiliza un sistema de modo retenido. Esto significa que los objetos de la aplicación que tienen aspecto visual definen un conjunto de datos de dibujo serializados. Una vez definidos los datos de dibujo, el sistema se hace responsable en lo sucesivo de responder a todas las solicitudes de repetición del dibujo para representar los objetos de aplicación. Incluso en tiempo de ejecución, se puede modificar o crear los objetos de aplicación y, aún así, confiar en que el sistema responderá a las solicitudes de dibujo. La eficacia de un sistema de gráficos de modo retenido reside en que la aplicación conserva en todo momento la información de dibujo siempre en un estado serializado, pero deja al sistema la responsabilidad de la representación. En el diagrama siguiente se muestra cómo delega la aplicación en WPF para que responda a las solicitudes de dibujo.

Diagrama de secuencia de representación de WPF

Diagrama de la secuencia de representación de WPF

Una de las mayores ventajas que aporta el uso de gráficos de modo retenidos es que WPF puede optimizar con eficacia lo que es preciso volver a dibujar en la aplicación. Aunque se trate de una escena compleja con varios niveles de opacidad, generalmente no se necesita escribir código específico para optimizar la actualización del dibujo. Compare esto con la programación de Win32, en la que se puede llegar a dedicar mucho esfuerzo a optimizar la aplicación minimizando la cantidad de actualizaciones del dibujo que se efectúan en la región de actualización. Vea Redrawing in the Update Region para obtener un ejemplo del tipo de complejidad que conlleva la optimización de la actualización del dibujo en las aplicaciones de Win32.

WPF utiliza gráficos vectoriales como su formato de representación de datos. Los gráficos vectoriales, que incluyen gráficos vectoriales escalables (SVG), metarchivos de Windows (.wmf) y fuentes TrueType, almacenan los datos de representación y los transmiten como una lista de instrucciones que describen cómo volver a crear la imagen mediante los elementos primitivos de los gráficos. Por ejemplo, las fuentes TrueType son fuentes de contorno que describen un conjunto de líneas, curvas y comandos, en lugar de una matriz de píxeles. Una de las ventajas fundamentales de los gráficos vectoriales es la capacidad de adaptar su escala a cualquier tamaño y resolución.

Al contrario que los gráficos vectoriales, los gráficos de mapa de bits almacenan los datos de representación como una representación píxel por píxel de una imagen, previamente representada para una resolución específica. Una de las diferencias fundamentales entre los formatos de gráficos de mapa de bits y vectorial es la fidelidad con respecto a la imagen de origen inicial. Por ejemplo, cuando se modifica el tamaño de la imagen de origen, los sistemas de gráficos de mapa de bits ajustan la imagen, mientras que los sistemas de gráficos vectoriales adaptan su escala, conservando la fidelidad con la imagen inicial.

En la ilustración siguiente se muestra una imagen de origen cuyo tamaño se ha cambiado al 300%. Observe las distorsiones que aparecen cuando se amplía la imagen de origen como imagen de gráficos de mapa de bits en lugar de ajustarla a escala como imagen de gráficos vectoriales.

Diferencias entre gráficos de trama y vectoriales

Diferencias entre gráficos de tramas y vectoriales

En el marcado siguiente se muestran dos elementos Path definidos. El segundo elemento utiliza un objeto ScaleTransform para cambiar el tamaño de las instrucciones de dibujo del primer elemento al 300%. Observe que las instrucciones de dibujo de los elementos Path no sufren cambio alguno.

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

Existen dos factores del sistema que determinan el tamaño del texto y los gráficos en la pantalla: la resolución y los píxeles por pulgada (PPP). La resolución describe el número de píxeles que aparecen en la pantalla. A medida que aumenta la resolución, se reducen los píxeles, lo que hace que los gráficos y el texto parezcan menores. Un gráfico mostrado en un monitor configurado con una resolución de 1024 x 768 parece mucho menor cuando la resolución se cambia a 1600 x 1200.

El otro valor del sistema, PPP, describe el tamaño de una pulgada de pantalla en píxeles. La mayoría de los sistemas Windows tienen un valor de PPP de 96, lo que significa que pulgada de pantalla tiene 96 píxeles. Al aumentar el valor de PPP se incrementa el tamaño de la pulgada de pantalla; al disminuir el valor de PPP se reduce el tamaño de la pulgada de pantalla. Esto significa que una pulgada de pantalla no tiene el mismo tamaño que una pulgada real; en la mayoría de los sistemas, probablemente ambas pulgadas no sean iguales. Cuando se incrementa el valor de PPP, los gráficos y el texto que tienen en cuenta los PPP aumentan, porque se ha incrementado el tamaño de la pulgada de pantalla. Al aumentar el valor de PPP se puede facilitar la lectura del texto, especialmente con las resoluciones más altas.

No todas las aplicaciones tienen en cuenta el valor de PPP: algunas utilizan los píxeles de hardware como unidad de medida principal; en estas aplicaciones, cambiar los PPP del sistema no surte ningún efecto. Muchas otras aplicaciones utilizan unidades que tienen en cuenta el valor de PPP para describir los tamaños de fuente, pero utilizan píxeles para describir todo lo demás. Un valor de PPP demasiado pequeño o demasiado grande puede causar problemas del diseño en estas aplicaciones, porque el texto de la aplicación adapta su escala de acuerdo con el valor de PPP del sistema, pero, en cambio, la interfaz de usuario de la aplicación no lo hace. Este problema se ha eliminado para las aplicaciones programadas mediante WPF.

WPF admite el ajuste automático de la escala, ya que utiliza píxeles independientes del dispositivo como unidad de medida principal, en lugar de los píxeles del hardware; la escala de los gráficos y del texto se adapta correctamente sin que el desarrollador de la aplicación tenga que realizar ninguna labor adicional. En la ilustración siguiente se muestra un ejemplo de cómo aparecen el texto y los gráficos de WPF con distintos valores de PPP.

Gráficos y texto en diferentes valores de PPP

Gráficos y texto con distintos valores de PPP

La clase VisualTreeHelper es una clase auxiliar estática que proporciona funcionalidad de bajo nivel para programar en el nivel de objetos visuales, lo que resulta útil en escenarios muy concretos, como el de la programación de controles personalizados de alto rendimiento. En la mayoría de los casos, los objetos del marco de trabajo WPF de nivel superior, tales como Canvas y TextBlock, proporcionan mayor flexibilidad y facilidad de uso.

La clase VisualTreeHelper proporciona métodos para efectuar las pruebas de posicionamiento de los objetos visuales la compatibilidad de pruebas de posicionamiento predeterminada no satisface sus necesidades. Puede utilizar los métodos HitTest en la clase VisualTreeHelper para determinar si una geometría o el valor de coordenada de punto está dentro del límite de un objeto determinado, como un control o elemento gráfico. Por ejemplo, podría utilizar las pruebas de posicionamiento para determinar si un clic del mouse dentro del rectángulo delimitador de un objeto pertenece a la geometría de un círculo. Si lo desea, también puede invalidar la implementación predeterminada de las pruebas de posicionamiento y realizar sus propios cálculos de pruebas de posicionamiento personalizadas.

Para obtener más información sobre pruebas de posicionamiento, vea Realizar pruebas de posicionamiento en la capa visual.

La clase VisualTreeHelper proporciona la funcionalidad de enumerar los miembros de un árbol visual. Para recuperar un objeto primario, llame al método GetParent. Para recuperar un elemento secundario o un descendiente directo de un objeto visual, llame al método GetChild. Este método devuelve el elemento secundario Visual del elemento primario en el índice especificado.

En el ejemplo siguiente se muestra cómo enumerar todos los descendientes de un objeto visual, que es una técnica que se puede utilizar si se desea serializar toda la información de representación de una jerarquía de objetos visuales.

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

En la mayoría de los casos, el árbol lógico constituye una representación más útil de los elementos de una aplicación WPF. Aunque no se modifica directamente el árbol lógico, esta vista de la aplicación es útil para entender la herencia de propiedades y el enrutamiento de eventos. A diferencia del árbol visual, el árbol lógico puede representar objetos de datos no visuales, tales como ListItem. Para obtener más información sobre el árbol lógico, vea Árboles en WPF.

La clase VisualTreeHelper proporciona métodos para devolver el rectángulo delimitador de los objetos visuales. Puede devolver el rectángulo delimitador de un objeto visual llamando a GetContentBounds. Puede devolver el rectángulo delimitador de todos los descendientes de un objeto visual, incluido el propio objeto visual, llamando a GetDescendantBounds. En el código siguiente se muestra cómo se calcularía el rectángulo delimitador de un objeto visual y todos sus descendientes.

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