Files
personal-toolbox/PersonalToolBox/ViewModels/GroupEditViewModel.cs
home-PC b715904439 新增工具/组合随软件启动自动运行功能
- ToolItem 模型新增 AutoRunOnStart 属性,持久化到配置文件
- App.OnStartup 启动后自动执行标记为自启动的工具/组合(间隔500ms)
- 工具编辑窗口和组合编辑窗口新增「随软件启动自动运行」CheckBox
- 主界面工具卡片左上角 Rocket 角标标识已启用自启的项目
2026-05-10 02:51:29 +08:00

197 lines
6.3 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using PersonalToolBox.Helpers;
using PersonalToolBox.Models;
using PersonalToolBox.Services;
namespace PersonalToolBox.ViewModels;
/// <summary>
/// 组合编辑窗口 ViewModel管理一键多开组合的创建与编辑
/// </summary>
public partial class GroupEditViewModel : ObservableObject
{
private readonly IDataService _dataService;
private readonly ILogService _logService;
private readonly ToolItem? _editingGroup;
// ──────── 可观察属性 ────────
[ObservableProperty]
private string _windowTitle = "添加组合";
[ObservableProperty]
private string _name = string.Empty;
[ObservableProperty]
private string _hotKey = string.Empty;
[ObservableProperty]
private Category? _selectedCategory;
[ObservableProperty]
private IconProvider.IconOption? _selectedIcon;
[ObservableProperty]
private bool _autoRunOnStart;
/// <summary>
/// 可供勾选的普通工具列表IsGroup == false
/// </summary>
public ObservableCollection<SelectableTool> AvailableTools { get; } = new();
/// <summary>
/// 分类下拉列表
/// </summary>
public ObservableCollection<Category> Categories { get; } = new();
/// <summary>
/// 按分类分组的可用图标列表
/// </summary>
public ListCollectionView AvailableIconsView { get; }
public Action<bool?>? CloseAction { get; set; }
public bool Saved { get; private set; }
// ──────── 构造 ────────
public GroupEditViewModel(IDataService dataService, ILogService logService, ToolItem? groupToEdit = null)
{
_dataService = dataService;
_logService = logService;
_editingGroup = groupToEdit;
AvailableIconsView = new ListCollectionView(IconProvider.AvailableIcons);
AvailableIconsView.GroupDescriptions.Add(new PropertyGroupDescription("Category"));
foreach (var cat in _dataService.Config.Categories)
Categories.Add(cat);
// 加载所有工具(排除自身及祖先组合,防止循环引用)
var excludeIds = GetAncestorIds();
var selectedIds = _editingGroup?.SubToolIds ?? new List<string>();
foreach (var tool in _dataService.Config.Tools.Where(t => !excludeIds.Contains(t.Id)))
{
AvailableTools.Add(new SelectableTool
{
Tool = tool,
IsSelected = selectedIds.Contains(tool.Id)
});
}
if (groupToEdit != null)
{
WindowTitle = "编辑组合";
Name = groupToEdit.Name;
HotKey = groupToEdit.HotKey;
SelectedCategory = Categories.FirstOrDefault(c => c.Id == groupToEdit.CategoryId);
AutoRunOnStart = groupToEdit.AutoRunOnStart;
if (!string.IsNullOrEmpty(groupToEdit.IconCode))
{
SelectedIcon = IconProvider.AvailableIcons.FirstOrDefault(i => i.Icon.ToString() == groupToEdit.IconCode);
}
}
}
// ──────── 命令 ────────
[RelayCommand]
private void Save()
{
try
{
if (string.IsNullOrWhiteSpace(Name))
{
_logService.Warning("组合名称不能为空");
return;
}
var selectedIds = AvailableTools
.Where(t => t.IsSelected)
.Select(t => t.Tool.Id)
.ToList();
if (_editingGroup != null)
{
_editingGroup.Name = Name.Trim();
_editingGroup.IconCode = SelectedIcon?.Icon.ToString() ?? string.Empty;
_editingGroup.HotKey = HotKey.Trim();
_editingGroup.CategoryId = SelectedCategory?.Id ?? string.Empty;
_editingGroup.SubToolIds = selectedIds;
_editingGroup.IsValid = true;
_editingGroup.AutoRunOnStart = AutoRunOnStart;
_logService.Info($"已更新组合: {Name.Trim()}(包含 {selectedIds.Count} 个工具)");
}
else
{
_dataService.Config.Tools.Add(new ToolItem
{
Name = Name.Trim(),
IconCode = SelectedIcon?.Icon.ToString() ?? string.Empty,
HotKey = HotKey.Trim(),
CategoryId = SelectedCategory?.Id ?? string.Empty,
IsGroup = true,
SubToolIds = selectedIds,
IsValid = true,
AutoRunOnStart = AutoRunOnStart
});
_logService.Info($"已添加组合: {Name.Trim()}(包含 {selectedIds.Count} 个工具)");
}
_dataService.Save();
Saved = true;
CloseAction?.Invoke(true);
}
catch (Exception ex)
{
_logService.Error($"保存组合失败: {ex.Message}");
}
}
[RelayCommand]
private void Cancel()
{
CloseAction?.Invoke(false);
}
/// <summary>
/// 获取需要排除的工具 ID 集合(自身 + 所有祖先组合),防止循环引用
/// </summary>
private System.Collections.Generic.HashSet<string> GetAncestorIds()
{
var ancestors = new System.Collections.Generic.HashSet<string>();
if (_editingGroup != null)
{
ancestors.Add(_editingGroup.Id);
CollectAncestors(_editingGroup.Id, ancestors);
}
return ancestors;
}
private void CollectAncestors(string groupId, System.Collections.Generic.HashSet<string> ancestors)
{
foreach (var tool in _dataService.Config.Tools.Where(t => t.IsGroup))
{
if (tool.SubToolIds.Contains(groupId) && ancestors.Add(tool.Id))
{
CollectAncestors(tool.Id, ancestors);
}
}
}
}
/// <summary>
/// 可勾选的工具项(用于 CheckBox 列表绑定)
/// </summary>
public partial class SelectableTool : ObservableObject
{
public ToolItem Tool { get; set; } = null!;
[ObservableProperty]
private bool _isSelected;
}