原文: WPF異常捕獲,并使程式不崩潰!
在.NET中,我們使用try-catch-finally來處理異常。但,當一個Exception抛出,抛出Exception的代碼又沒有被try包圍時,程式就崩潰了。
這些異常往往是你沒有注意到的。在WPF中,提供了一種處理這些個異常的方式。
舉例來說明。
1.先抛出個異常,不用try包圍它。
在MainWindow上添加一個如下的Button。
<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事件中抛出個異常
private void OnClick(object sender, RoutedEventArgs e)
{
throw new InvalidOperationException("Something has gone wrong.");
}
如果,我們Ctrl+F5運作這個程式,點選按鈕,程式就崩潰了。
WPF如何解決這個問題呢?
2.WPF處理這種異常的方法
在App.xaml.cs中訂閱DispatcherUnhandledException事件,并添加相應的事件處理。
App.xaml.cs如下:
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運作程式。
這樣,異常就被捕獲并處理了,程式沒有崩潰。
所有 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.");
}
}