WPF整理-處理沒有注意到的異常

在.NET中,咱們使用try-catch-finally來處理異常。但,當一個Exception拋出,拋出Exception的代碼又沒有被try包圍時,程序就崩潰了。html

這些異常每每是你沒有注意到的。在WPF中,提供了一種處理這些個異常的方式。async

舉例來講明。ide

1.先拋出個異常,不用try包圍它。

在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

2.WPF處理這種異常的方法

在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

WPF程序的異常捕獲總結

相關文章
相關標籤/搜索