語言

未在物件樹中的物件元素初始化

Windows Presentation Foundation (WPF) 初始化的某些層面會延後處理,因為這些處理通常需要將該元素連接到邏輯樹狀結構或視覺化樹狀結構。 本主題說明為了初始化未連接到任一樹狀結構的項目所需的步驟。

元素和邏輯樹狀結構

當您在程式碼中建立 Windows Presentation Foundation (WPF) 類別的執行個體時,您應該注意到 Windows Presentation Foundation (WPF) 類別的物件初始化有幾個層面刻意不屬於呼叫類別建構函式時所執行的程式碼。 特別是對於控制類別,大多數控制項的視覺表示並不是由建構函式定義的。 而是由控制項的範本來定義視覺表示。 範本可能來自各種不同的來源,但最常會從佈景主題樣式取得範本。 範本實際上是晚期繫結;必須等到相關控制項可以開始配置之後,才能將所需的範本附加至該控制項。 此外,控制項必須等到附加至連接到根目錄之呈現介面的邏輯樹狀結構之後,才能開始配置。 根層級項目會依照邏輯樹狀結構中的定義,來啟始其所有子項目的呈現。

視覺化樹狀結構也會參與此程序。 透過範本成為視覺化樹狀結構一部分的項目,也必須等到連接之後才能完全具現化。

此行為的結果是,依賴某個項目之完整視覺特性的特定作業需要額外的步驟。 其中一個範例是您嘗試取得某個類別的視覺特性,而此類別已建構但尚未附加至樹狀結構。 例如,如果您想在 Render 上呼叫 RenderTargetBitmap,而且您傳遞的視覺物件是未連接到樹狀結構的元素,則該元素在額外的初始化步驟完成之前,無法呈現完整的視覺效果。

使用 BeginInit 和 EndInit 來初始化項目

WPF 中的各種類別會實作 ISupportInitialize 介面。 您可以使用介面的 BeginInit 和 EndInit 方法來表示程式碼中包含初始化步驟的區域(例如設定會影響渲染的屬性值)。 在呼叫EndInit序列之後,配置系統可以處理元素並開始尋找隱含樣式。

如果您在設定屬性的元素是 `` 或 `` 衍生類別,則可以直接呼叫 `` 和 `` 的類別版本,而不需要將其轉型為 ``。

範例程式碼

下列範例是主控台應用程式的範例程式碼,使用渲染 API 和鬆散 XAML 檔案中的 XamlReader.Load(Stream),以示範如何正確放置 BeginInit 和 EndInit 於調整影響渲染屬性的其他 API 呼叫周圍。

此範例僅示範「main」函數。 Rasterize 和 函式 (未顯示) 是負責影像處理和 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

另請參閱

  • WPF 中的樹
  • WPF 圖形呈現概觀
  • WPF 中的 XAML