Phase 2-3: UI layout, theme switching, CRUD tools, process execution
- Phase 2: MainWindow 3-section layout (sidebar/content/log bar), Dark/Light theme with ThemeHelper, MainViewModel with ObservableProperty/RelayCommand, tool card filtering by search + category - Phase 3: ToolEditWindow for add/edit tools, ProcessExecutionService (Process.Start + error handling), double-click + right-click context menu (run/edit), path browse dialog - Bugfix: ContextMenu commands now use PlacementTarget.Tag binding (ContextMenu in separate visual tree) - Bugfix: StaticResource converters moved to XAML before DataTemplate to fix XamlParseException on tool card render - Bugfix: Pure filenames (no path separators) treated as PATH commands, not marked invalid - Bugfix: RefreshData preserves SelectedCategory; Load() catches all exceptions; Save() wrapped in try-catch; auto-scroll log to newest entry - Tests: xUnit project with 55 tests covering models, services, converters, and view models
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using PersonalToolBox.Services;
|
||||
using PersonalToolBox.Views;
|
||||
|
||||
@@ -12,34 +13,81 @@ public partial class App : 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)
|
||||
{
|
||||
base.OnStartup(e);
|
||||
try
|
||||
{
|
||||
base.OnStartup(e);
|
||||
|
||||
var services = new ServiceCollection();
|
||||
ConfigureServices(services);
|
||||
Services = services.BuildServiceProvider();
|
||||
var services = new ServiceCollection();
|
||||
ConfigureServices(services);
|
||||
Services = services.BuildServiceProvider();
|
||||
|
||||
// 启动时加载配置文件(含路径验证与容错)
|
||||
var dataService = Services.GetRequiredService<IDataService>();
|
||||
dataService.Load();
|
||||
// 启动时加载配置文件(含路径验证与容错)
|
||||
var dataService = Services.GetRequiredService<IDataService>();
|
||||
dataService.Load();
|
||||
|
||||
var mainWindow = Services.GetRequiredService<MainWindow>();
|
||||
mainWindow.Show();
|
||||
var mainWindow = Services.GetRequiredService<MainWindow>();
|
||||
mainWindow.Show();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
WriteCrashLog($"启动失败: {ex}");
|
||||
MessageBox.Show($"启动失败:\n{ex.Message}\n\n详情已写入:\n{CrashLogPath}",
|
||||
"启动错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册所有服务到 DI 容器(单例模式)
|
||||
/// 注册所有服务到 DI 容器
|
||||
/// </summary>
|
||||
private static void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
// 日志服务
|
||||
services.AddSingleton<ILogService, LogService>();
|
||||
|
||||
// 数据持久化服务
|
||||
services.AddSingleton<IDataService, JsonDataService>();
|
||||
|
||||
// 主窗口
|
||||
services.AddSingleton<IProcessExecutionService, ProcessExecutionService>();
|
||||
services.AddSingleton<ViewModels.MainViewModel>();
|
||||
services.AddTransient<ViewModels.ToolEditViewModel>();
|
||||
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
|
||||
{
|
||||
// 无法写入日志时静默忽略
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user