WPF异常处理详解

2023-05-16

总目录


文章目录

  • 总目录
  • 一、WPF异常
    • 1 未捕获异常
    • 2 模拟未捕获异常场景
  • 二、处理未捕获异常
    • 1 DispatcherUnhandledException 异常捕获
    • 2 UnhandledException异常捕获
    • 3 UnobservedTaskException异常捕获
    • 4 异常捕获的综合使用
  • 结语


一、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 事件

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

WPF异常处理详解 的相关文章

  • Windows Server 出现多个匿名登陆用户的问题解决

    1 起因 工作中需要在同一台 windows server的机器上多个用户同时使用 xff0c 遂建立多个账号 xff0c 供大家进行使用 2 问题 一段时间后发现系统特别卡顿并会死机 xff0c 查询原因后发现 xff0c 如图所示 xf
  • java锁 synchronized的使用及原理剖析

    synchronized用法有三个 修饰实例方法 修饰静态方法 修饰代码块 1 修饰实例方法 synchronized关键词作用在方法的前面 xff0c 用来锁定方法 xff0c 其实默认锁定的是this对象 public class Th
  • 面试HashMap的原理

    一般来说 xff0c java面试必不可少的菜品 xff0c 那就是 来 xff0c 讲一下HashMap的原理 那么今天就来讲一下HashMap的原理 先说一下JDK1 7跟JDK1 8对它的改变 JDK1 7之前使用的是数组加链表 xf
  • JAVA开发环境配置

    1 自己在网上下载JDK xff0c 本教程使用JDK1 6 下载好JDK后双击运行 xff0c 然后根据提示进行安装 安装好JDK后 bin xff1a 存放java可执行文件 如 xff1a javac exe java exe等等 d
  • MyEcplise_Maven搭建SSM框架

    Maven源码 链接 xff1a https pan baidu com s 1eTQMJQy 密码 xff1a 8j1q 博文中的MyEcplise 链接 xff1a https pan baidu com s 1dEdQYa 密码 xf
  • 怎么使用Linux常用命令大全

    系统信息 arch 显示机器的处理器架构 1 uname m 显示机器的处理器架构 2 uname r 显示正在使用的内核版本 dmidecode q 显示硬件系统部件 SMBIOS DMI hdparm i dev hda 罗列一个磁盘的
  • MySQL常用语句详解

    Winfrom连接网页 第一种方法 xff1a 调用本地浏览器System Diagnostics Process Start 34 https www microsoft com zh cn 34 第二种方法 xff1a 连接 strin
  • Maven搭建SSH连接Oracle数据库

    Maven工程搭建SSH连接Oracle数据库 首先在pom xml里引入jar lt project xmlns 61 34 http maven apache org POM 4 0 0 34 xmlns xsi 61 34 http
  • MyBatis简介与运用

    1 Mybatis简介 1 1 Mybatis是什么 Mybatis是一个java的持久层框架 xff0c 保存到数据库 持久化 xff1a 保存到本地文件 1 2 Mybatis的作用 操作数据库 1 3 为什么要学习mybatis 1
  • SpringMVC入门原理

    1 Springmvc原理 1 1 什么是springmvc SpringMVC是一个Spring框架内置的对MVC模式的实现 xff0c 就spring的一个子模块 1 2 什么是mvc Model view controller 模型
  • MyBatis逆向工程建立实体

    下面是用MyEcplise开发工具 为例 使用Ecplise操作步骤雷同于MyEcplise 1 第一步 2 搜索MyBatis 等待装载完成 xff0c 完成后 3 创建一个web项目 创建包 xff0c 创建generatorConfi
  • python apscheculer 报错 skipped: maximum number of running instances reached (1)

    apscheduler定时任务报错skipped maximum number of running instances reached 1 原因是默认max instances最大定时任务是1个 xff0c 可以通过在add job中调m
  • java 反射很重要

    1 创建一个User类 public class User private String username private String password private String name public User public Use
  • Netty入门案例教程

    1 首先导入netty all 5 0 0 Alpha1 jar 2 创建一个NettyConfig 整个工程的全局配置 package websocketcom netty import io netty channel group Ch
  • 微信公众号分享的坑

    记一次微信公众号分享sdk 这里我的脚本是用jquery写的 xff0c 不带框架源码 首先创建jsp引入JavaScript微信分享js lt script type 61 34 text javascript 34 src 61 34
  • java linux部署web项目详解

    下载SecureCRT连接linux xff0c 激活SecureCRT跟怎么连接自行百度喽 xff0c 下面开始操作linux服务器 1 查看安装的jdk rpm qa grep java 2 如果有旧的jdk xff0c 就卸载jdk
  • 人工智能如何可以思考?

    近日在给同事讲人工智能的时候 xff0c 提到当数据量不够的时候 xff0c 必要时需要加入人工工程 xff0c 引导计算机 归纳 一些知识 xff0c 毕竟计算机智能比起人类智能 xff0c 最大的缺陷可能在于不懂得 举一反三 换句话说
  • 在Ubuntu 20.04上安装Google Chrome浏览器

    在Ubuntu上安装Google Chrome
  • OpenCV人脸识别之FisherFace算法(LDA线性判别分析)

    FisherFace算法 Fisherface是由Ronald Fisher发明的 xff0c Fisherface所基于的LDA xff08 Linear Discriminant Analysis xff0c 线性判别分析 xff09
  • Spring 源码-Spring的注解是如何解析的?(7)

    我们知道 ConfigurationClassPostProcessor实际上是BeanFactoryPostProcessor的一个实现类 xff0c 他特殊的地方是他还实现了BeanDefinitionRegisterPostProce

随机推荐