8.2 KiB
个人工具箱 (Personal ToolBox) - 详细开发路径文档
Target Audience: OpenCode (DeepSeek-v4-flash) Architecture Pattern: MVVM (Model-View-ViewModel) Tech Stack: C# / .NET 8 / WPF / CommunityToolkit.Mvvm
🤖 【全局系统提示词 (System Prompt)】
(在开始任何代码生成前,请先将以下全局设定发给 AI)
"你现在是一位资深的 Windows 桌面客户端架构师和 C# WPF 专家。我们将一起开发一款名为“个人工具箱”的本地效率软件。 开发规范要求:
- 使用 .NET 8 WPF 技术栈。
- 严格遵循 MVVM 架构,引入
CommunityToolkit.Mvvm库以简化开发。- 采用依赖注入 (DI) 思想管理服务(如存储服务、日志服务)。
- UI 设计需极简现代化,原生支持暗黑/明亮模式切换。
- 必须提供完整、可运行的代码,且包含关键的中文注释。
- 请严格按照我后续给出的 Phase 阶段进行开发,不要跨越阶段。"
📍 Phase 0: 项目初始化与基础架构
【输入给 AI 的指令】:
"现在我们开始 Phase 0:项目初始化。请帮我:
- 创建一个名为
PersonalToolBox的 WPF 应用程序。- 引入必要的 NuGet 包:
CommunityToolkit.Mvvm、System.Text.Json。- 建立标准 MVVM 目录结构:
Models、ViewModels、Views、Services、Helpers。- 编写
ILogService接口和LogService实现类,用于管理底部的日志打印栏数据(需要包含时间、日志级别 Info/Warning/Error、日志内容),并能通过事件或 ObservableCollection 将日志实时推送到 UI。 请给出项目结构树以及LogService的完整代码。"
📍 Phase 1: 数据模型与本地存储服务
【输入给 AI 的指令】:
"进入 Phase 1:数据模型与存储。我们需要用本地 JSON 文件作为数据库。请帮我实现:
- 在
Models文件夹下创建数据模型:
ToolItem: 包含 Id, Name, IconCode, ExecutablePath, Arguments, CategoryId, HotKey, IsValid(布尔值,用于标记文件是否丢失,不存入JSON,仅运行时计算)。Category: 包含 Id, Name。AppConfig: 包含 Theme(Dark/Light), AutoStart(bool), List, List。- 在
Services下创建IDataService和JsonDataService:
- 实现数据的加载 (Load) 和 保存 (Save),文件默认保存在
AppDomain.CurrentDomain.BaseDirectory + "config.json"。- 核心业务逻辑(容错机制):在
Load时,遍历所有的ToolItem,检查ExecutablePath是否存在(使用File.Exists)。如果不存在,将该工具的IsValid设为false,并调用ILogService打印警告日志[警告] 工具 {Name} 路径失效...,绝对不要从集合中删除它。 请提供这些 Model 和 Service 的完整 C# 代码。"
📍 Phase 2: 主窗口 UI 布局与主题切换
【输入给 AI 的指令】:
"进入 Phase 2:主界面搭建。请帮我编写
MainWindow.xaml及其 ViewModelMainViewModel.cs。 UI 布局要求 (Grid 布局):
- 整体分为三部分:左侧边栏 (宽200)、右侧主体区 (按比例占满)、底部日志栏 (高120)。
- 左侧边栏:顶部显示软件名称,中间使用
ListBox绑定 Categories(标签页分类),底部放置一个切换“黑夜/白天模式”的 Button。- 右侧主体区:顶部包含一个
TextBox(全局搜索框) 和一个 "添加工具" Button。下方使用ItemsControl+WrapPanel绑定当前分类下的 ToolItems,以卡片形式展示工具图标和名称。- 底部日志栏:包含一个标题栏(附带“清空日志”按钮)和一个只读的
RichTextBox或ListBox,绑定LogService的日志数据。功能要求:
- 实现简单的黑夜/白天模式切换(动态替换 WPF 的
ResourceDictionary中的颜色画笔)。- 当
ToolItem.IsValid为 false 时,UI 上的工具卡片需变灰(Opacity=0.5)。 请提供MainWindow.xaml的布局代码、ThemeHelper切换主题代码、以及绑定的MainViewModel代码。"
📍 Phase 3: 核心逻辑 - 增删改查与运行进程
【输入给 AI 的指令】:
"进入 Phase 3:工具的管理与执行。请帮我实现:
- 新建/编辑工具弹窗:创建一个
ToolEditWindow.xaml,包含表单字段(名称、路径选择按钮、参数、分类下拉框、快捷键输入框)。保存时更新到JsonDataService并刷新主界面。- 搜索功能:在
MainViewModel中实现搜索框的过滤逻辑。根据TextBox的输入,实时过滤展示的 ToolItems。- 运行进程服务:新建
ProcessExecutionService.cs。
- 接收
ToolItem作为参数。- 如果
!IsValid,调用日志服务提示用户无法运行。- 使用
System.Diagnostics.Process.Start(new ProcessStartInfo { FileName = path, Arguments = args, UseShellExecute = true })启动进程。- 如果发生异常(如权限不足),被
try-catch捕获并将 Error 写入底部日志栏。 请给出编辑窗口的 XAML 与代码,以及进程执行服务类的核心代码。"
📍 Phase 4: 高级特性 - 全局快捷键拦截 (Win32 API)
【输入给 AI 的指令】:
"进入 Phase 4:全局快捷键支持。这个工具箱即使在后台,按下为某个工具配置的全局快捷键也需要能直接拉起该工具。
- 在
Helpers目录下创建HotKeyManager.cs。- 使用 Win32 API (
RegisterHotKey和UnregisterHotKey)。- 在
MainWindow.xaml.cs中重写OnSourceInitialized,通过HwndSource.FromHwnd挂载AddHook拦截系统 Windows 消息 (WM_HOTKEY)。- 当拦截到快捷键时,根据热键 ID 匹配对应的
ToolItem,并调用ProcessExecutionService启动它,同时在底部日志打印“通过快捷键启动:XXX”。 请提供完整的 Win32 API 声明代码以及快捷键注册、解绑、拦截执行的完整逻辑。"
📍 Phase 5: 高级特性 - 系统托盘与开机自启
【输入给 AI 的指令】:
"进入最后一个阶段 Phase 5:系统托盘与自启动。
- 系统托盘集成:不需要引入复杂的第三方库,请直接使用
System.Windows.Forms.NotifyIcon来实现。
- 托盘图标常驻。
- 鼠标左键点击托盘图标:如果主窗口隐藏则显示,如果显示则隐藏。
- 重写
MainWindow的OnClosing事件:点击右上角关闭按钮时,取消关闭 (e.Cancel = true),改为隐藏窗口 (this.Hide())。- 右键托盘图标提供菜单:“显示主界面”、“设置”、“彻底退出”。
- 开机自启动设置:
- 在
Helpers目录下创建AutoStartHelper.cs。- 通过写入 Windows 注册表
HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Run实现开机自启动。- 如果启动参数带有
-autostart,则主程序启动后直接隐藏到系统托盘,不弹出主窗口。 请给出托盘管理逻辑代码和自启动帮助类的实现代码。"
💡 辅助除错指南 (针对 DeepSeek 可能会犯的错误)
如果在开发过程中,AI 返回的代码运行报错:
- 如果 UI 数据不刷新:
"界面没有刷新。请检查 ViewModel 中的属性是否使用了
[ObservableProperty](CommunityToolkit.Mvvm),以及集合是否使用了ObservableCollection<T>而不是List<T>。" - 如果快捷键注册失败:
"RegisterHotKey 返回 false。请确保热键 ID 唯一,且修饰键(Ctrl/Alt/Shift)和虚拟键码(VK)的转换正确。请检查是否与其他系统快捷键冲突,并在 LogService 中打印错误码。"
- 如果读取 JSON 失败:
"反序列化 JSON 失败。请检查
System.Text.Json的配置,是否需要开启PropertyNameCaseInsensitive = true,或者类定义缺少了无参构造函数。" - 如果托盘图标不显示:
"NotifyIcon 没有显示。请确保为其分配了有效的
.ico文件资源,并且设置了Visible = true。请确保在程序退出时调用了NotifyIcon.Dispose()释放图标。"