次の方法で共有


オブジェクト ツリーにないオブジェクト要素の初期化

Windows Presentation Foundation (WPF) の初期化の一部の側面は、通常、論理ツリーまたはビジュアル ツリーに接続されているその要素に依存するプロセスに遅延されます。 このトピックでは、どちらのツリーにも接続されていない要素を初期化するために必要な手順について説明します。

要素と論理ツリー

コードで Windows Presentation Foundation (WPF) クラスのインスタンスを作成する場合、Windows Presentation Foundation (WPF) クラスのオブジェクト初期化のいくつかの側面は、クラス コンストラクターを呼び出すときに実行されるコードの一部ではないことに注意する必要があります。 特にコントロール クラスの場合、そのコントロールの視覚的表現のほとんどはコンストラクターによって定義されません。 代わりに、ビジュアル表現はコントロールのテンプレートによって定義されます。 テンプレートはさまざまなソースから取得される可能性がありますが、ほとんどの場合、テンプレートはテーマ スタイルから取得されます。 テンプレートは実質的に遅延バインディングです。必要なテンプレートは、コントロールがレイアウトの準備ができるまで、該当するコントロールにアタッチされません。 コントロールは、ルートでレンダリングするための表面に接続される論理ツリーに適用されるまで、レイアウトが可能になりません。 論理ツリーで定義されているすべての子要素のレンダリングを開始するのは、ルート レベルの要素です。

ビジュアル ツリーもこのプロセスに参加します。 テンプレートを介してビジュアル ツリーの一部である要素も、接続されるまで完全にはインスタンス化されません。

この動作の結果として、要素の完成した視覚的特性に依存する特定の操作には、追加の手順が必要になります。 たとえば、構築されたが、ツリーにまだアタッチされていないクラスの視覚的特性を取得しようとしている場合です。 たとえば、RenderTargetBitmapRender を呼び出し、渡すビジュアルがツリーに接続されていない要素である場合、追加の初期化手順が完了するまで、その要素は視覚的に完了しません。

BeginInit と EndInit を使用して要素を初期化する

WPF のさまざまなクラスは、ISupportInitialize インターフェイスを実装します。 インターフェイスの BeginInit メソッドと EndInit メソッドを使用して、初期化手順 (レンダリングに影響するプロパティ値の設定など) を含むコード内の領域を示します。 シーケンスで EndInit が呼び出されると、レイアウト システムは要素を処理し、暗黙的なスタイルの検索を開始できます。

プロパティを設定する要素が FrameworkElement または FrameworkContentElement 派生クラスである場合は、ISupportInitializeにキャストするのではなく、BeginInitEndInit のクラス バージョンを呼び出すことができます。

サンプル コード

次の例は、レンダリング API と緩い XAML ファイルの XamlReader.Load(Stream) を使用して、レンダリングに影響するプロパティを調整する他の API 呼び出しに関する BeginInitEndInit の適切な配置を示すコンソール アプリケーションのサンプル コードです。

この例では、main 関数のみを示しています。 Rasterize 関数と Save 関数 (図示せず) は、画像処理と 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

関連項目