Partilhar via


WPF Graphics Rendering Overview

This topic provides an overview of the WPF visual layer. It focuses on the role of the Visual class for rendering support in the WPF model.

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

  • Role of the Visual Object
  • How Visual Objects are Used to Build Controls
  • Visual Tree
  • Visual Rendering Behavior
  • VisualTreeHelper Class
  • Tópicos relacionados

Role of the Visual Object

The Visual class is the basic abstraction from which every FrameworkElement object derives. It also serves as the entry point for writing new controls in WPF, and in many ways can be thought of as the window handle (HWND) in the Win32 application model.

The Visual object is a core WPF object, whose primary role is to provide rendering support. User interface controls, such as Button and TextBox, derive from the Visual class, and use it for persisting their rendering data. The Visual object provides support for:

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

  • Transformações: A execução de transformações em um visual.

  • Corte: Fornecendo suporte de região de recorte para um visual.

  • O teste de hit: Determinando se uma coordenada ou geometria está contida dentro dos limites de um visual.

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

However, the Visual object does not include support for non-rendering features, such as:

  • Event handling

  • Layout

  • Styles

  • Data binding

  • Globalization

Visual is exposed as a public abstract class from which child classes must be derived. The following illustration shows the hierarchy of the visual objects that are exposed in WPF.

Visual class hierarchy

Diagrama de classes derivadas do objeto Visual

DrawingVisual Class

The DrawingVisual is a lightweight drawing class that is used to render shapes, images, or text. This class is considered lightweight because it does not provide layout or event handling, which improves its runtime performance. For this reason, drawings are ideal for backgrounds and clip art. O DrawingVisual pode ser usado para criar um objeto visual personalizado. For more information, see Using DrawingVisual Objects.

Viewport3DVisual Class

The Viewport3DVisual provides a bridge between 2D Visual and Visual3D objects. The Visual3D class is the base class for all 3D visual elements. The Viewport3DVisual requires that you define a Camera value and a Viewport value. The camera allows you to view the scene. The viewport establishes where the projection maps onto the 2D surface. For more information on 3D in WPF, see Visão geral de elementos gráficos 3D.

ContainerVisual Class

The ContainerVisual class is used as a container for a collection of Visual objects. The DrawingVisual class derives from the ContainerVisual class, allowing it to contain a collection of visual objects.

Drawing Content in Visual Objects

A Visual object stores its render data as a vector graphics instruction list. Each item in the instruction list represents a low-level set of graphics data and associated resources in a serialized format. There are four different types of render data that can contain drawing content.

Drawing content type

Description

Vector graphics

Represents vector graphics data, and any associated Brush and Pen information.

Image

Represents an image within a region defined by a Rect.

Glyph

Represents a drawing that renders a GlyphRun, which is a sequence of glyphs from a specified font resource. This is how text is represented.

Video

Represents a drawing that renders video.

The DrawingContext allows you to populate a Visual with visual content. When you use a DrawingContext object's draw commands, you are actually storing a set of render data that will later be used by the graphics system; you are not drawing to the screen in real-time.

Quando você cria um WPF de controle, como um Button, o controle implicitamente gera dados de processamento de desenho próprio. For example, setting the Content property of the Button causes the control to store a rendering representation of a glyph.

A Visual describes its content as one or more Drawing objects contained within a DrawingGroup. A DrawingGroup também descreve as 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 é processado: OpacityMask, Opacity, BitmapEffect, ClipGeometry, GuidelineSet, and then Transform.

The following illustration shows the order in which DrawingGroup operations are applied during the rendering sequence.

Order of DrawingGroup operations

Ordem de operações de DrawingGroup

For more information, see Visão Geral de Objetos de Desenho.

Drawing Content at the Visual Layer

You never directly instantiate a DrawingContext; you can, however, acquire a drawing context from certain methods, such as DrawingGroup.Open and DrawingVisual.RenderOpen. The following example retrieves a DrawingContext from a DrawingVisual and uses it to draw a rectangle.

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

Enumerating Drawing Content at the Visual Layer

In addition to their other uses, Drawing objects also provide an object model for enumerating the contents of a Visual.

Observação

When you are enumerating the contents of the visual, you are retrieving Drawing objects, and not the underlying representation of the render data as a vector graphics instruction list.

The following example uses the GetDrawing method to retrieve the DrawingGroup value of a Visual and enumerate it.

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

How Visual Objects are Used to Build Controls

Many of the objects in WPF are composed of other visual objects, meaning they can contain varying hierarchies of descendant objects. Many of the user interface elements in WPF, such as controls, are composed of multiple visual objects, representing different types of rendering elements. Por exemplo, o Button controle pode conter um número de outros objetos, incluindo ClassicBorderDecorator, ContentPresenter, e TextBlock.

The following code shows a Button control defined in markup.

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

If you were to enumerate the visual objects that comprise the default Button control, you would find the hierarchy of visual objects illustrated below:

Diagram of visual tree hierarchy

Diagrama de hierarquia de árvore visual

The Button control contains a ClassicBorderDecorator element, which in turn, contains a ContentPresenter element. The ClassicBorderDecorator element is responsible for drawing a border and a background for the Button. The ContentPresenter element is responsible for displaying the contents of the Button. In this case, since you are displaying text, the ContentPresenter element contains a TextBlock element. The fact that the Button control uses a ContentPresenter means that the content could be represented by other elements, such as an Image or a geometry, such as an EllipseGeometry.

Control Templates

The key to the expansion of a control into a hierarchy of controls is the ControlTemplate. A control template specifies the default visual hierarchy for a control. When you explicitly reference a control, you implicitly reference its visual hierarchy. You can override the default values for a control template to create a customized visual appearance for a control. For example, you could modify the background color value of the Button control so that it uses a linear gradient color value instead of a solid color value. For more information, see Modelos e estilos de botão.

A user interface element, such as a Button control, contains several vector graphics instruction lists that describe the entire rendering definition of a control. The following code shows a Button control defined in markup.

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

If you were to enumerate the visual objects and vector graphics instruction lists that comprise the Button control, you would find the hierarchy of objects illustrated below:

Diagram of visual tree and rendering data

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

The Button control contains a ClassicBorderDecorator element, which in turn, contains a ContentPresenter element. The ClassicBorderDecorator element is responsible for drawing all the discrete graphic elements that make up the border and background of a button. The ContentPresenter element is responsible for displaying the contents of the Button. In this case, since you are displaying an image, the ContentPresenter element contains a Image element.

There are a number of points to note about the hierarchy of visual objects and vector graphics instruction lists:

  • The ordering in the hierarchy represents the rendering order of the drawing information. From the root visual element, child elements are traversed, left to right, top to bottom. If an element has visual child elements, they are traversed before the element’s siblings.

  • Non-leaf node elements in the hierarchy, such as ContentPresenter, are used to contain child elements—they do not contain instruction lists.

  • If a visual element contains both a vector graphics instruction list and visual children, the instruction list in the parent visual element is rendered before drawings in any of the visual child objects.

  • The items in the vector graphics instruction list are rendered left to right.

Visual Tree

The visual tree contains all visual elements used in an application's user interface. Since a visual element contains persisted drawing information, you can think of the visual tree as a scene graph, containing all the rendering information needed to compose the output to the display device. This tree is the accumulation of all visual elements created directly by the application, whether in code or in markup. The visual tree also contains all visual elements created by the template expansion of elements such as controls and data objects.

The following code shows a StackPanel element defined in markup.

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

If you were to enumerate the visual objects that comprise the StackPanel element in the markup example, you would find the hierarchy of visual objects illustrated below:

Diagram of visual tree hierarchy

Diagrama de hierarquia de árvore visual

Rendering Order

The visual tree determines the rendering order of WPF visual and drawing objects. The order of traversal starts with the root visual, which is the top-most node in the visual tree. The root visual’s children are then traversed, left to right. If a visual has children, its children are traversed before the visual’s siblings. This means that the content of a child visual is rendered in front of the visual's own content.

Diagram of visual tree rendering order

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

Root Visual

The root visual is the top-most element in a visual tree hierarchy. In most applications, the base class of the root visual is either Window or NavigationWindow. However, if you were hosting visual objects in a Win32 application, the root visual would be the top-most visual you were hosting in the Win32 window. For more information, see Tutorial: Hospedando objetos visuais em um aplicativo Win32.

Relationship to the Logical Tree

A árvore lógica no WPF representa os elementos de um aplicativo em tempo de execução. Although you do not manipulate this tree directly, this view of the application is useful for understanding property inheritance and event routing. Unlike the visual tree, the logical tree can represent non-visual data objects, such as ListItem. In many cases, the logical tree maps very closely to an application's markup definitions. The following code shows a DockPanel element defined in markup.

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

If you were to enumerate the logical objects that comprise the DockPanel element in the markup example, you would find the hierarchy of logical objects illustrated below:

Diagram of logical tree

Diagrama de árvore

Both the visual tree and logical tree are synchronized with the current set of application elements, reflecting any addition, deletion, or modification of elements. However, the trees present different views of the application. Unlike the visual tree, the logical tree does not expand a control's ContentPresenter element. This means there is not a direct one-to-one correspondence between a logical tree and a visual tree for the same set of objects. In fact, invoking the LogicalTreeHelper object's GetChildren method and the VisualTreeHelper object's GetChild method using the same element as a parameter yields differing results.

For more information on the logical tree, see Árvores em WPF.

Viewing the Visual Tree with XamlPad

The WPF tool, XamlPad, provides an option for viewing and exploring the visual tree that corresponds to the currently defined XAML content. Click the Show Visual Tree button on the menu bar to display the visual tree. A seguir ilustra a expansão da XAML conteúdo em nós de árvore visual na Explorer da árvore Visual o painel de XamlPad:

Visual Tree Explorer panel in XamlPad

Painel do gerenciador de árvore visual no XamlPad

Notice how the Label, TextBox, and Button controls each display a separate visual object hierarchy in the Visual Tree Explorer panel of XamlPad. Isso ocorre porque WPF controles têm um ControlTemplate que contém a árvore visual do controle. When you explicitly reference a control, you implicitly reference its visual hierarchy.

Profiling Visual Performance

WPF provides a suite of performance profiling tools that allow you to analyze the run-time behavior of your application and determine the types of performance optimizations you can apply. The Visual Profiler tool provides a rich, graphical view of performance data by mapping directly to the application's visual tree. In this screenshot, the CPU Usage section of the Visual Profiler gives you a precise breakdown of an object's use of WPF services, such as rendering and layout.

Visual Profiler display output

Saída da exibição do Visual Profiler

Visual Rendering Behavior

WPFapresenta vários recursos que afetam o comportamento de processamento de objetos visuais: retidos gráficos de modo, gráficos vetoriais e gráficos independentes de dispositivo.

Retained Mode Graphics

One of the keys to understanding the role of the Visual object is to understand the difference between immediate mode and retained mode graphics systems. A standard Win32 application based on GDI or GDI+ uses an immediate mode graphics system. This means that the application is responsible for repainting the portion of the client area that is invalidated, due to an action such as a window being resized, or an object changing its visual appearance.

Diagram of Win32 rendering sequence

Diagrama de sequência de renderização Win32

In contrast, WPF uses a retained mode system. This means application objects that have a visual appearance define a set of serialized drawing data. Once the drawing data is defined, the system is responsible thereafter for responding to all repaint requests for rendering the application objects. Even at run time, you can modify or create application objects, and still rely on the system for responding to paint requests. The power in a retained mode graphics system is that drawing information is always persisted in a serialized state by the application, but rendering responsibility left to the system. The following diagram shows how the application relies on WPF for responding to paint requests.

Diagram of WPF rendering sequence

Diagrama de sequência de renderização WPF

Intelligent Redrawing

One of the biggest benefits in using retained mode graphics is that WPF can efficiently optimize what needs to be redrawn in the application. Even if you have a complex scene with varying levels of opacity, you generally do not need to write special-purpose code to optimize redrawing. Compare this with Win32 programming in which you can spend a great deal of effort in optimizing your application by minimizing the amount of redrawing in the update region. Consulte Redrawing na região de atualização para obter um exemplo do tipo de complexidade envolvida na otimização redesenho em aplicativos Win32.

Vector Graphics

WPF uses vector graphics as its rendering data format. Vector graphics—which include Scalable Vector Graphics (SVG), Windows metafiles (.wmf), and TrueType fonts—store rendering data and transmit it as a list of instructions that describe how to recreate an image using graphics primitives. For example, TrueType fonts are outline fonts that describe a set of lines, curves, and commands, rather than an array of pixels. One of the key benefits of vector graphics is the ability to scale to any size and resolution.

Unlike vector graphics, bitmap graphics store rendering data as a pixel-by-pixel representation of an image, pre-rendered for a specific resolution. One of the key differences between bitmap and vector graphic formats is fidelity to the original source image. For example, when the size of a source image is modified, bitmap graphics systems stretch the image, whereas vector graphics systems scale the image, preserving the image fidelity.

The following illustration shows a source image that has been resized by 300%. Notice the distortions that appear when the source image is stretched as a bitmap graphics image rather than scaled as a vector graphics image.

Differences between raster and vector graphics

Diferenças entre elementos gráficos de varredura e vetoriais

The following markup shows two Path elements defined. The second element uses a ScaleTransform to resize the drawing instructions of the first element by 300%. Notice that the drawing instructions in the Path elements remain unchanged.

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

About Resolution and Device-Independent Graphics

Há dois fatores de sistema que determinam o tamanho do texto e elementos gráficos na tela: resolução e DPI. Resolution describes the number of pixels that appear on the screen. As the resolution gets higher, pixels get smaller, causing graphics and text to appear smaller. A graphic displayed on a monitor set to 1024 x 768 will appear much smaller when the resolution is changed to 1600 x 1200.

The other system setting, DPI, describes the size of a screen inch in pixels. Most Windows systems have a DPI of 96, which means a screen inch is 96 pixels. Increasing the DPI setting makes the screen inch larger; decreasing the DPI makes the screen inch smaller. This means that a screen inch isn't the same size as a real-world inch; on most systems, it's probably not. As you increase the DPI, DPI-aware graphics and text become larger because you've increased the size of the screen inch. Increasing the DPI can make text easier to read, especially at high resolutions.

Nem todos os aplicativos estão cientes do PPP: alguns usam pixels de hardware, como a principal unidade de medida; alterar o sistema de PPP não tem efeito nesses aplicativos. Many other applications use DPI-aware units to describe font sizes, but use pixels to describe everything else. Making the DPI too small or too large can cause layout problems for these applications, because the applications' text scales with the system's DPI setting, but the applications' UI does not. This problem has been eliminated for applications developed using WPF.

WPFoferece suporte ao dimensionamento automático usando o pixel independente de dispositivo, como sua principal unidade de medida, em vez de pixels de hardware; escala de elementos gráficos e texto corretamente sem nenhum trabalho extra do desenvolvedor do aplicativo. The following illustration shows an example of how WPF text and graphics are appear at different DPI settings.

Graphics and text at different DPI settings

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

VisualTreeHelper Class

The VisualTreeHelper class is a static helper class that provides low-level functionality for programming at the visual object level, which is useful in very specific scenarios, such as developing high-performance custom controls. Na maioria dos casos, o nível mais alto WPF estrutura de objetos, como Canvas e TextBlock, oferecem maior flexibilidade e facilidade de uso.

Hit Testing

The VisualTreeHelper class provides methods for hit testing on visual objects when the default hit test support does not meet your needs. You can use the HitTest methods in the VisualTreeHelper class to determine whether a geometry or point coordinate value is within the boundary of a given object, such as a control or graphic element. For example, you could use hit testing to determine whether a mouse click within the bounding rectangle of an object falls within the geometry of a circle You can also choose to override the default implementation of hit testing to perform your own custom hit test calculations.

For more information on hit testing, see Hit Testing in the Visual Layer.

Enumerating the Visual Tree

The VisualTreeHelper class provides functionality for enumerating the members of a visual tree. To retrieve a parent, call the GetParent method. To retrieve a child, or direct descendant, of a visual object, call the GetChild method. This method returns a child Visual of the parent at the specified index.

The following example shows how to enumerate all the descendants of a visual object, which is a technique you might want to use if you were interested in serializing all the rendering information of a visual object hierarchy.

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

In most cases, the logical tree is a more useful representation of the elements in a WPF application. Although you do not modify the logical tree directly, this view of the application is useful for understanding property inheritance and event routing. Unlike the visual tree, the logical tree can represent non-visual data objects, such as ListItem. For more information on the logical tree, see Árvores em WPF.

The VisualTreeHelper class provides methods for returning the bounding rectangle of visual objects. You can return the bounding rectangle of a visual object by calling GetContentBounds. You can return the bounding rectangle of all the descendants of a visual object, including the visual object itself, by calling GetDescendantBounds. The following code shows how you would calculate the bounding rectangle of a visual object and all its descendants.

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

Consulte também

Referência

Visual

VisualTreeHelper

DrawingVisual

Conceitos

Otimização de desempenho: 2D Graphics and Imaging

Hit Testing in the Visual Layer

Using DrawingVisual Objects

Tutorial: Hospedando objetos visuais em um aplicativo Win32

Optimizing WPF Application Performance