# XFEToolBox 工具开发者指南与 API 参考 本文面向使用 XFEToolBox Code Studio 编写、调试、打包和发布 WPF 工具的开发者。内容以当前仓库源码为准,覆盖工具运行模型、工程结构、清单格式、宿主生命周期、数据存储、统一主题、可复用控件、弹窗、交互教程、目录客户端和服务端工具接口。 > API 范围说明:本文所称“全部 API”指 XFEToolBox 明确提供给源码工具复用的宿主 API。生成的运行工程也引用了完整客户端程序集,因此部分客户端内部类型在 C# 层面是 `public`,但登录会话、主窗口导航、管理页面、客户端 Profile 和 Code Studio 内部服务不属于工具 SDK,不提供兼容承诺。 ## 目录 - [设计边界](#设计边界) - [运行环境与自动引用](#运行环境与自动引用) - [使用 Code Studio](#使用-code-studio) - [包目录](#包目录) - [manifest.json](#manifestjson) - [入口视图与生命周期](#入口视图与生命周期) - [文件、资源与依赖](#文件资源与依赖) - [工具数据存储 API](#工具数据存储-api) - [主题与标准控件](#主题与标准控件) - [宿主控件 API](#宿主控件-api) - [弹窗 API](#弹窗-api) - [交互教程 API](#交互教程-api) - [目录模型与客户端 API](#目录模型与客户端-api) - [Code Studio 快捷键](#code-studio-快捷键) - [服务端工具接口](#服务端工具接口) - [调试、发布与安全](#调试发布与安全) ## 设计边界 `.xfetool` 是扩展名固定的 ZIP 源码包,当前 `packageFormatVersion` 为 `1`。服务端使用 `XFEExtension.NetCore.ServerInteractive` 保存、校验和分发工具包,但不会在服务器上编译或执行其中的代码。 客户端在下载后校验服务端返回的 SHA-256,再把包解压到临时目录、生成独立的 WPF 运行工程并调用 `dotnet` 编译。工具最终在单独进程和窗口中运行,但仍拥有当前桌面用户的系统权限,因此发布前必须审核源码。 每个工具拥有独立进程、独立 WPF `Application`、独立宿主窗口和按工具 ID 隔离的数据目录。独立进程可以隔离崩溃和静态状态,但不是安全沙箱:工具仍能访问当前 Windows 用户有权访问的文件、网络、剪贴板、注册表和进程。 ## 运行环境与自动引用 Code Studio 每次生成临时运行工程,开发者不需要维护 `.csproj`。当前生成参数和引用如下: | 项目 | 当前值 | | --- | --- | | 目标框架 | `net10.0-windows` | | UI 框架 | WPF,`UseWPF=true` | | 可空引用类型 | 启用 | | 隐式 using | 启用 | | 应用入口 | 由 XFEToolBox 生成 | | NuGet | `CommunityToolkit.Mvvm 8.4.2` | | 宿主程序集 | `XFEToolBox` | | 共享契约 | `XFEToolBox.Core` | | 客户端核心 | `XFEToolBox.Client.Core` | | 扩展库 | `XFEExtension.NetCore 5.1.0` | 因此工具代码可以直接使用: - .NET 10 基础类库和 WPF API; - `CommunityToolkit.Mvvm` 的 `ObservableObject`、`[ObservableProperty]`、`[RelayCommand]` 等; - 本文列出的 XFEToolBox 宿主 API; - `XFEExtension.NetCore 5.1.0` 的公开 API。该依赖属于外部库并随宿主版本固定,本文不复制其完整 API 参考,工具不应依赖未在清单中声明的宿主内部行为。 运行工程不读取工具目录中的自定义 `.csproj`,也不会解析额外的 `PackageReference`。工具包禁止携带 DLL 和 EXE,因此当前工具只能使用上述固定引用;需要新增三方依赖时,应先由 XFEToolBox 宿主正式加入并发布兼容版本。 ## 使用 Code Studio 客户端的 XFEToolBox Code Studio 可以完成完整的工具开发流程: 1. 新建项目,或打开包含 `manifest.json` 的现有目录。 2. 在 Monaco Editor 中编辑 C#、XAML、JSON 和 Markdown;`manifest.json` 同时提供可视化设计器。 3. 使用预览检查 XAML 或 Markdown,并使用“运行”在独立窗口中编译测试。 4. 导出 `.xfetool` 到工程目录之外,或以管理员账号直接发布到工具服务器。 默认工作区位于客户端本地数据目录的 `EditorWorkspaces`。工程历史和资源管理器布局保存在客户端本地数据中,不会写入导出的工具包。 ## 包目录 Code Studio 新建项目时采用以下结构;也可以使用其他目录名,只要 `manifest.json` 中的入口路径与包内文件一致。 ```text base64-generator.xfetool ├── manifest.json ├── README.md ├── Code │ ├── Views │ │ ├── MainPage.xaml │ │ └── MainPage.xaml.cs │ ├── ViewModels │ │ └── MainPageViewModel.cs │ └── Models │ └── ToolModel.cs └── Assets └── icon.png ``` 服务端允许 `.xaml`、`.cs`、`.json`、`.xml`、`.resx`、`.txt`、`.md`、常用图片、SVG、TTF 和 OTF;不允许 DLL、EXE、脚本、重复路径或符号链接。默认限制为: | 项目 | 默认值 | | --- | --- | | 压缩包大小 | 10 MiB | | 解压后总大小 | 30 MiB | | 文件数量 | 256 | | 单个清单大小 | 256 KiB | | 单个图标大小 | 512 KiB | | 最大压缩率 | 100:1 | 包大小、解压大小、文件数和压缩率可以通过服务端 `ServerProfile` 的 AutoConfig XML 调整。 ## manifest.json ```json { "packageFormatVersion": 1, "id": "base64-generator", "name": "Base64 生成器", "subtitle": "文本与 Base64 快速互转", "version": "1.0.0", "description": "文本与 Base64 的相互转换。", "author": "XFEstudio", "icon": "Assets/icon.png", "category": "编码", "tags": ["base64", "编码"], "minimumHostVersion": "0.2.0", "releaseNotes": "首个版本。", "nugetPackages": [ { "id": "Example.Package", "version": "1.2.3" } ], "requiresAdministrator": false, "entry": { "viewXaml": "Code/Views/MainPage.xaml", "viewClass": "XFEToolBox.Tools.Base64.MainPage", "viewCodeBehind": "Code/Views/MainPage.xaml.cs", "viewModel": "Code/ViewModels/MainPageViewModel.cs", "viewModelClass": "XFEToolBox.Tools.Base64.MainPageViewModel" }, "window": { "width": 760, "height": 560, "minWidth": 420, "minHeight": 300, "allowResize": true, "allowMaximize": true, "showMinimizeButton": true, "showCloseButton": true }, "requestedPermissions": ["clipboard"] } ``` ### 顶层字段 | JSON 字段 | C# 类型 | 必填/默认值 | 约束与行为 | | --- | --- | --- | --- | | `packageFormatVersion` | `int` | 默认 `1` | 必须等于 `ToolPackageManifest.CurrentPackageFormatVersion`,当前为 `1` | | `id` | `string` | 必填 | 1–64 位;小写字母开头;仅允许小写字母、数字、`.`、`-`;发布后应保持稳定 | | `name` | `string` | 必填 | 1–100 字符;显示在工具卡片和窗口标题区 | | `subtitle` | `string?` | `null` | 窗口标题区副标题;空值时使用 `description` | | `version` | `string` | 必填 | 有效 SemVer,如 `1.2.0`、`2.0.0-beta.1` | | `description` | `string` | 必填 | 1–2000 字符 | | `author` | `string` | 必填 | 1–100 字符 | | `icon` | `string?` | `null` | 包内相对路径;PNG/JPEG/GIF/BMP/ICO;文件存在且不超过 512 KiB | | `category` | `string` | `"其他"` | 1–50 字符 | | `tags` | `string[]` | `[]` | 最多 20 项,每项 1–40 字符 | | `minimumHostVersion` | `string?` | `null` | 非空时必须是 SemVer;当前服务端会校验格式,但客户端尚未据此阻止运行 | | `releaseNotes` | `string?` | `null` | 当前版本说明 | | `nugetPackages` | `ToolNuGetPackageReference[]` | `[]` | 当前项目独立使用的 NuGet 包;最多 64 项,包 ID 不区分大小写且不能重复,版本必须是精确版本 | | `requiresAdministrator` | `bool` | `false` | 为 `true` 时工具卡片显示 UAC 盾牌,宿主强制通过 Windows UAC 以管理员身份启动;用户不能在工具配置中关闭 | | `entry` | `ToolEntryManifest` | 必填 | 入口视图配置,见下表 | | `window` | `ToolWindowManifest` | 默认对象 | 独立宿主窗口配置,见下表 | | `requestedPermissions` | `string[]` | `[]` | 最多 32 项,每项 1–64 字符;当前为声明信息,不代表已获得或被限制的权限 | Code Studio 可视化设计器提供的通用权限名称为:`FileSystem`、`Network`、`Clipboard`、`Process`、`Shell`、`Registry`、`Notifications`、`Environment`、`InputSimulation`、`Camera`、`Microphone`、`Location`。名称比较不区分大小写,也允许保留自定义权限名。 `requiresAdministrator` 也可以在代码工坊的 `manifest.json · 可视化配置` →“权限与格式”中勾选。该字段属于工具作者声明的强制策略,与用户在工具卡片“工具配置”中的可选管理员模式不同;任一项启用都会以管理员身份启动,但清单强制策略不能被用户覆盖。 ### `nugetPackages` 每个项目可以在 Code Studio 的 `manifest.json · 可视化配置` →“NuGet 包”中独立添加、更新或移除包。运行和生成验证时,工具箱会把这些引用写入该工具自己的临时 `.csproj`,再使用标准 `dotnet restore/build` 流程解析依赖;发布到 `.xfetool` 后,包引用仍保存在清单中。 包 ID 仅允许字母、数字、点、短横线和下划线,长度不超过 100;`version` 必须固定为 `1.2.3`、`1.2.3-beta.1` 这类精确版本,不接受 `*`、`[1.0,2.0)` 等浮动版本或范围。项目显式引用 `CommunityToolkit.Mvvm` 时可以覆盖工具箱内置的默认版本。NuGet 包可能携带构建目标并在还原/编译阶段运行,因此只应添加可信来源的包。 ### `entry` | JSON 字段 | C# 类型 | 必填 | 说明 | | --- | --- | --- | --- | | `viewXaml` | `string` | 是 | 安全的包内 `.xaml` 相对路径,文件必须存在 | | `viewClass` | `string` | 是 | 入口 CLR 完整类名,最长 300 字符;必须具有无参数构造函数 | | `viewCodeBehind` | `string` | 是 | 安全的包内 `.cs` 相对路径,文件必须存在 | | `viewModel` | `string?` | 否 | ViewModel `.cs` 路径;填写时文件必须存在 | | `viewModelClass` | `string?` | 否 | ViewModel 完整类名;设置它时必须同时设置 `viewModel` | `viewModel` 和 `viewModelClass` 当前用于清单描述与文件校验。宿主不会自动创建该类型或设置 `DataContext`;入口视图必须在构造函数中自行完成。 ### `window` | JSON 字段 | 默认值 | 运行时行为 | | --- | --- | --- | | `width` | `760` | 初始宽度,运行时限制到 320–3840,且不小于 `minWidth` | | `height` | `560` | 初始高度,运行时限制到 220–2160,且不小于 `minHeight` | | `minWidth` | `420` | 最小宽度,运行时限制到 320–3840 | | `minHeight` | `300` | 最小高度,运行时限制到 220–2160 | | `allowResize` | `true` | 是否允许缩放;为 `false` 时同时禁用最大化 | | `allowMaximize` | `true` | 是否允许双击顶部拖动条最大化/还原;不会增加单独的最大化按钮 | | `showMinimizeButton` | `true` | 是否显示最小化按钮 | | `showCloseButton` | `true` | 是否显示关闭按钮 | 宿主会自动记住窗口位置、普通状态尺寸和最大化状态。即使保存时窗口处于最小化状态,下次也会恢复到最后一个可见状态。 ## 入口视图与生命周期 入口类必须满足以下条件: 1. 类名与 `entry.viewClass` 完全一致; 2. 具有可调用的无参数构造函数; 3. 继承 `UIElement`(通常为 `UserControl` 或 `Page`)或 `Window`; 4. XAML 的 `x:Class` 与代码后置命名空间、类名一致。 推荐使用 `UserControl`,由宿主负责窗口外壳: ```xml