首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

WPF 核心機制深度解析:Application 生命週期、XAML 編譯管線與動態載入技術

     編輯:關於.NET

理解 WPF 應用程式的啟動流程、Application/Window 生命週期、XAML 編譯為 BAML 的管線機制,以及 XamlReader/XamlWriter 動態載入技術,是進階 WPF 開發者的必修課。本文結合 IL 反編譯、命令列編譯實驗,揭開 WPF 執行時的底層面紗。

Application:應用程式的大管家

啟動模式三選一

  1. App.xaml 指定 StartupUri(VS 預設):編譯器自動生成 Main() 呼叫 Application.Run()。
  2. 自訂類別 + Main():手動建立 Application 實例,呼叫 Run(Window)、Run()(需先設 MainWindow + Show())、或 StartupUri。
  3. 純代碼啟動:無 XAML,完全手動控制。

關閉模式

  • OnLastWindowClose(預設):最後一個視窗關閉或呼叫 Shutdown() 結束。
  • OnMainWindowClose:主視窗關閉即結束。
  • OnExplicitShutdown:僅 Shutdown() 才結束,適合系統盤常駐程式。

關鍵事件

Startup、Exit、DispatcherUnhandledException(全域例外捕獲)、SessionEnding(系統登出/關機)。可在 App.xaml 綁定或代碼訂閱。

Window 生命週期完整圖譜

建構子 → SourceInitialized → Loaded → ContentRendered → Activated/Deactivated(焦點切換) → Closing(可取消) → Closed → Unloaded。

實測事件觸發順序:

SourceInitialized
Loaded
ContentRendered
Activated
... 用戶操作 ...
Closing (可 e.Cancel = true)
Closed
Unloaded

Dispatcher 與多線程 UI 存取

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 (幾何圖形)

邏輯樹與視覺樹

  • 邏輯樹:XAML 元素直接對應,反映內容結構(如 Window → StackPanel → Label → "Text")。支援資源查找、屬性繼承、事件路由。
  • 視覺樹:邏輯樹節點展開為渲染基元(如 Label → Border → ContentPresenter → TextBlock → TextRun)。支援命中測試、座標轉換、樣式模板實例化。

遍歷輔助類:LogicalTreeHelper、VisualTreeHelper。視覺樹需在 OnContentRendered 後才完整形成。

脫離 VS:命令列 CSC 編譯 WPF

純代碼 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 呼叫鏈,驗證啟動流程。

XAML 動態載入:XamlReader / XamlWriter

XamlReader - 運行時解析 XAML

  • Parse(string):字串載入
  • Load(Stream):流載入(支援異步 LoadAsync、CancelAsync、LoadCompleted 事件)
  • 限制:不可包含 x:Class、x:Code、事件綁定
var xaml = @""; 
var win = (Window)XamlReader.Parse(xaml);
win.ShowDialog();

XamlWriter - 物件序列化為 XAML

Save(object) 將運行時物件樹序列化為 XAML 字串(受限序列化,不保證往返無損)。適用於動態換膚、UI 持久化、設計時預覽。

進階:BAML 雙向轉換工具類

利用 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 佈局系統與渲染管線。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved