将Feature/XP.Common和Feature/XP.Hardware分支合并至Develop/XP.forHardwareAndCommon,完善XPapp注册和相关硬件类库通用类库功能。

This commit is contained in:
QI Mingxuan
2026-04-16 17:31:13 +08:00
parent 6ec4c3ddaa
commit 2bd6e566c3
581 changed files with 74600 additions and 222 deletions
@@ -0,0 +1,378 @@
# RaySourceOperateView 使用说明
## 概述
`RaySourceOperateView` 是射线源操作和监控面板,提供射线源开关控制、电压电流实时调节和状态监控功能。
## 架构设计
### MVVM 模式
- **View**: `RaySourceOperateView.xaml` - WPF 用户控件界面
- **ViewModel**: `RaySourceOperateViewModel.cs` - 视图模型,处理业务逻辑
- **Model**: `RaySourceStatus.cs` - 射线源状态枚举(Unavailable / Closed / Opened
### 依赖注入
ViewModel 通过构造函数注入以下依赖:
- `IRaySourceService` - 射线源业务服务
- `IEventAggregator` - Prism 事件聚合器
- `RaySourceConfig` - 射线源配置
- `ILoggerService` - 日志服务
- `ILocalizationService` - 多语言服务
## 功能特性
### 1. 状态监控
- **腰圆状态指示器**
- 灰色径向渐变 = 射线源不可用(Unavailable
- 绿色径向渐变 (#8BC34A#4CAF50) = 射线源已关闭(Closed
- 红色径向渐变 (#FF8A80#F44336) = 射线源已开启(Opened
- **呼吸闪烁动画**:射线源开启时,状态指示器播放呼吸闪烁动画(透明度 1.0 → 0.6 循环,周期约 1.5 秒)
- **实时状态文本**:通过 `ILocalizationService` 获取多语言状态文字
### 2. 射线源控制
- **开启射线源按钮**
- 仅在 Closed 状态、已初始化且变量已连接时可用
- 调用 `IRaySourceService.TurnOn()`
- 按钮文字通过多语言绑定:`{loc:Localization RaySource_TurnOnButton}`
- **关闭射线源按钮**
- 仅在 Opened 状态、已初始化且变量已连接时可用
- 调用 `IRaySourceService.TurnOff()`
- 按钮文字通过多语言绑定:`{loc:Localization RaySource_TurnOffButton}`
- **配置按钮**
- 打开 `RaySourceConfigWindow`(射线源配置窗口)
- 窗口已存在时激活而非重复创建
- **高级/设置按钮**
- 启动外部高级设置程序(`FXEControl.exe`
- 如果程序已运行则将窗口置前
- 使用 `ProcessHelper.StartOrActivate()` 实现
### 3. 电压调节
- **滑块范围**:从配置文件读取(默认 20-225 kV)
- **双向绑定**:滑块和数值输入框绑定同一属性 `VoltageValue`,使用 `Mode=TwoWay`
- **延迟拖拽**:滑块使用 `IsDeferredDraggingEnabled="True"`,松手时才提交值
- **手动提交**:通过 `ApplyVoltageCommand` 提交电压值到硬件(滑块松手/输入框失焦时触发)
- **启用条件**:仅在服务已初始化且变量已连接时可调节(`IsSlidersEnabled`
- **范围显示**:滑块下方显示最小值和最大值
- **实际值显示**:右上角显示当前实际电压值
### 4. 电流调节
- **滑块范围**:从配置文件读取(默认 10-1000 μA)
- **双向绑定**:滑块和数值输入框绑定同一属性 `CurrentValue`,使用 `Mode=TwoWay`
- **延迟拖拽**:滑块使用 `IsDeferredDraggingEnabled="True"`,松手时才提交值
- **手动提交**:通过 `ApplyCurrentCommand` 提交电流值到硬件
- **启用条件**:仅在服务已初始化且变量已连接时可调节(`IsSlidersEnabled`
- **范围显示**:滑块下方显示最小值和最大值
- **实际值显示**:右上角显示当前实际电流值
### 5. 自动初始化
- ViewModel 提供 `AutoInitializeAsync()` 方法
- 由 View 的 `Loaded` 事件触发,仅执行一次
- 异步执行 `InitializeAndConnectAsync()`(初始化 + 连接变量)
- 如果已初始化且变量已连接则跳过
## 关联视图:RaySourceConfigView
`RaySourceConfigView` 是射线源配置和设备状态监控面板,通过 `RaySourceConfigWindow` 包裹为独立窗口。
### ConfigView 功能
- **设备信息**:显示射线源类型和连接状态(颜色编码:灰色=未连接,橙色=已初始化,绿色=变量已连接)
- **操作按钮**:初始化 / 连接变量 / 断开(三列等宽布局)
- **设备状态面板**:暖机/真空/启动/自动定心/灯丝校准/射线开启/连锁/看门狗/TXI/功率模式
- **TXI 控制**TXI ON / TXI OFF 按钮
- **功率模式切换**High Power / Micro Focus 按钮
- **功能设置按钮**:暖机设置 / 训机设置 / 灯丝校准 / 自动定心(四列等宽布局,带确认对话框和进度条窗口)
- **灯丝寿命进度条**:显示灯丝使用百分比(60 秒定时刷新),颜色随百分比变化(绿/黄/红)
### ConfigView 依赖注入
- `IRaySourceService` - 射线源业务服务
- `IEventAggregator` - Prism 事件聚合器
- `RaySourceConfig` - 射线源配置
- `ILoggerService` - 日志服务
- `ILocalizationService` - 多语言服务
- `IFilamentLifetimeService` - 灯丝寿命管理服务
## 多语言支持
### XAML 中使用
```xml
xmlns:loc="clr-namespace:XP.Common.Localization.Extensions;assembly=XP.Common"
<TextBlock Text="{loc:Localization RaySource_VoltageLabel}"/>
<telerik:RadButton Content="{loc:Localization RaySource_TurnOnButton}"/>
```
### ViewModel 中使用
```csharp
_localizationService.GetString("RaySource_StatusClosed")
```
### 资源键列表
#### OperateView 资源键
| 资源键 | 中文 | 英文 |
|--------|------|------|
| RaySource_VoltageLabel | 电压(kV | Voltage (kV) |
| RaySource_CurrentLabel | 电流(μA | Current (μA) |
| RaySource_ActualValueLabel | 当前值: {0} | Actual: {0} |
| RaySource_TurnOnButton | 开启射线源 | Turn On X-Ray |
| RaySource_TurnOffButton | 关闭射线源 | Turn Off X-Ray |
| RaySource_AdvanceButton | 高级 | Advance |
| RaySource_ConfigButton | 配置 | Config |
| RaySource_StatusUnavailable | 射线源\n不可用 | X-Ray\nUnavailable |
| RaySource_StatusClosed | 射线源\n已关闭 | X-Ray\nClosed |
| RaySource_StatusOpened | 射线源\n已开启 | X-Ray\nOpened |
#### ConfigView 资源键
| 资源键 | 中文 | 英文 |
|--------|------|------|
| RaySource_SourceTypeLabel | 射线源类型 | Source Type |
| RaySource_InitializeButton | 初始化 | Initialize |
| RaySource_ConnectVariablesButton | 连接变量 | Connect Variables |
| RaySource_DisconnectButton | 断开 | Disconnect |
| RaySource_WarmUpLabel | 暖机 | Warm-up |
| RaySource_VacuumLabel | 真空 | Vacuum |
| RaySource_StartUpLabel | 启动 | Startup |
| RaySource_AutoCenterLabel | 自动定心 | Auto-center |
| RaySource_FilamentLabel | 灯丝校准 | Filament |
| RaySource_XRayOnLabel | 射线 | X-Ray |
| RaySource_InterlockLabel | 连锁 | Interlock |
| RaySource_WatchdogLabel | 看门狗 | Watchdog |
| RaySource_TxiStatusLabel | TXI | TXI |
| RaySource_TxiOnButton | TXI ON | TXI ON |
| RaySource_TxiOffButton | TXI OFF | TXI OFF |
| RaySource_PowerModeLabel | 功率模式 | Power Mode |
| RaySource_HighPowerButton | High Power | High Power |
| RaySource_MicroFocusButton | Micro Focus | Micro Focus |
| RaySource_WarmUpSettingButton | 暖机设置 | Warm-up |
| RaySource_TrainingSettingButton | 训机设置 | Training |
| RaySource_FilamentCalibrationButton | 灯丝校准 | Filament Cal. |
| RaySource_AutoCenterSettingButton | 自动定心 | Auto-center |
| RaySource_FilamentLifetimeLabel | 灯丝寿命 | Filament Life |
| RaySource_ConfigWindowTitle | 射线源配置 | X-Ray Source Config |
> 注意:多语言仅在应用启动时加载,无需运行时热切换。
## 呼吸闪烁动画
射线源开启时,状态指示器播放呼吸闪烁动画,增强视觉警示效果。
### 动画定义
```xml
<Storyboard x:Key="BreathingAnimation" RepeatBehavior="Forever">
<DoubleAnimation Storyboard.TargetProperty="Opacity"
From="1.0" To="0.6" Duration="0:0:0.75"
AutoReverse="True"/>
</Storyboard>
```
### 触发机制
通过 `DataTrigger` 监听 `RaySourceStatus` 属性:
- 当状态变为 `Opened` 时,自动开始动画
- 当状态离开 `Opened` 时,自动停止动画
## 事件订阅
### OperateViewModel 订阅事件
1. **RaySourceStatusChangedEvent**:射线源状态变更(三态)
- 更新 `RaySourceStatus` 属性和按钮/滑块启用状态
- 异常断联时重置变量连接状态
2. **StatusUpdatedEvent**:系统状态更新
- 更新实际电压和电流值(仅在值真正变化时更新,避免无意义赋值)
- 同步服务层权威状态
3. **ErrorOccurredEvent**:错误发生
- 显示错误消息对话框
4. **OperationResultEvent**:操作结果
- 操作失败时显示警告消息
5. **VariablesConnectedEvent**:变量连接状态变更
- 更新 `IsVariablesConnected` 属性
- 连接成功时主动读取最新设备状态
### ConfigViewModel 订阅事件
1. **RaySourceStatusChangedEvent**:刷新初始化状态和命令可执行状态
2. **StatusUpdatedEvent**:刷新设备状态面板所有字段
3. **VariablesConnectedEvent**:刷新连接状态和命令可执行状态
## 数据绑定
### OperateView 状态绑定
```xml
<!-- 状态指示器背景色(径向渐变)-->
Background="{Binding RaySourceStatus, Converter={StaticResource StatusToColorConverter}}"
<!-- 状态指示器边框色 -->
BorderBrush="{Binding RaySourceStatus, Converter={StaticResource StatusToBorderColorConverter}}"
<!-- 状态文本(多语言)-->
Text="{Binding StatusText}"
```
### OperateView 命令绑定
```xml
<telerik:RadButton Content="{loc:Localization RaySource_TurnOnButton}" Command="{Binding TurnOnCommand}"/>
<telerik:RadButton Content="{loc:Localization RaySource_TurnOffButton}" Command="{Binding TurnOffCommand}"/>
<telerik:RadButton Content="{loc:Localization RaySource_AdvanceButton}" Command="{Binding SettingsCommand}"/>
<telerik:RadButton Content="{loc:Localization RaySource_ConfigButton}" Command="{Binding ConfigCommand}"/>
```
### OperateView 滑块绑定
```xml
<!-- 电压滑块(延迟拖拽模式)-->
<telerik:RadSlider Minimum="{Binding VoltageMin}" Maximum="{Binding VoltageMax}"
Value="{Binding VoltageValue, Mode=TwoWay}"
IsDeferredDraggingEnabled="True"
IsEnabled="{Binding IsSlidersEnabled}"/>
<!-- 电压数值输入框 -->
<telerik:RadNumericUpDown Minimum="{Binding VoltageMin}" Maximum="{Binding VoltageMax}"
Value="{Binding VoltageValue, Mode=TwoWay}"
IsEnabled="{Binding IsSlidersEnabled}" NumberDecimalDigits="1"/>
```
## 转换器
### 1. RaySourceStatusToColorConverter
`RaySourceStatus` 枚举转换为径向渐变背景色:
- `Unavailable` → 灰色渐变(#E0E0E0#BDBDBD
- `Closed` → 绿色渐变(#8BC34A#4CAF50
- `Opened` → 红色渐变(#FF8A80#F44336
### 2. RaySourceStatusToBorderColorConverter
`RaySourceStatus` 枚举转换为边框色:
- `Unavailable`#9E9E9E
- `Closed`#2E7D32
- `Opened`#C62828
### 3. FilamentLifetimeColorConverter
将灯丝寿命百分比转换为进度条颜色:
- < 80% → 绿色 (#4CAF50)
- 80%-89% → 黄色 (#FFC107)
- ≥ 90% → 红色 (#E53935)
## 业务规则
### 安全规则
1. **未初始化禁止操作**:所有操作前检查 `IsInitialized``IsVariablesConnected`
2. **参数范围校验**:电压和电流值必须在配置的范围内
3. **操作失败回滚**:设置失败时恢复滑块到实际值(仅当实际值在有效范围内时)
4. **连接丢失处理**:连接丢失时状态设为 `Unavailable`,重置变量连接状态,禁用所有操作
5. **设备反馈保护**`IsUpdatingFromDevice` 标志防止设备反馈更新时误触发写入
### 状态管理
- 状态变更通过事件驱动,确保 UI 与硬件状态同步
- 使用 `RaisePropertyChanged` 通知 UI 更新
- 命令的 `CanExecute` 自动监听状态变化
- 三态管理:Unavailable → Closed → Opened
## 使用示例
### 在独立窗口中使用
```csharp
var raySourceView = _containerProvider.Resolve<RaySourceOperateView>();
var window = new Window
{
Title = "射线源操作",
Content = raySourceView,
SizeToContent = SizeToContent.WidthAndHeight,
ResizeMode = ResizeMode.NoResize,
WindowStartupLocation = WindowStartupLocation.CenterOwner,
Owner = Application.Current.MainWindow
};
window.ShowDialog();
```
### 在主窗口 Region 中加载
```xml
<ContentControl prism:RegionManager.RegionName="RaySourceOperateRegion" />
```
```csharp
_regionManager.RequestNavigate("RaySourceOperateRegion", "RaySourceOperateView");
```
## XAML 命名空间引用
```xml
xmlns:local="clr-namespace:XP.Hardware.RaySource.Views"
xmlns:converters="clr-namespace:XP.Hardware.RaySource.Converters"
xmlns:enums="clr-namespace:XP.Hardware.RaySource.Abstractions.Enums"
xmlns:loc="clr-namespace:XP.Common.Localization.Extensions;assembly=XP.Common"
xmlns:prism="http://prismlibrary.com/"
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
```
## 注意事项
1. **线程安全**:所有事件处理使用 `ThreadOption.UIThread` 确保在 UI 线程执行
2. **资源释放**ViewModel 实现 `IDisposable`,在 Dispose 时取消事件订阅、断开射线源连接、关闭配置窗口
3. **同步操作**:硬件操作为同步方法,ViewModel 中直接调用(不阻塞 UI 因为操作通过 IPC 快速返回)
4. **错误处理**:所有操作包含 try-catch,确保异常不会导致程序崩溃
5. **多语言**:所有界面文字通过 `{loc:Localization}``ILocalizationService` 获取,无硬编码文字
6. **动画性能**:呼吸闪烁动画使用 WPF Storyboard,性能开销极低
7. **日志规范**:使用 `_logger.ForModule("RaySource.ViewModel")` 和结构化日志消息
8. **自动初始化**OperateView 加载时自动执行 `AutoInitializeAsync()`,仅执行一次
9. **配置窗口**:通过 ConfigCommand 打开,单例模式(已存在时激活而非重复创建)
## 故障排查
### 按钮不可用
- 检查 `IsInitialized``IsVariablesConnected` 状态
- 检查 `RaySourceStatus` 是否正确
- 查看命令的 `CanExecute` 逻辑
### 滑块不可用
- 确认服务已初始化且变量已连接(`IsSlidersEnabled`
### 实际值不更新
- 确认已订阅 `StatusUpdatedEvent`
- 检查 Host 进程是否正常推送状态
- 验证 `ThreadOption.UIThread` 设置
### 设置值不生效
- 检查 `ApplyVoltageCommand` / `ApplyCurrentCommand` 是否正确触发
- 查看业务规则校验逻辑
- 确认 IPC 管道连接正常
### 多语言文字不显示
- 确认 XP.Common 资源文件中已添加对应的资源键
- 检查 XAML 中 `xmlns:loc` 命名空间引用是否正确
### 动画不播放
- 确认 `RaySourceStatus` 已变为 `Opened`
- 检查 `enums` 命名空间引用是否正确
### 状态显示为"不可用"
- 检查射线源服务连接状态
- 确认 Host 进程是否正常运行
- 查看日志中是否有连接丢失的警告信息
---
**最后更新 | Last Updated**: 2026-03-26