在.NET中,咱們使用try-catch-finally來處理異常。但,當一個Exception拋出,拋出Exception的代碼又沒有被try包圍時,程序就崩潰了。html
這些異常每每是你沒有注意到的。在WPF中,提供了一種處理這些個異常的方式。async
舉例來講明。ide
在MainWindow上添加一個以下的Button。post
<Window x:Class="HandlingAnUnhandledException.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"> <StackPanel> <Button Click="OnClick"> <Button.Template> <ControlTemplate> <Grid> <Ellipse Height="100" Width="250" Fill="Pink"/> <TextBlock Text="Button to Throw Exception by DebugLZQ" VerticalAlignment="Center" HorizontalAlignment="Center"/> </Grid> </ControlTemplate> </Button.Template> </Button> </StackPanel> </Window>
在Button的Click事件中拋出個異常url
private void OnClick(object sender, RoutedEventArgs e) { throw new InvalidOperationException("Something has gone wrong."); }
若是,咱們Ctrl+F5運行這個程序,點擊按鈕,程序就崩潰了。
WPF如何解決這個問題呢?spa
在App.xaml.cs中訂閱DispatcherUnhandledException事件,並添加相應的事件處理。線程
App.xaml.cs以下:code
public partial class App : Application { public App() { DispatcherUnhandledException += App_DispatcherUnhandledException; } void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) { MessageBox.Show("Error encountered! Please contact support."+ Environment.NewLine + e.Exception.Message); //Shutdown(1); e.Handled = true; } }
這時,當咱們Ctrl+F5運行程序。orm
這樣,異常就被捕獲並處理了,程序沒有崩潰。 xml
Update:剛百度了一下:WinForm也有相似的機制,請參考Kevin Gao的這篇博文:C# winform 捕獲全局異常.
Update:
全部 WPF 應用程序啓動時都會加載兩個重要的線程:一個用於呈現用戶界面,另外一個用於管理用戶界面。呈現線程是一個在後臺運行的隱藏線程,所以咱們一般面對的惟一線程就是 UI 線程。
這種方法只能捕捉UI線程的異常,及使用了Dispatcher進行線程關聯了的線程(其實Dispatcher.Invoke/BeginInvoke就是將要執行的代碼,扔到UI線程去執行)的異常。不能捕捉普通的子線程異常。
如:
private void OnClick(object sender, RoutedEventArgs e) { Dispatcher.BeginInvoke(new Action(() => { throw new InvalidOperationException("Something has gone wrong."); })); }
也能夠正常捕獲。
而:
private void OnClick(object sender, RoutedEventArgs e) { Thread t = new Thread(() => { throw new InvalidOperationException("Something has gone wrong."); }); t.IsBackground = true; t.Start(); }
則不能捕獲。
感謝veboys博友的指點~
------------------------------------------
一樣的,即便咱們用一個try-catch包圍以下的異常,異常也不會被Handle:
try { var thread = new Thread(() => {throw new Exception(); }); thread.Start(); } catch (Exception) { MessageBox.Show("Will not execute!"); throw; }
try { Task.Run(() =>{throw new Exception(); }); } catch (Exception) { MessageBox.Show("Will not execute!"); }
--------------
對應Async await 異常:
private async void ButtonBase_OnClick(object sender, RoutedEventArgs e) { try { await Task.Run(() => { throw new Exception(); }); } catch (Exception) { MessageBox.Show("Will execute!"); } }
處理Unhandled exception異常 以下:TaskScheduler.UnobservedTaskException
public partial class App : Application { protected override void OnStartup(StartupEventArgs e) { RegisterEvents(); base.OnStartup(e); } private void RegisterEvents() { TaskScheduler.UnobservedTaskException += (sender, args) => { MessageBox.Show(args.Exception.Message); args.SetObserved(); }; AppDomain.CurrentDomain.UnhandledException += (sender, args) => MessageBox.Show("Unhandled exception."); } }
Update: