You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

WPF中如何捕获应用程序崩溃事件?附相关代码咨询

WPF应用崩溃事件捕获的正确实现方式

嘿,我来帮你把WPF里的崩溃捕获代码补全并优化一下~你已经找对了核心的两个捕获点,但还需要完善具体处理逻辑,另外别忘了异步任务里的未捕获异常也要覆盖到!下面是完整的可运行实现:

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);
        
        // 捕获UI线程上的未处理异常
        Dispatcher.UnhandledException += Dispatcher_UnhandledException;
        // 捕获非UI线程(后台线程)的未处理异常
        AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
        // 捕获未被await的异步任务抛出的异常(.NET 4.0+必备)
        TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
    }

    private void Dispatcher_UnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
    {
        // 统一处理异常:写日志、给用户友好提示
        HandleException(e.Exception, "UI线程未处理异常");
        
        // 设置为true,告诉WPF我们已经处理了这个异常,应用不会直接崩溃
        e.Handled = true;
    }

    private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
    {
        var exception = e.ExceptionObject as Exception;
        HandleException(exception, "应用域致命未处理异常");
        
        // 注意:这个事件触发的异常大多是致命的,处理完后应用还是会退出
        // 这里可以做最后的资源清理,比如关闭文件、释放连接等
    }

    private void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
    {
        // 处理那些没被await的异步任务抛出的异常
        HandleException(e.Exception, "未观察到的异步任务异常");
        
        // 标记异常已被处理,避免GC回收时触发应用崩溃
        e.SetObserved();
    }

    private void HandleException(Exception ex, string exceptionType)
    {
        if (ex == null) return;
        
        // 1. 记录详细错误日志,这里用本地文件示例,你可以换成NLog/Serilog等框架
        var logPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "WpfAppLogs", "CrashLogs.txt");
        Directory.CreateDirectory(Path.GetDirectoryName(logPath));
        
        var errorContent = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss} | {exceptionType}\n{ex.ToString()}\n----------------------------------------------------\n";
        File.AppendAllText(logPath, errorContent);
        
        // 2. 给用户弹出友好提示
        MessageBox.Show("抱歉,应用发生了意外错误,我们已经记录了相关信息,应用将退出。", "应用错误", MessageBoxButton.OK, MessageBoxImage.Error);
    }
}

关键知识点说明

  • Dispatcher.UnhandledException:专门管UI线程的异常,设置e.Handled = true可以阻止应用直接崩溃,给你机会处理完日志再优雅退出或者继续运行。
  • AppDomain.CurrentDomain.UnhandledException:负责捕获后台线程的未处理异常,这类异常一般是致命的,处理完日志后应用还是会退出,所以重点做最后的资源清理。
  • TaskScheduler.UnobservedTaskException:很多新手容易漏掉这个!如果你的异步任务没有用await,抛出的异常会在GC回收时触发这个事件,不处理的话会直接导致应用崩溃,设置e.SetObserved()就能解决这个问题。

额外注意事项

  • 日志路径别写死,用Environment.SpecialFolder里的目录更稳妥,避免权限问题。
  • 如果用了第三方日志框架,直接替换HandleException里的文件写入逻辑就行,更专业也更灵活。
  • 测试的时候可以故意在UI按钮点击事件里抛异常,或者在后台线程里throw new Exception("测试崩溃"),验证捕获逻辑是否生效。

内容的提问来源于stack exchange,提问作者Dim Mark

火山引擎 最新活动