理解 WPF 應用程式的啟動流程、Application/Window 生命週期、XAML 編譯為 BAML 的管線機制,以及 XamlReader/XamlWriter 動態載入技術,是進階 WPF 開發者的必修課。本文結合 IL 反編譯、命令列編譯實驗,揭開 WPF 執行時的底層面紗。
Main() 呼叫 Application.Run()。Application 實例,呼叫 Run(Window)、Run()(需先設 MainWindow + Show())、或 StartupUri。OnLastWindowClose(預設):最後一個視窗關閉或呼叫 Shutdown() 結束。OnMainWindowClose:主視窗關閉即結束。OnExplicitShutdown:僅 Shutdown() 才結束,適合系統盤常駐程式。Startup、Exit、DispatcherUnhandledException(全域例外捕獲)、SessionEnding(系統登出/關機)。可在 App.xaml 綁定或代碼訂閱。
建構子 → SourceInitialized → Loaded → ContentRendered → Activated/Deactivated(焦點切換) → Closing(可取消) → Closed → Unloaded。
實測事件觸發順序:
SourceInitialized Loaded ContentRendered Activated ... 用戶操作 ... Closing (可 e.Cancel = true) Closed Unloaded
WPF 採單一 UI 線程模型,所有 DispatcherObject 衍生類別(含 UI 元素、Application)具有線程親和性。非 UI 線程存取需透過 Dispatcher.Invoke(同步)或 BeginInvoke(非同步)封送:
// 錯誤:非 UI 線程直接存取
new Thread(() => lbl.Content = "Hi").Start(); // 拋 InvalidOperationException
// 正確:封送至 UI 線程
Application.Current.Dispatcher.BeginInvoke(() => lbl.Content = "Hi");
DispatcherPriority 控制優先順序,Normal 適用大多數場景。
Object
└ DispatcherObject (線程親和性)
└ DependencyObject (依賴屬性系統)
└ Visual (渲染、座標轉換、命中測試)
└ UIElement (核心輸入/佈局/事件)
└ FrameworkElement (框架層:樣式、資料綁定、資源、動畫)
├ Control (ControlTemplate 外觀)
│ ├ ContentControl (單一內容)
│ ├ ItemsControl (項目集合)
│ └ ...
├ Panel (佈局容器)
├ Decorator (單一子元素裝飾)
└ Shape (幾何圖形)
遍歷輔助類:LogicalTreeHelper、VisualTreeHelper。視覺樹需在 OnContentRendered 後才完整形成。
純代碼 WPF 程式可直接用 csc.exe 參考三大組件編譯:
csc /out:Hello.exe Hello.cs ^
/r:"C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\PresentationFramework.dll" ^
/r:"C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\WindowsBase.dll" ^
/r:"C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\PresentationCore.dll"
反編譯 IL 可見 Main、Application.Run、Window.Show 呼叫鏈,驗證啟動流程。
Parse(string):字串載入Load(Stream):流載入(支援異步 LoadAsync、CancelAsync、LoadCompleted 事件)x:Class、x:Code、事件綁定var xaml = @" ";
var win = (Window)XamlReader.Parse(xaml);
win.ShowDialog();
Save(object) 將運行時物件樹序列化為 XAML 字串(受限序列化,不保證往返無損)。適用於動態換膚、UI 持久化、設計時預覽。
利用 MSBuild Engine 將 XAML 編譯為 BAML,再用反射呼叫內部 XamlReader.LoadBaml 載入:
public static class BamlWriter {
public static void Save(object obj, Stream stream) { /* MSBuild 編譯 XAML→BAML 寫入流 */ }
}
public static class BamlReader {
public static object Load(Stream stream) { /* 反射呼叫 LoadBaml */ }
}
此技術可實現運行時 BAML 熱更新、插件系統 UI 動態載入等高階場景。
掌握 Application/Window 生命週期、Dispatcher 線程模型、邏輯/視覺樹差異、XAML 編譯管線與動態載入技術,能讓你在架構設計、效能調優、插件擴展、異常診斷等高階場景遊刃有餘。下一站:深入 WPF 佈局系統與渲染管線。