WPF异常处理详解

总目录



一、WPF异常

1 未捕获异常

正常情况下,开发过程中都会使用try…catch在可能会出现异常的地方去捕获和处理异常。然而实际上开发过程中,由于开发疏忽和一些未知原因,程序中会存在未被处理的异常,当程序运行到此,可能会导致程序崩溃的情况,这样会大大的降低用户的使用体验。对于这种未发现未处理的异常,称之为未捕获异常(UnhandledException)。

2 模拟未捕获异常场景

下面的案例中,就是模拟一个未捕获的异常场景,点击按钮,抛出异常,不使用try…catch 捕获处理。

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            throw new Exception("一个异常!");
        }

在这里插入图片描述
这种由于未捕获异常导致的程序崩溃,从而影响使用者的正常操作,交互上很不友好。此类异常如果需要追溯就必须去查看Windows的事件日志,导致查找问题也比较麻烦。
在这里插入图片描述

二、处理未捕获异常

我们虽然不能完全杜绝未捕获异常的产生,但是当其出现的时候,我们应当予以处理,做到尽量不影响使用者的操作。

在WPF应用程序中,各类未处理异常及其处理方式如下:

异常种类处理方式案例说明
UI线程抛的异常使用Application.Current.DispatcherUnhandledException 事件处理例如点击了用户界面上面的某个控件,然后执行某行代码的时候,遇到了异常;
非UI线程抛的异常使用AppDomain.CurrentDomain.UnhandledException事件处理例如在一个多线程的程序里面,工作线程的代码遇到了异常。
Task线程抛的异常使用TaskScheduler.UnobservedTaskException事件处理例如在一个多线程的程序里面,工作线程的代码遇到了异常。

1 DispatcherUnhandledException 异常捕获

  • DispatcherUnhandledException 用于捕获UI线程的异常,对于多线程Thread 和Task 异常不会捕获。
  • 该事件中可以通过设置 e.Handle=true ,表明该异常已被处理,不会造成程序崩溃和退出

具体验证代码如下:
在这里插入图片描述
上面测试结果:

  • UI线程异常【可以捕获】,通过e.Handle处理,应用程序不会发生崩溃或退出情况
  • Thread多线程异常【无法捕获】,会造成应用程序崩溃或退出
  • Task多线程异常【无法捕获】,但不会造成程序崩溃或退出

2 UnhandledException异常捕获

  • UnhandledException 用于捕获应用程序所有的异常
  • 该事件只管捕获,没有什么e.Handle的设置去处理异常
  • 若想应用程序捕获到异常后不退出或崩溃需要配合legacyUnhandledExceptionPolicy 配置设置实现(作用类似于e.Handle=true)

如何配置legacyUnhandledExceptionPolicy 呢?只需要在 app.config 文件的 <runtime> 节点中添加如下代码:

<legacyUnhandledExceptionPolicy enabled="1"/>  

具体使用案例如下所示:
在这里插入图片描述
上面测试结果:

  • UI线程异常【可以捕获】,但是应用程序仍会发生崩溃或退出情况
  • Thread多线程异常【可以捕获】,应用程序不会崩溃或退出
  • Task多线程异常【无法捕获】,也不会造成程序崩溃或退出

3 UnobservedTaskException异常捕获

  • UnobservedTaskException 专用于捕获Task 多线程异常

在这里插入图片描述
上面测试结果:

  • UI线程异常【无法捕获】,应用程序发生崩溃或退出
  • Thread多线程异常【无法捕获】,应用程序会崩溃或退出
  • Task多线程异常【可以捕获】,应用程序不会崩溃或退出

UnobservedTaskException 事件执行的时机?

通过上面的案例中,我们发现在Task中发生异常了以后,并不会马上执行UnobservedTaskException 事件内的代码,而是会等一会儿才执行? 这是因为Task异常只有在垃圾回收的时候,才会推送到该事件内进行处理。

4 异常捕获的综合使用

如果我们在项目将三类异常的捕获事件,全部定义出来,即可捕获所有的异常事件。

  • 在xaml中
    <StackPanel>
        <Button Content="测试UI线程异常" Width="300" Height="50" Click="Button_Click" Margin="10"></Button>
        <Button Content="测试Thread线程异常" Width="300" Height="50" Click="Button_Click_1" Margin="10"></Button>
        <Button Content="测试Task线程异常" Width="300" Height="50" Click="Button_Click_2" Margin="10"></Button>
    </StackPanel>
  • 在代码中
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            throw new Exception("UI线程异常[01]!");
        }

        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            new Thread(new ThreadStart(()=> 
            {
                throw new Exception("Thread多线程异常[02]");
            })).Start();
        }

        private void Button_Click_2(object sender, RoutedEventArgs e)
        {
            Task.Run(()=> 
            {
                throw new Exception("Task多线程异常[03]");                
            });
        }
  • 在App.xaml.cs的代码中
    public partial class App : Application
    {
        public App()
        {
            //当应用程序引发但未处理异常时出现,UI线程的异常,无法捕获多线程异常
            Application.Current.DispatcherUnhandledException += Current_DispatcherUnhandledException;
            
            //当某个异常未被捕获时出现
            AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;

            //未被观察到的Task多线程异常
            TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
        }

        private void Current_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
        {
            e.Handled = true;
            MessageBox.Show($"Current_DispatcherUnhandledException:" + e.Exception.Message);
        }
        private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            MessageBox.Show($"CurrentDomain_UnhandledException:" + (e.ExceptionObject as Exception).Message);
        }
        private void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
        {
            MessageBox.Show($"TaskScheduler_UnobservedTaskException:" + e.Exception.Message);
        }
    }

结语

以上就是本文的内容,希望以上内容可以帮助到您,如文中有不对之处,还请批评指正。


参考资料:
WPF异常处理
TaskScheduler.UnobservedTaskException 事件

  • 0
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值