轉載自:http://www.cnblogs.com/chenxizhang/p/3280947.html
這一篇文章來談談對於WPF應用程序開發中的未捕獲異常的處理。
首先,我們當然是要求應用程序開發人員,儘可能地在程序可能出現異常的地方都去捕捉異常,使用try…catch的方式。但是總是有一些意外的情況可能會發生,這就導致會出現所謂的“未捕獲異常(UnhandledException)”。對於這一類異常,如果我們沒有一個合適的策略進行處理,則當其發生的時候,會給用戶帶來不太好的使用體驗。例如下面這樣
備註:這個截圖是在Windows 8上面做的,其他操作系統看到的界面可能略有不同。
用戶看到這個窗口的時候,其實一般只能點擊Close the prograrm按鈕。也就是說,這種情況下會導致用戶無法繼續使用這個程序,而且他們還得不到任何具體的消息:到底發生了什麼事情了?除非他們去查看Windows的事件日誌。(但一般的用戶是不太會這個操作的)
我們可以看到在Windows事件日誌中,會有兩個具體的事件。首先是一個.NET Runtime的事件
然後是一個Application Error的事件
通常來說,這樣的用戶體驗有值得改進的地方。我們雖然不能防止異常的產生,但是當意外發生的時候,我們應該要以更好地方式地通知到用戶,或者儘可能地不要影響用戶當前的操作。
在WPF這種應用程序中,會有兩大類未處理異常:一類是在UI線程拋出來的,例如點擊了用戶界面上面的某個控件,然後執行某個代碼的時候,遇到了異常;另一類是非UI線程跑出來的,例如在一個多線程的程序裏面,工作線程的代碼遇到了異常。
對於UI線程的未處理異常,我們可以通過監控下面這個事件來處理
Application.Current.DispatcherUnhandledException http://msdn.microsoft.com/en-us/library/system.windows.application.dispatcherunhandledexception.aspx
一個參考代碼如下:
using System;
using System.Windows;
namespace WpfApplicationExceptionSample
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
public App()
{
Application.Current.DispatcherUnhandledException += Current_DispatcherUnhandledException;
}
void Current_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
MessageBox.Show("我們很抱歉,當前應用程序遇到一些問題,該操作已經終止,請進行重試,如果問題繼續存在,請聯繫管理員.", "意外的操作", MessageBoxButton.OK, MessageBoxImage.Information);//這裏通常需要給用戶一些較爲友好的提示,並且後續可能的操作
e.Handled = true;//使用這一行代碼告訴運行時,該異常被處理了,不再作爲UnhandledException拋出了。
}
}
}
運行的效果大致如下
對於非UI線程拋出的未處理異常,我們需要監控另外一個事件來處理
AppDomain.CurrentDomain.UnhandledException http://msdn.microsoft.com/en-us/library/system.appdomain.unhandledexception.aspx
一個參考代碼如下
using System;
using System.Windows;
namespace WpfApplicationExceptionSample
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
public App()
{
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
}
void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
MessageBox.Show("我們很抱歉,當前應用程序遇到一些問題,該操作已經終止,請進行重試,如果問題繼續存在,請聯繫管理員.", "意外的操作", MessageBoxButton.OK, MessageBoxImage.Information);
}
}
}
令人不解的是,這個事件中沒有和前面那個事件一樣的e.Handled參數,就是說,雖然這樣是可以捕捉到非UI線程的異常,而且也可以進行相應的處理,但是應用程序還是會退出,也就是說這個異常還是被當作是未處理異常繼續彙報給Runtime。
爲了改進這一點,我們可以通過修改配置文件來實現。
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<runtime>
<legacyUnhandledExceptionPolicy enabled="1"/>
</runtime>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>
這裏的legacyUnhandledExceptionPolicy,如果enabled=1的話,用意是使用早期版本的異常處理策略。