Compartilhar via


Inicialização para elementos do objeto não está em uma árvore de objetos

Some aspects of Windows Presentation Foundation (WPF) initialization are deferred to processes that typically rely on that element being connected to either the logical tree or visual tree. This topic describes the steps that may be necessary in order to initialize an element that is not connected to either tree.

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

  • Elements and the Logical Tree
  • Tópicos relacionados

Elements and the Logical Tree

Quando você cria uma instância de um Windows Presentation Foundation (WPF) classe no código, você deve estar ciente de que vários aspectos do objeto de inicialização para um Windows Presentation Foundation (WPF) classe são deliberadamente não fizer parte do código que é executado quando chamar o construtor de classe. Particularly for a control class, most of the visual representation of that control is not defined by the constructor. Instead, the visual representation is defined by the control's template. The template potentially comes from a variety of sources, but most often the template is obtained from theme styles. Templates are effectively late-binding; the necessary template is not attached to the control in question until the control is ready for layout. And the control is not ready for layout until it is attached to a logical tree that connects to a rendering surface at the root. It is that root-level element that initiates the rendering of all of its child elements as defined in the logical tree.

The visual tree also participates in this process. Elements that are part of the visual tree through the templates are also not fully instantiated until connected.

The consequences of this behavior are that certain operations that rely on the completed visual characteristics of an element require additional steps. An example is if you are attempting to get the visual characteristics of a class that was constructed but not yet attached to a tree. For instance, if you want to call Render on a RenderTargetBitmap and the visual you are passing is an element not connected to a tree, that element is not visually complete until additional initialization steps are completed.

Using BeginInit and EndInit to Initialize the Element

Various classes in WPF implement the ISupportInitialize interface. You use the BeginInit and EndInit methods of the interface to denote a region in your code that contains initialization steps (such as setting property values that affect rendering). After EndInit is called in the sequence, the layout system can process the element and start looking for an implicit style.

If the element you are setting properties on is a FrameworkElement or FrameworkContentElement derived class, then you can call the class versions of BeginInit and EndInit rather than casting to ISupportInitialize.

Sample Code

The following example is sample code for a console application that uses rendering APIs and XamlReader.Load(Stream) of a loose XAML file to illustrate the proper placement of BeginInit and EndInit around other API calls that adjust properties that affect rendering.

The example illustrates the main function only. The functions Rasterize and Save (not shown) are utility functions that take care of image processing and IO.

        <STAThread>
        Shared Sub Main(ByVal args() As String)
            Dim e As UIElement
            Dim _file As String = Directory.GetCurrentDirectory() & "\starting.xaml"
            Using stream As Stream = File.Open(_file, FileMode.Open)
                ' loading files from current directory, project settings take care of copying the file
                Dim pc As New ParserContext()
                pc.BaseUri = New Uri(_file, UriKind.Absolute)
                e = CType(XamlReader.Load(stream, pc), UIElement)
            End Using

            Dim paperSize As New Size(8.5 * 96, 11 * 96)
            e.Measure(paperSize)
            e.Arrange(New Rect(paperSize))
            e.UpdateLayout()

'            
'             *   Render effect at normal dpi, indicator is the original RED rectangle
'             
            Dim image1 As RenderTargetBitmap = Rasterize(e, paperSize.Width, paperSize.Height, 96, 96)
            Save(image1, "render1.png")

            Dim b As New Button()
            b.BeginInit()
            b.Background = Brushes.Blue
            b.Height = 200
            b.Width = b.Height
            b.EndInit()
            b.Measure(paperSize)
            b.Arrange(New Rect(paperSize))
            b.UpdateLayout()

            ' now render the altered version, with the element built up and initialized

            Dim image2 As RenderTargetBitmap = Rasterize(b, paperSize.Width, paperSize.Height, 96, 96)
            Save(image2, "render2.png")
        End Sub
[STAThread]
static void Main(string[] args)
{
    UIElement e;
    string file = Directory.GetCurrentDirectory() + "\\starting.xaml";
    using (Stream stream = File.Open(file, FileMode.Open))
    {
        // loading files from current directory, project settings take care of copying the file
        ParserContext pc = new ParserContext();
        pc.BaseUri = new Uri(file, UriKind.Absolute);
        e = (UIElement)XamlReader.Load(stream, pc);
    }

    Size paperSize = new Size(8.5 * 96, 11 * 96);
    e.Measure(paperSize);
    e.Arrange(new Rect(paperSize));
    e.UpdateLayout();

    /*
     *   Render effect at normal dpi, indicator is the original RED rectangle
     */
    RenderTargetBitmap image1 = Rasterize(e, paperSize.Width, paperSize.Height, 96, 96);
    Save(image1, "render1.png");

    Button b = new Button();
    b.BeginInit();
    b.Background = Brushes.Blue;
    b.Width = b.Height = 200;
    b.EndInit();
    b.Measure(paperSize);
    b.Arrange(new Rect(paperSize));
    b.UpdateLayout();

    // now render the altered version, with the element built up and initialized

    RenderTargetBitmap image2 = Rasterize(b, paperSize.Width, paperSize.Height, 96, 96);
    Save(image2, "render2.png");
}

Consulte também

Conceitos

Árvores em WPF

WPF Graphics Rendering Overview

Visão geral do XAML (WPF)