在给客户演示软件功能时,你精心编写的 WinForms 桌面应用程序运行得好好的,突然抛出一个未捕获的异常,用户面前弹出一个吓人的错误窗口,然后就莫名其妙地关闭了,毫无预警。
这不仅让用户感到困惑,也让作为开发者的你感到无比尴尬。为了防止这种情况的发生,我们需要在 WinForms 中设置一个全局的异常处理机制。
今天,我们来看看如何为你的 WinForms 桌面应用程序穿上一件“防护服”,让它能够优雅地处理这些未捕获的异常,提升程序的稳定性和用户体验。
1. 创建一个新的 WinForms 项目,命名为“ExceptionHandlerDemo”
2. 添加一个简单的用户界面
- 在设计视图中,拖一个 Button 控件到默认的 Form1 窗体上。
- 将按钮的 Text 属性设置为“抛出异常”。
3. 添加引发异常的代码
在按钮的 Click 事件中,我们故意抛出一个异常。
private?void?button1_Click(object?sender, EventArgs e)
{
? ??throw?new?InvalidOperationException("这是一个测试异常!");
}
4. 订阅全局异常事件
设置全局异常处理机制来获未处理的异常,可以通过订阅 Application.ThreadException 和 AppDomain.CurrentDomain.UnhandledException 事件来实现。
这就像告诉应用程序:“嘿,如果你遇到任何未捕获的异常,请不要慌,我会帮你处理的。”
在 Program.cs 文件中编写以下代码:
internal?static?class?Program
{
? ??///?
? ??///? 应用程序入口
? ??///?
? ? [STAThread]
? ??static?void?Main()
? ? {
? ? ? ? ApplicationConfiguration.Initialize();
? ? ? ??// 订阅 ThreadException 事件,用于捕获 UI 线程上的未捕获异常
? ? ? ? Application.ThreadException +=?new?ThreadExceptionEventHandler(Application_ThreadException);
? ? ? ??// 设置未经处理的异常模式,以便在非 UI 线程上也能捕获异常
? ? ? ? Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
? ? ? ??// 订阅 UnhandledException 事件,用于捕获所有线程上的未捕获异常
? ? ? ? AppDomain.CurrentDomain.UnhandledException +=?new?UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
? ? ? ? Application.Run(new?Form1());
? ? }
? ??// 处理 UI 线程上的未捕获异常
? ??private?static?void?Application_ThreadException(object?sender, ThreadExceptionEventArgs e)
? ? {
? ? ? ? HandleException(e.Exception);
? ? }
? ??// 处理所有线程上的未捕获异常
? ??private?static?void?CurrentDomain_UnhandledException(object?sender, UnhandledExceptionEventArgs e)
? ? {
? ? ? ? HandleException(e.ExceptionObject?as?Exception);
? ? }
? ??// 统一的异常处理方法
? ??private?static?void?HandleException(Exception ex)
? ? {
? ? ? ??if?(ex ==?null)?return;
? ? ? ??// 记录错误日志
? ? ? ??// 显示友好的错误信息给用户
? ? ? ? MessageBox.Show(@$"
对不起,应用程序遇到了一个问题,错误信息如下:
{ex.Message}
我们已经记录了这个问题,稍后会进行修复。",
? ? ? ? ? ? ? ? ? ? ? ??"应用程序错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
? ? ? ??// (可选)退出应用程序或采取其他措施
? ? ? ? Application.Exit();
? ? }
}
5. 测试代码
按 Ctrl+F5 编译并运行程序,然后点击按钮引发异常,你应该会看到一个友好的错误提示框,显示捕获到的异常信息,如下图:
总结
想象一下,你正在开车,突然遇到了一个坑洼,如果你事先知道这一点,提前减速或绕道行驶,是不是会更安全、更舒适?
同样,在编程中,如果我们能提前为应用程序设置好应对策略,就可以更好地保护它免受意外的伤害。
通过在 WinForms 应用程序中设置全局异常处理器,我们就可以捕获并优雅地处理所有未被捕获的异常,无论是 UI 线程还是其他线程的异常,避免那些令人头疼的崩溃,提升用户体验。