WPF UnhandledException
在 WPF 程序中,通常可以通过 Application.DispatcherUnhandledException
或 AppDomain.UnhandledException
事件来处理全局 未处理异常
,其中前者是由 WPF 框架提供的,后者是由 .NET Framework 提供的,后者能够捕获更多的未处理异常。对于 Task
中的未处理异常,这两种事件都不会触发,仅能通过 TaskScheduler.UnobservedTaskException
事件来捕获。另外,还有个 AppDomain.FirstChanceException
事件,每个异常都会引发该事件,即使该异常已被 try...catch
处理,此事件不在本文的讨论范围内。
- Application.DispatcherUnhandledException 事件
- 能够捕获 UI 线程抛出的未处理异常
- 可通过事件参数
e.Handled = true
来阻止程序崩溃
- AppDomain.UnhandledException 事件
- 能捕获
所有线程(Task 除外)
抛出的未处理异常 - 默认情况无法阻止程序崩溃(可通过
legacyUnhandledExceptionPolicy
配置异常策略 )
- 能捕获
- TaskScheduler.UnobservedTaskException
- 仅能捕获
Task
中抛出的未处理异常 - 事件的触发有延时,依赖垃圾回收
- 仅能捕获
注册异常事件
protected override void OnStartup(StartupEventArgs e)
{AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;Application.Current.DispatcherUnhandledException += Current_DispatcherUnhandledException;base.OnStartup(e);
}private void Current_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{MessageBox.Show($"Current_DispatcherUnhandledException:{e.Exception}");e.Handled = true; // 标记为 “已处理”,避免异常进一步传递而引起崩溃
}private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{MessageBox.Show($"CurrentDomain_UnhandledException: {e.ExceptionObject}");
}
UI 线程异常
private void Button_Click(object sender, RoutedEventArgs e)
{throw new InvalidOperationException();
}
对于一个 UI 线程抛出的未处理异常,其会先触发 DispatcherUnhandledException
事件,如果该事件处理方法中未标记 e.Handled
为 true
,则会进一步触发 UnhandledException
事件。
Thread 异常
private void Button_Click(object sender, RoutedEventArgs e)
{Thread thread = new Thread(() => { throw new InvalidOperationException(); });thread.Start();// ThreadPool.QueueUserWorkItem(state => { throw new InvalidOperationException(); });
}
此类未捕获异常仅会触发 UnhandledException 事件,并且事件参数中并未提供类似 e.Handled
的方法来阻止程序崩溃,通常仅在该事件处理方法中添加日志记录或用户提示。在 .NET 2.0
及以前的版本,此类未处理异常是不会引起程序崩溃的,我们也可以通过配置来开启旧的异常处理策略,在 App.Config 中添加如下配置:
<configuration><runtime><legacyUnhandledExceptionPolicy enabled="1"/></runtime>
</configuration>
Task 异常
private void Button_Click(object sender, RoutedEventArgs e)
{var task = new Task(() =>{throw new InvalidOperationException();});task.Start();// Task.Run(() => throw new InvalidOperationException());// Task.Factory.StartNew(() => throw new InvalidOperationException());// var worker = new BackgroundWorker();// worker.DoWork += (s, ex) => { throw new InvalidOperationException(); };// worker.RunWorkerAsync();
}
如上的代码不会触发 UnhandledException
事件,也不会引起程序奔溃。如果想从全局捕获此类未处理异常,可注册 TaskScheduler.UnobservedTaskException
事件。
protected override void OnStartup(StartupEventArgs e)
{TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;base.OnStartup(e);
}private void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
{MessageBox.Show($"TaskScheduler_UnobservedTaskException: {e.Exception}");e.SetObserved(); // 标识异常已被观察,不会传给系统,避免崩溃
}
此事件并非在抛出异常后立即触发,其依赖于垃圾回收,在某次垃圾收集过程,从 Finalizer 线程里触发并执行。可通过如下方式来强制垃圾回收,及时触发事件(实际工程中避免这些操作,会有性能问题)。
private void Button_Click(object sender, RoutedEventArgs e)
{var task = Task.Run(() => throw new NotImplementedException());((IAsyncResult)task).AsyncWaitHandle.WaitOne();task = null;GC.Collect();GC.WaitForPendingFinalizers();GC.Collect();
}
另外,还可将 Task 中的异常转到调度线程中,从而引发 UnhandledException 事件,Task.Result、Task.Wait() 等都可实现此效果。
private void Button_Click(object sender, RoutedEventArgs e)
{var task = Task.Run(() => throw new NotImplementedException());task.Wait();
}
顽固的异常
在 托管代码
中调用 非托管
接口,部分未处理异常是无法接住的,会直接引起程序崩溃。如下所示,C++
中实现了 Add(int x, int y)
方法,在 C#
中调用之,前面的未处理异常事件均不会触发,程序会直接崩溃。
extern "C" _declspec(dllexport) int Add(int x, int y)
{char *p = nullptr;*p = '1'; // 此处会抛异常 return x + y;
}
[DllImport("MyDll")]
public static extern int Add(int x, int y);private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{Add(1, 2);
}
结合前面 Task
内部异常的特性,可以将调用代码放在 Task
中,以避免程序崩溃。Task
是个神奇的东西,还需要进一步深入学习。
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{Task.Run(() => Add(1, 2));
}
原文地址:https://blog.csdn.net/Iron_Ye/article/details/82913025
WPF UnhandledException相关推荐
- WPF整理-处理没有注意到的异常
在.NET中,我们使用try-catch-finally来处理异常.但,当一个Exception抛出,抛出Exception的代码又没有被try包围时,程序就崩溃了. 这些异常往往是你没有注意到的.在 ...
- 06Prism WPF 入门实战 - Log控件库
1.概要 源码及PPT地址:https://github.com/JusterZhu/wemail 视频地址:https://www.bilibili.com/video/BV1KQ4y1C7tg?s ...
- 关于未捕获异常的处理(WPF)
转载自:http://www.cnblogs.com/chenxizhang/p/3280947.html 这一篇文章来谈谈对于WPF应用程序开发中的未捕获异常的处理. 首先,我们当然是要求应用程序开 ...
- WPF捕获未处理的异常
WPF程序中,对于异常的捕获一般使用try/catch块.就像程序中的bug一样,很难保证程序中所有的异常都能够通过try/catch捕获.如果异常没有被捕获,轻则影响用户体验,严重时会导致数据丢失 ...
- WPF 不要给 Window 类设置变换矩阵(分析篇):System.InvalidOperationException: 转换不可逆。
最近总是收到一个异常 "System.InvalidOperationException: 转换不可逆.",然而看其堆栈,一点点自己写的代码都没有.到底哪里除了问题呢? 虽然异常堆 ...
- 基于 WPF + Modern UI 的 公司OA小助手 开发总结
前言: 距离上一篇博客,整整一个月的时间了.人不能懒下来,必须有个阶段性的总结,算是对我这个阶段的一个反思.人只有在总结的过程中才会发现自己的不足. 公司每天都要在OA系统上上班点击签到,下班点击签退 ...
- 学习Modern UI for WPF
这两天断断续续的学了学Modern UI for WPF 没啥学习笔记呵呵,来自大牛王春明的博客园 http://www.cnblogs.com/wangchunming/category/34288 ...
- [转][小结][三种方法]实现WPF不规则窗体
实现WPF不规则窗体的三种常用的方法如下: 1.使用Blend等工具绘制一个不规则xaml,然后作为窗体的背景.这个可以参考xiaowei0705的这篇博文:WPF制作不规则的窗体 . 2.给wind ...
- WPF:跨应用程序会话保持和还原应用程序范围的属性
所谓的wpf夸应用程序员会话保持和还原.其实就是将多个应用程序都用的资源保存到一个独立的文件存储系统中.这个应用程序退出的时候将数据写入文件中,其他应用程序使用的时候可以去读取这个文件 这个地方用到了 ...
最新文章
- 2018 前端面试题(不定期更新)
- 桥接模式coding
- 弹出对话框拖拽JavaScript实现
- php与mysql手册下载地址_PHP与Mysql的连接
- MQTT(3)---MQTT协议及其在物联网中的应用
- mysql设计学习_Mysql数据库设计学习
- c语言万年历程序设计方案,万年历程序设计c语言代码
- linux gettimeofday()函数
- 量子计算机 时间倒流,科学家首次利用量子计算机成功逆转时间,时间倒流将变成可能?...
- 饥荒服务器运行时cpu的占用,饥荒联机版服务器卡顿原因分析及解决教程_饥荒联机版服务器卡顿怎么解决_游戏堡...
- SPSS分析数据学习笔记
- 蚂蚁金服java年终奖,蚂蚁金服发布年终奖调查结果 超六成人无缘年终奖
- php 路由修改密码,TPLINK路由器如何修改管理密码和无线密码)
- 网站调用百度地图展示位置,调用百度开放平台api 动态静态调用
- java实现支付宝app支付
- Qzone 超级补丁热修复方案原理
- prusai3打印机使用教程_打印虎原创RepRapPrusai33D打印机校准图解教程系列之二.pdf...
- 解决Chrome自带翻译功能无法使用问题
- 洛谷P1244青蛙过河
- 为什么onenote一直在加载_超好用的笔记软件,Onenote是我的最爱