栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > .Net

WPF 全局异常捕获

.Net 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

WPF 全局异常捕获

在开发过程中我们一般都用try/catch块来捕获异常,但不是每个异常我们都能捕获,程序总会出现一些意想不到的情况,抛出一些未捕获的异常,这时就要用到全局异常捕获,即在程序的最外层加上捕获未处理异常,以免程序奔溃,影响用户体验。

事件描述
Application.DispatcherUnhandledExceptionUI线程的未处理异常捕获
AppDomain.UnhandledException非UI线程的未处理异常捕获
TaskScheduler.UnobservedTaskExceptionTask内未处理异常捕获
  • 构造中添加注册和退出事件
public App()
{
    //注册开始和退出事件
    Startup += App_Startup;
    Exit += App_Exit;
}
  • 注册事件中绑定异常处理事件
private void App_Startup(object sender, StartupEventArgs e)
{
    //UI线程未捕获异常处理事件
    DispatcherUnhandledException += App_DispatcherUnhandledException;
    //Task线程内未捕获异常处理事件
    TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
    //非UI线程未捕获异常处理事件
    AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
}
  • 退出事件中添加关闭程序需要处理的业务
private void App_Exit(object sender, ExitEventArgs e)
{
    //程序退出时需要处理的业务
}
  • 提取异常信息函数
/// 
/// 提取异常信息
/// 
private static string ExceptionToString(Exception ex, string info)
{
    StringBuilder str = new StringBuilder($"{DateTime.Now}, {info}发生了一个错误!{Environment.NewLine}");
    if (ex.InnerException == null)
    {
        str.Append($"【对象名称】:{ex.Source}{Environment.NewLine}");
        str.Append($"【异常类型】:{ex.GetType().Name}{Environment.NewLine}");
        str.Append($"【详细信息】:{ex.Message}{Environment.NewLine}");
        str.Append($"【堆栈调用】:{ex.StackTrace}");
    }
    else
    {
        str.Append($"【对象名称】:{ex.InnerException.Source}{Environment.NewLine}");
        str.Append($"【异常类型】:{ex.InnerException.GetType().Name}{Environment.NewLine}");
        str.Append($"【详细信息】:{ex.InnerException.Message}{Environment.NewLine}");
        str.Append($"【堆栈调用】:{ex.InnerException.StackTrace}");
    }
    return str.ToString();
}
  • UI线程未捕获异常处理函数
/// 
/// UI线程未捕获异常处理函数
/// 
private void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
    try
    {
        e.Handled = true;
        string msg = ExceptionToString(e.Exception, "UI线程");
        MessageBox.Show(msg, "系统错误", MessageBoxButton.OK, MessageBoxImage.Error);
    }
    catch (Exception ex)
    {
        string msg = ExceptionToString(ex, "UI线程 处理函数");
        MessageBox.Show(msg, "系统错误", MessageBoxButton.OK, MessageBoxImage.Error);
    }
}

备注:把 Handled 属性设为true,表示此异常已处理,程序可以继续运行,不会强制退出。
但不是所有的异常都可恢复,
如果异常是FileNotFoundException,程序可以在处理异常后继续运行,
如果异常是StackOverflowException,则无法再继续运行,即将关闭。

  • Task线程内未捕获异常处理函数
/// 
/// Task线程内未捕获异常处理函数
/// 
private void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
{
    try
    {
        string msg = ExceptionToString(e.Exception, "Task线程");
        MessageBox.Show(msg, "系统错误", MessageBoxButton.OK, MessageBoxImage.Error);
        e.SetObserved();//设置该异常已察觉(这样处理后就不会引起程序崩溃)
    }
    catch (Exception ex)
    {
        string msg = ExceptionToString(ex, "Task线程 处理函数");
        MessageBox.Show(msg, "系统错误", MessageBoxButton.OK, MessageBoxImage.Error);
    }
}

备注:该捕获存在延时

  • 非UI子线程未捕获异常处理函数
/// 
/// 非UI线程未捕获异常处理函数
/// 
private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
	try
	{
	    string msg;
	    if (e.ExceptionObject is Exception ex)
	    {
	        msg = ExceptionToString(ex, "非UI线程");
	    }
	    else
	    {
	        msg = $"发生了一个错误!信息:{e.ExceptionObject}";
	    }
	    MessageBox.Show(msg, "系统错误", MessageBoxButton.OK, MessageBoxImage.Error);
	}
	catch (Exception ex)
	{
	    string msg = ExceptionToString(ex, "非UI线程 处理函数");
	    MessageBox.Show(msg, "系统错误", MessageBoxButton.OK, MessageBoxImage.Error);
	}
}

备注:子线程异常处理完成后程序还是会结束,如果不希望程序退出则在App.config中添加如下内容


    
	    
	

这里的 ,用意是使用早期版本的异常处理策略。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/985417.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号