オブジェクト ツリーに存在しないオブジェクト要素の初期化Initialization for Object Elements Not in an Object Tree

Windows Presentation Foundation (WPF)Windows Presentation Foundation (WPF) の初期化処理では、プロセスに処理を委任することがあり、そのプロセスは、一般的にその要素が論理ツリーまたはビジュアル ツリーのいずれかに接続されていることを前提としています。Some aspects of Windows Presentation Foundation (WPF)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.

要素と論理ツリーElements and the Logical Tree

コード内で Windows Presentation Foundation (WPF)Windows Presentation Foundation (WPF) クラスのインスタンスを作成するときは、Windows Presentation Foundation (WPF)Windows Presentation Foundation (WPF) クラスのオブジェクト初期化処理の一部が、クラス コンストラクターの呼び出し時に実行されるコードから意図的に除外されていることに注意してください。When you create an instance of a Windows Presentation Foundation (WPF)Windows Presentation Foundation (WPF) class in code, you should be aware that several aspects of object initialization for a Windows Presentation Foundation (WPF)Windows Presentation Foundation (WPF) class are deliberately not a part of the code that is executed when calling the class constructor. 特に、コントロール クラスの場合は、コントロールの視覚的表現のほとんどが、コンストラクターでは定義されません。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. たとえば、呼び出そうとする場合Render上、RenderTargetBitmapを渡しているビジュアルがツリーに接続されていない要素とその要素は、追加の初期化手順が完了するまでは視覚的に完了しません。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.

BeginInit と EndInit を使用して要素を初期化するUsing BeginInit and EndInit to Initialize the Element

さまざまなクラスにWPFWPF実装、ISupportInitializeインターフェイス。Various classes in WPFWPF implement the ISupportInitialize interface. 使用する、BeginInitEndInit(レンダリングに影響をその値のプロパティの設定) には、初期化の手順を含むコード内の領域を示すためにインターフェイスのメソッド。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). EndInit呼びますで、シーケンスのレイアウト システムは、要素を処理し、暗黙的なスタイルの検索を開始します。After EndInit is called in the sequence, the layout system can process the element and start looking for an implicit style.

要素のプロパティを設定する場合は、FrameworkElementまたはFrameworkContentElement派生クラスでのクラスのバージョンを呼び出すことができますBeginInitEndInitへのキャストではなくISupportInitializeします。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

次の例は Api のレンダリングを使用するコンソール アプリケーションのサンプル コードとXamlReader.Load(Stream)looseXAMLXAMLの適切な位置を示すためにファイルBeginInitEndInitプロパティを調整する他の API 呼び出しの周りをレンダリングに影響します。The following example is sample code for a console application that uses rendering APIs and XamlReader.Load(Stream) of a loose XAMLXAML file to illustrate the proper placement of BeginInit and EndInit around other API calls that adjust properties that affect rendering.

この例では、main 関数のみを示します。The example illustrates the main function only. 関数 Rasterize および Save (この例には示していません) は、イメージ処理および入出力を扱うユーティリティ関数です。The functions Rasterize and Save (not shown) are utility functions that take care of image processing and IO.

[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");
}
        <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

関連項目See also