在WPF開發過程中我們一般都用try/catch塊來捕獲異常,但不是每個異常我們都能捕獲,程序總會出現一些意想不到情況,拋出一些未捕獲的異常,這時就要用到全局異常捕獲,即在程序的最外層加上捕獲未處理異常,以免程序奔潰,影響用戶體驗。
在WPF應用程序中,會有兩大類未處理異常:一類是在UI線程拋出來的,例如點擊了用戶界面上面的某個控件,然後執行某個代碼的時候,遇到了異常;另一類是非UI線程跑出來的,例如在一個多線程的程序裏面,工作線程的代碼遇到了異常。
對於UI線程的未處理異常,我們用Application.DispatcherUnhandledException事件來處理,對於非UI線程的未處理異常用AppDomain.UnhandledException事件來處理,對於Task內未處理異常用TaskScheduler.UnobservedTaskException事件來處理;
下面看代碼:
public App()
{
//首先註冊開始和退出事件
this.Startup += new StartupEventHandler(App_Startup);
this.Exit += new ExitEventHandler(App_Exit);
}
啓動事件對應的方法:
void App_Startup(object sender, StartupEventArgs e)
{
//UI線程未捕獲異常處理事件
this.DispatcherUnhandledException += new DispatcherUnhandledExceptionEventHandler(App_DispatcherUnhandledException);
//Task線程內未捕獲異常處理事件
TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
//非UI線程未捕獲異常處理事件
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler( CurrentDomain_UnhandledException);
}
退出事件對應的方法:
void App_Exit(object sender, ExitEventArgs e)
{
//程序退出時需要處理的業務
}
具體對應的方法:
void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
try
{
e.Handled = true; //把 Handled 屬性設爲true,表示此異常已處理,程序可以繼續運行,不會強制退出
MessageBox.Show("捕獲未處理異常:" + e.Exception.Message);
}
catch (Exception ex)
{
//此時程序出現嚴重異常,將強制結束退出
MessageBox.Show("程序發生致命錯誤,將終止,請聯繫運營商!");
}
}
void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
StringBuilder sbEx = new StringBuilder();
if (e.IsTerminating)
{
sbEx.Append("程序發生致命錯誤,將終止,請聯繫運營商!\n");
}
sbEx.Append("捕獲未處理異常:");
if (e.ExceptionObject is Exception)
{
sbEx.Append(((Exception)e.ExceptionObject).Message);
}
else
{
sbEx.Append(e.ExceptionObject);
}
MessageBox.Show(sbEx.ToString());
}
void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
{
//task線程內未處理捕獲
MessageBox.Show("捕獲線程內未處理異常:" + args.Exception.Message);
args.SetObserved();//設置該異常已察覺(這樣處理後就不會引起程序崩潰)
}