詳解WPF中的APP生命周期以及全局異常捕獲

APP生命周期

wpf項目目錄中有一個App.xaml.cs文件,該文件中App是一個partical類,與之對應的另一partical部分在App.g.i.cs文件中,該文件是在編譯的時候WPF自動生成的。程序的入口Main方法在該文件中定義。

[System.STAThreadAttribute()]
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "7.0.1.0")]
public static void Main() {
    WpfApp.App app = new WpfApp.App();
    app.InitializeComponent();//初始化Xaml
    app.Run();//程序運行
}

APP類繼承自Application,常見的生命周期事件有以下幾個:

  • Startup:在調用 Application 對象的 Run 方法時發生
  • Navigating:在應用程序中的導航器請求新導航時發生(針對Browser類型的應用)
  • LoadCompleted:在已經加載、分析並開始呈現應用程序中的導航器導航到的內容時發生
  • Navigated:在已經找到應用程序中的導航器要導航到的內容時發生,盡管此時該內容可能尚未完成加載
  • NavigationFailed:在應用程序中的導航器在導航到所請求內容時出現錯誤的情況下發生
  • NavigationProgress:在由應用程序中的導航器管理的下載過程中定期發生,以提供導航進度信息
  • NavigationStopped:在調用應用程序中的導航器的 StopLoading 方法時發生,或者當導航器在當前導航正在進行期間請求瞭一個新導航時發生
  • SessionEnding:在用戶通過註銷或關閉操作系統而結束 Windows 會話時發生
  • Activated:當應用程序成為前臺應用程序時發生,App任意一個窗口激活
  • Deactivated:當應用程序停止作為前臺應用程序時發生,App中所有窗口非激活
  • Exit:在應用程序關閉之前發生(無法像SessionEnding事件進行取消)

對於普通窗體程序,從開始到結束會依次調用如下事件

—–App_Startup
—–App_Navigating
—–App_Activated
—–App_Exit

窗體生命周期事件

在APP運行後,會啟動窗體,窗體常用的聲明周期事件如下:

  • SourceInitialized:操作系統給窗口分配句柄的時候觸發,註意WPF窗體裡面的控件是沒有句柄的
  • ContentRendered:窗體內容渲染後觸發
  • Loaded:窗體佈局加載完成即準備好交互後觸發
  • Activated:窗體激活
  • Deactivated:窗體失去焦點
  • Closing:調用關閉窗體時觸發,此時可以取消操作
  • Closed:窗體關閉後

全局異常捕獲

對於異常捕獲一般使用try-catch語句進行捕獲,但是對於全局的異常可以在App中進行捕獲。

  • DispatcherUnhandledException:在異常由應用程序引發但未進行處理時發生針對UI線程,無法捕獲多線程異常
  • AppDomain.CurrentDomain.UnhandledException:專門捕獲所有線程中的異常
  • TaskScheduler.UnobservedTaskException:專門捕獲Task異常

案例:

APP中進行全局異常捕獲

public partial class App : Application
{
    public App()
    {
        //在異常由應用程序引發但未進行處理時發生。UI線程
        //無法捕獲多線程異常
        this.DispatcherUnhandledException += App_DispatcherUnhandledException;
        //專門捕獲所有線程中的異常
        AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
        //專門捕獲Task異常
        TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
    }
    private void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
    {
        Debug.WriteLine("-----App_DispatcherUnhandledException--UI線程" + e.Exception.Message);
    }
    private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
    {
        Debug.WriteLine("-----CurrentDomain_UnhandledException--其他線程" + (e.ExceptionObject as Exception).Message);
    }
    private void TaskScheduler_UnobservedTaskException(object? sender, UnobservedTaskExceptionEventArgs e)
    {
        Debug.WriteLine("-----TaskScheduler_UnobservedTaskException--Task測試" + e.Exception.Message);
        e.SetObserved();
    }
}

窗體中拋異常

public partial class MainWindow : Window
{
    int i = 0;
    public MainWindow()
    {
        InitializeComponent();
        //1、ui線程異常測試
        _ = 1 / i;

        //2、其他線程異常測試
        new Thread(new ThreadStart(() => { _ = 1 / i; })).Start();

        //3、Task異常測試
        Task.Run(() =>
        {
            _ = 1 / i;
        });
    }   
}
異常 結果 說明
隻打開異常1 —–App_DispatcherUnhandledException–UI線程—–CurrentDomain_UnhandledException–其他線程 UI線程中的異常DispatcherUnhandledException和AppDomain.CurrentDomain.UnhandledException均能捕獲到
隻打開異常2 —–CurrentDomain_UnhandledException–其他線程 隻有AppDomain.CurrentDomain.UnhandledException可以捕獲
隻打開異常3 —–TaskScheduler_UnobservedTaskException–Task測試 隻有TaskScheduler.UnobservedTaskException可以捕獲到Task異常

備註:Task中的異常並不是立刻就能捕獲到的,而是等到垃圾回收的時候進行捕獲。如果想立刻進行捕獲則可以調用GC.Collect(0);GC.WaitForPendingFinalizers();

到此這篇關於詳解WPF中的APP生命周期以及全局異常捕獲的文章就介紹到這瞭,更多相關WPF生命周期 全局異常捕獲內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: