Files
XplorePlane/XP.Common/Documents/GeneralForm.README.md
T

248 lines
8.4 KiB
Markdown
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.
# 通用窗体使用指南 | 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<SomeService>()
?? 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<string, string?>`),验证失败时在输入框下方显示红色错误提示
- 输入内容变化时自动清除验证错误
- 使用 Telerik `RadWatermarkTextBox``RadButton` 控件(Crystal 主题)
- 提供静态 `Show()` 便捷方法,一行代码即可调用
### 静态方法 | Static Method
```csharp
public static string? Show(
string prompt, // 提示文本
string title, // 窗口标题
string defaultValue = "", // 默认值
Func<string, string?>? validate = null, // 验证委托(可选)
Window? owner = null // 父窗口(可选)
)
```
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| `prompt` | `string` | 必填 | 输入框上方的提示文本 |
| `title` | `string` | 必填 | 窗口标题栏文本 |
| `defaultValue` | `string` | `""` | 输入框的初始值 |
| `validate` | `Func<string, string?>?` | `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`),自动跟随应用语言