128 lines
3.8 KiB
C#
128 lines
3.8 KiB
C#
|
using System.Diagnostics;
|
|||
|
using System.IO;
|
|||
|
using System.Windows;
|
|||
|
using System.Windows.Threading;
|
|||
|
|
|||
|
namespace WPF_25_TreeView;
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Interaction logic for App.xaml
|
|||
|
/// </summary>
|
|||
|
public partial class App
|
|||
|
{
|
|||
|
protected override void OnStartup(StartupEventArgs e)
|
|||
|
{
|
|||
|
// 全局未处理异常捕获(UI线程和非UI线程)
|
|||
|
AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
|
|||
|
|
|||
|
// 专为WPF UI线程异常捕获(例如按钮点击事件中的异常)
|
|||
|
DispatcherUnhandledException += OnDispatcherUnhandledException;
|
|||
|
|
|||
|
// 异步任务异常捕获
|
|||
|
TaskScheduler.UnobservedTaskException += OnUnobservedTaskException;
|
|||
|
|
|||
|
base.OnStartup(e);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 处理非UI线程异常
|
|||
|
/// </summary>
|
|||
|
private static void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
|
|||
|
{
|
|||
|
if (e.ExceptionObject is not Exception exception) return;
|
|||
|
LogException(exception, "全局异常");
|
|||
|
|
|||
|
if (e.IsTerminating) // 如果是致命异常
|
|||
|
{
|
|||
|
ShowFatalError(exception);
|
|||
|
Environment.Exit(1); // 确保应用退出
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
ShowUserFriendlyError(exception);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 处理UI线程异常(可阻止应用崩溃)
|
|||
|
/// </summary>
|
|||
|
private static void OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
|
|||
|
{
|
|||
|
LogException(e.Exception, "UI线程异常");
|
|||
|
ShowUserFriendlyError(e.Exception);
|
|||
|
|
|||
|
// 标记为已处理,阻止应用崩溃(谨慎使用!)
|
|||
|
e.Handled = true;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 处理异步任务异常
|
|||
|
/// </summary>
|
|||
|
private static void OnUnobservedTaskException(object? sender, UnobservedTaskExceptionEventArgs e)
|
|||
|
{
|
|||
|
LogException(e.Exception, "异步任务异常");
|
|||
|
e.SetObserved(); // 标记为已处理,避免进程崩溃
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 记录异常到日志文件
|
|||
|
/// </summary>
|
|||
|
private static void LogException(Exception ex, string category)
|
|||
|
{
|
|||
|
var logMessage = $"[{DateTime.Now}] [{category}]\n{ex}\n\n";
|
|||
|
|
|||
|
try
|
|||
|
{
|
|||
|
File.AppendAllText("app_errors.log", logMessage);
|
|||
|
Debug.WriteLine(logMessage); // 输出到调试窗口
|
|||
|
}
|
|||
|
catch
|
|||
|
{
|
|||
|
/* 防止日志记录本身抛出异常 */
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 显示用户友好的错误提示
|
|||
|
/// </summary>
|
|||
|
private static void ShowUserFriendlyError(Exception ex)
|
|||
|
{
|
|||
|
var message = ex switch
|
|||
|
{
|
|||
|
UnauthorizedAccessException => $"权限不足: {ex.Message}\n请检查文件/文件夹权限。",
|
|||
|
FileNotFoundException => $"文件未找到: {ex.Message}",
|
|||
|
IOException => $"文件读写错误: {ex.Message}",
|
|||
|
_ => $"发生错误: {(ex.InnerException ?? ex).Message}"
|
|||
|
};
|
|||
|
|
|||
|
MessageBox.Show(
|
|||
|
message,
|
|||
|
"错误",
|
|||
|
MessageBoxButton.OK,
|
|||
|
MessageBoxImage.Error
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 显示致命错误并退出
|
|||
|
/// </summary>
|
|||
|
private static void ShowFatalError(Exception ex)
|
|||
|
{
|
|||
|
MessageBox.Show(
|
|||
|
$"程序即将关闭,原因:\n{ex.Message}\n\n详细信息已记录到日志。",
|
|||
|
"致命错误",
|
|||
|
MessageBoxButton.OK,
|
|||
|
MessageBoxImage.Stop
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
protected override void OnExit(ExitEventArgs e)
|
|||
|
{
|
|||
|
// 清理事件订阅
|
|||
|
AppDomain.CurrentDomain.UnhandledException -= OnUnhandledException;
|
|||
|
DispatcherUnhandledException -= OnDispatcherUnhandledException;
|
|||
|
TaskScheduler.UnobservedTaskException -= OnUnobservedTaskException;
|
|||
|
|
|||
|
base.OnExit(e);
|
|||
|
}
|
|||
|
}
|