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