- 系统托盘: NotifyIcon 常驻, 程序化生成 32x32 图标, 左键切换显示/隐藏, 右键菜单(显示主界面/设置/彻底退出) - 窗口关闭拦截: OnClosing 取消关闭改为 Hide(), 退出菜单执行真实 Shutdown() - 开机自启: AutoStartHelper 写入/删除 HKCU\...\Run 注册表项, UI 开关按钮显示 ✔/⊗ 状态 - 静默启动: -autostart 参数下 mainWindow.Hide() 直接最小化到托盘 - 类型冲突解决: ImplicitUsings=disable + GlobalUsings.cs 统一全局 using, 消除 WPF/WinForms 共享类型冲突 - 测试: 75 tests total (含 AutoStartHelper 2 tests)
105 lines
3.4 KiB
C#
105 lines
3.4 KiB
C#
using System.IO;
|
|
using System.Windows;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using PersonalToolBox.Services;
|
|
using PersonalToolBox.Views;
|
|
|
|
namespace PersonalToolBox;
|
|
|
|
/// <summary>
|
|
/// WPF 应用程序入口,负责依赖注入容器初始化和启动主窗口
|
|
/// </summary>
|
|
public partial class App : System.Windows.Application
|
|
{
|
|
public static IServiceProvider Services { get; private set; } = null!;
|
|
|
|
private static readonly string CrashLogPath = Path.Combine(
|
|
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
|
|
"PersonalToolBox", "crash.log");
|
|
|
|
public App()
|
|
{
|
|
// 监听未处理的异常,写入文件日志
|
|
DispatcherUnhandledException += (s, e) =>
|
|
{
|
|
WriteCrashLog($"UI线程异常: {e.Exception}");
|
|
e.Handled = true;
|
|
MessageBox.Show($"发生未处理异常:\n{e.Exception.Message}\n\n详情已写入:\n{CrashLogPath}",
|
|
"错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
};
|
|
|
|
AppDomain.CurrentDomain.UnhandledException += (s, e) =>
|
|
{
|
|
WriteCrashLog($"未处理异常: {e.ExceptionObject}");
|
|
};
|
|
}
|
|
|
|
protected override void OnStartup(StartupEventArgs e)
|
|
{
|
|
try
|
|
{
|
|
base.OnStartup(e);
|
|
|
|
var services = new ServiceCollection();
|
|
ConfigureServices(services);
|
|
Services = services.BuildServiceProvider();
|
|
|
|
// 启动时加载配置文件(含路径验证与容错)
|
|
var dataService = Services.GetRequiredService<IDataService>();
|
|
dataService.Load();
|
|
|
|
var mainWindow = Services.GetRequiredService<MainWindow>();
|
|
|
|
// -autostart 参数:开机自启时隐藏窗口
|
|
if (e.Args.Contains("-autostart", StringComparer.OrdinalIgnoreCase))
|
|
{
|
|
mainWindow.Hide();
|
|
}
|
|
else
|
|
{
|
|
mainWindow.Show();
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
WriteCrashLog($"启动失败: {ex}");
|
|
MessageBox.Show($"启动失败:\n{ex.Message}\n\n详情已写入:\n{CrashLogPath}",
|
|
"启动错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
Shutdown();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 注册所有服务到 DI 容器
|
|
/// </summary>
|
|
private static void ConfigureServices(IServiceCollection services)
|
|
{
|
|
services.AddSingleton<ILogService, LogService>();
|
|
services.AddSingleton<IDataService, JsonDataService>();
|
|
services.AddSingleton<IProcessExecutionService, ProcessExecutionService>();
|
|
services.AddSingleton<Helpers.HotKeyManager>();
|
|
services.AddSingleton<ViewModels.MainViewModel>();
|
|
services.AddTransient<ViewModels.ToolEditViewModel>();
|
|
services.AddTransient<ViewModels.CategoryEditViewModel>();
|
|
services.AddSingleton<MainWindow>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 将崩溃信息写入文件日志
|
|
/// </summary>
|
|
public static void WriteCrashLog(string message)
|
|
{
|
|
try
|
|
{
|
|
var dir = Path.GetDirectoryName(CrashLogPath);
|
|
if (dir != null) Directory.CreateDirectory(dir);
|
|
File.AppendAllText(CrashLogPath,
|
|
$"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {message}{Environment.NewLine}{Environment.NewLine}");
|
|
}
|
|
catch
|
|
{
|
|
// 无法写入日志时静默忽略
|
|
}
|
|
}
|
|
}
|