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:
55
PersonalToolBox/Helpers/ThemeHelper.cs
Normal file
55
PersonalToolBox/Helpers/ThemeHelper.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Windows;
|
||||
|
||||
namespace PersonalToolBox.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// 主题切换辅助类,动态替换 Application 的 ResourceDictionary
|
||||
/// </summary>
|
||||
public static class ThemeHelper
|
||||
{
|
||||
private const string ThemePrefix = "Themes/";
|
||||
private const string DarkThemePath = "Themes/DarkTheme.xaml";
|
||||
private const string LightThemePath = "Themes/LightTheme.xaml";
|
||||
|
||||
/// <summary>
|
||||
/// 切换主题(Dark / Light)
|
||||
/// </summary>
|
||||
public static void ApplyTheme(string theme)
|
||||
{
|
||||
var app = Application.Current;
|
||||
if (app == null) return;
|
||||
|
||||
// 移除旧的主题资源字典
|
||||
var oldDict = FindThemeDictionary(app.Resources.MergedDictionaries);
|
||||
if (oldDict != null)
|
||||
app.Resources.MergedDictionaries.Remove(oldDict);
|
||||
|
||||
// 加载新的主题资源字典
|
||||
var path = theme switch
|
||||
{
|
||||
"Light" => LightThemePath,
|
||||
_ => DarkThemePath
|
||||
};
|
||||
|
||||
var newDict = new ResourceDictionary
|
||||
{
|
||||
Source = new Uri(path, UriKind.Relative)
|
||||
};
|
||||
app.Resources.MergedDictionaries.Add(newDict);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 在当前合并字典中查找主题相关的 ResourceDictionary
|
||||
/// </summary>
|
||||
private static ResourceDictionary? FindThemeDictionary(Collection<ResourceDictionary> dictionaries)
|
||||
{
|
||||
foreach (var dict in dictionaries)
|
||||
{
|
||||
if (dict.Source != null && dict.Source.OriginalString.StartsWith(ThemePrefix))
|
||||
return dict;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user