# 通用窗体使用指南 | General Form Usage Guide ## 概述 | Overview `XP.Common.GeneralForm` 提供 XplorePlane 项目中可复用的通用 WPF 窗体组件。当前包含以下窗体: | 窗体 | 说明 | |---|---| | `ProgressWindow` | 模态进度条窗口,支持线程安全的进度更新和关闭操作 | | `InputDialog` | 通用输入对话框,支持单行文本输入、可选验证和多语言按钮 | ## 目录结构 | Directory Structure ``` XP.Common/GeneralForm/ ├── ViewModels/ │ ├── InputDialogViewModel.cs # 输入对话框 ViewModel │ └── ProgressWindowViewModel.cs # 进度窗口 ViewModel └── Views/ ├── InputDialog.xaml # 输入对话框 XAML 视图 ├── InputDialog.xaml.cs # 输入对话框 Code-Behind ├── ProgressWindow.xaml # 进度窗口 XAML 视图 └── ProgressWindow.xaml.cs # 进度窗口 Code-Behind ``` --- ## ProgressWindow 进度条窗口 ### 功能特性 | Features - 模态进度条窗口,居中显示,不可调整大小 - 线程安全:`UpdateProgress()` 和 `Close()` 可从任意线程调用,内部自动通过 `Dispatcher` 调度 - 可配置是否允许用户手动关闭窗口(`isCancelable` 参数) - 不可取消时,通过 Win32 API 禁用窗口关闭按钮(灰色不可点击) - 进度值自动 Clamp 到 `[0, 100]` 范围,超出范围时记录 Warn 日志 - 自动继承主窗口图标 - 使用 Telerik `RadProgressBar` 控件(Crystal 主题) ### 构造函数参数 | Constructor Parameters ```csharp public ProgressWindow( string title = "操作进行中", // 窗口标题 string message = "请稍候...", // 提示信息 bool isCancelable = true, // 是否允许用户关闭窗口 ILoggerService? logger = null // 日志服务(可选) ) ``` | 参数 | 类型 | 默认值 | 说明 | |---|---|---|---| | `title` | `string` | `"操作进行中"` | 窗口标题栏文本 | | `message` | `string` | `"请稍候..."` | 进度条上方的提示信息 | | `isCancelable` | `bool` | `true` | `true`:用户可手动关闭;`false`:禁用关闭按钮 | | `logger` | `ILoggerService?` | `null` | 传入日志服务后自动记录窗口生命周期日志 | ### 公开方法 | Public Methods #### UpdateProgress - 更新进度 ```csharp // 线程安全,可从任意线程调用 void UpdateProgress(string message, double progress) ``` - `message`:更新提示信息文本 - `progress`:进度值(0-100),超出范围自动修正 #### Close - 关闭窗口 ```csharp // 线程安全,可从任意线程调用(隐藏基类 Window.Close()) new void Close() ``` ### 基本用法 | Basic Usage ```csharp using XP.Common.GeneralForm.Views; using XP.Common.Logging.Interfaces; public class SomeService { private readonly ILoggerService _logger; public SomeService(ILoggerService logger) { _logger = logger?.ForModule() ?? throw new ArgumentNullException(nameof(logger)); } public async Task ExecuteLongOperation() { // 创建进度窗口(不可取消) var progressWindow = new ProgressWindow( title: "数据处理中", message: "正在初始化...", isCancelable: false, logger: _logger); // 显示模态窗口(需在 UI 线程调用) // 注意:ShowDialog() 会阻塞,通常配合 Task 使用 _ = Task.Run(async () => { try { progressWindow.UpdateProgress("正在加载数据...", 20); await Task.Delay(1000); // 模拟耗时操作 progressWindow.UpdateProgress("正在处理数据...", 60); await Task.Delay(1000); progressWindow.UpdateProgress("即将完成...", 90); await Task.Delay(500); progressWindow.UpdateProgress("完成", 100); } finally { // 关闭窗口(线程安全) progressWindow.Close(); } }); progressWindow.ShowDialog(); } } ``` ### 允许用户取消的用法 | Cancelable Usage ```csharp // 创建可取消的进度窗口 var progressWindow = new ProgressWindow( title: "文件导出", message: "正在导出文件...", isCancelable: true, // 用户可以点击关闭按钮取消 logger: _logger); progressWindow.ShowDialog(); ``` ### ViewModel 绑定属性 | ViewModel Binding Properties `ProgressWindowViewModel` 继承自 `BindableBase`,提供以下可绑定属性: | 属性 | 类型 | 说明 | |---|---|---| | `Title` | `string` | 窗口标题(只读) | | `Message` | `string` | 提示信息文本(可通知) | | `Progress` | `double` | 进度值 0-100(可通知) | | `ProgressText` | `string` | 百分比显示文本,如 `"75%"`(只读,自动计算) | | `IsCancelable` | `bool` | 是否允许用户关闭(只读) | ### 注意事项 | Notes 1. `ShowDialog()` 必须在 UI 线程调用,它会阻塞当前线程直到窗口关闭 2. `UpdateProgress()` 和 `Close()` 内部已处理跨线程调度,可安全地从后台线程调用 3. 当 `isCancelable = false` 时,窗口关闭按钮会被 Win32 API 禁用(灰色),用户无法通过 Alt+F4 或点击关闭 4. 进度值超出 `[0, 100]` 范围时会自动修正并记录 Warn 级别日志 5. `Close()` 使用 `new` 关键字隐藏基类方法(因 `Window.Close()` 非虚方法),确保通过 `ProgressWindow` 类型引用调用 --- ## InputDialog 输入对话框 ### 功能特性 | Features - 模态输入对话框,居中于父窗口显示,不可调整大小 - 自动继承主窗口图标 - 按钮文本支持多语言(使用 `Button_OK` / `Button_Cancel` 资源键) - 可选的输入验证委托(`Func`),验证失败时在输入框下方显示红色错误提示 - 输入内容变化时自动清除验证错误 - 使用 Telerik `RadWatermarkTextBox` 和 `RadButton` 控件(Crystal 主题) - 提供静态 `Show()` 便捷方法,一行代码即可调用 ### 静态方法 | Static Method ```csharp public static string? Show( string prompt, // 提示文本 string title, // 窗口标题 string defaultValue = "", // 默认值 Func? validate = null, // 验证委托(可选) Window? owner = null // 父窗口(可选) ) ``` | 参数 | 类型 | 默认值 | 说明 | |---|---|---|---| | `prompt` | `string` | 必填 | 输入框上方的提示文本 | | `title` | `string` | 必填 | 窗口标题栏文本 | | `defaultValue` | `string` | `""` | 输入框的初始值 | | `validate` | `Func?` | `null` | 验证委托:返回 `null` 表示通过,返回错误信息则阻止确认 | | `owner` | `Window?` | `null` | 父窗口,设置后对话框居中于父窗口 | 返回值:用户输入的字符串,取消时返回 `null`。 ### 基本用法 | Basic Usage ```csharp using XP.Common.GeneralForm.Views; // 最简用法,无验证 var name = InputDialog.Show("请输入名称:", "新建项目"); if (name == null) return; // 用户取消 // 带默认值 var port = InputDialog.Show("请输入端口号:", "配置", "8080"); ``` ### 带验证的用法 | Usage with Validation ```csharp // 验证委托:返回 null 表示通过,返回错误信息则显示在输入框下方 var groupId = InputDialog.Show( "请输入 Group ID:", "新增 Group", validate: input => { if (string.IsNullOrWhiteSpace(input)) return "ID 不能为空"; if (existingIds.Contains(input)) return "ID 已存在,请使用不同的 ID"; return null; // 验证通过 }); // 验证非负整数 var dbNumber = InputDialog.Show( "请输入 DB 块号(非负整数):", "新增 Group", "0", validate: input => { if (!int.TryParse(input, out int val) || val < 0) return "必须为非负整数"; return null; }); ``` ### 注意事项 | Notes 1. `Show()` 必须在 UI 线程调用(内部使用 `ShowDialog()`) 2. 验证委托在用户点击确定按钮时执行,验证失败不会关闭对话框 3. 用户修改输入内容时会自动清除上一次的验证错误提示 4. 按钮文本从 XP.Common 资源文件读取(`Button_OK` / `Button_Cancel`),自动跟随应用语言