初始化物件樹狀結構以外的物件元素
Windows Presentation Foundation (WPF) 初始化的某些層面會延後處理,因為這些處理通常需要將該元素連接到邏輯樹狀結構或視覺化樹狀結構。 本主題說明為了初始化未連接到任一樹狀結構的項目所需的步驟。
項目和邏輯樹狀結構
當您在程式碼中建立 Windows Presentation Foundation (WPF) 類別的執行個體時,您應該注意到 Windows Presentation Foundation (WPF) 類別的物件初始化有幾個層面刻意不屬於呼叫類別建構函式時所執行的程式碼。 特別是控制項類別,該控制項的視覺表示大部分不是由建構函式定義, 而是由控制項的範本來定義視覺表示。 範本可能來自各種不同的來源,但最常會從佈景主題樣式取得範本。 範本實際上是晚期繫結;必須等到相關控制項可以開始配置之後,才能將所需的範本附加至該控制項。 此外,控制項必須等到附加至連接到根目錄之呈現介面的邏輯樹狀結構之後,才能開始配置。 根層級項目會依照邏輯樹狀結構中的定義,來啟始其所有子項目的呈現。
視覺化樹狀結構也會參與此程序。 透過範本成為視覺化樹狀結構一部分的項目,也必須等到連接之後才能完全具現化。
此行為的結果是,依賴某個項目之完整視覺特性的特定作業需要額外的步驟。 其中一個範例是您嘗試取得某個類別的視覺特性,而此類別已建構但尚未附加至樹狀結構。 例如,如果您想要在 RenderTargetBitmap 上呼叫 Render,而且您傳遞的視覺物件是未連接到樹狀結構的元素,則必須等到完成額外的初始化步驟之後,該元素才能呈現完整的視覺效果。
使用 BeginInit 和 EndInit 來初始化項目
WPF 中的各種類別會實作 ISupportInitialize 介面。 您可以使用介面的 BeginInit 和 EndInit 方法來表示程式碼中包含初始化步驟的區域 (例如設定會影響轉譯的屬性值)。 在呼叫序列中的 EndInit 之後,配置系統可以處理元素並開始尋找隱含樣式。
如果您要在其上設定屬性的元素是 FrameworkElement 或 FrameworkContentElement 衍生類別,則可以呼叫 BeginInit 和 EndInit 的類別版本,而不是轉型成 ISupportInitialize。
範例程式碼
下列範例是主控台應用程式的範例程式碼,其使用轉譯 API 和鬆散 XAML 檔案的 XamlReader.Load(Stream),以說明 BeginInit 和 EndInit 在其他可調整影響轉譯之屬性的 API 呼叫周圍的適當位置。
此範例只會說明 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