248 lines
8.4 KiB
Markdown
248 lines
8.4 KiB
Markdown
# 通用窗体使用指南 | 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`),自动跟随应用语言
|