1032 lines
30 KiB
Markdown
1032 lines
30 KiB
Markdown
# 探测器模块使用指南 | Detector Module Usage Guide
|
||
|
||
## 1. 模块概述 | Module Overview
|
||
|
||
XP.Hardware.Detector 是 XplorePlane X 射线检测系统的探测器控制模块,负责与工业 X 射线探测器进行通讯和控制。该模块采用策略模式设计,支持多种探测器型号的统一管理。
|
||
|
||
### 核心特性 | Key Features
|
||
|
||
- 支持多种探测器型号(Varex、iRay 等)
|
||
- 完整的探测器生命周期管理(初始化、采集、校正)
|
||
- 单帧和连续采集模式
|
||
- 自动校正功能(暗场、增益、坏像素)
|
||
- 实时状态监控
|
||
- 基于 Prism 事件聚合器的松耦合通讯
|
||
- 异步操作,不阻塞 UI 线程
|
||
|
||
---
|
||
|
||
## 2. 模块注册 | Module Registration
|
||
|
||
探测器模块通过 Prism 的模块化系统注册,在应用启动时自动加载。
|
||
|
||
### 在 App.xaml.cs 中注册
|
||
|
||
```csharp
|
||
using Prism.Modularity;
|
||
using XP.Hardware.Detector.Module;
|
||
|
||
protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
|
||
{
|
||
// 注册探测器模块 | Register Detector module
|
||
moduleCatalog.AddModule<DetectorModule>();
|
||
|
||
base.ConfigureModuleCatalog(moduleCatalog);
|
||
}
|
||
```
|
||
|
||
### 模块自动注册的服务
|
||
|
||
- `IDetectorFactory` - 探测器工厂(瞬态)
|
||
- `IDetectorService` - 探测器业务服务(单例)
|
||
|
||
---
|
||
|
||
## 3. 配置文件设置 | Configuration File Setup
|
||
|
||
在 `App.config` 中添加探测器配置:
|
||
|
||
```xml
|
||
<?xml version="1.0" encoding="utf-8" ?>
|
||
<configuration>
|
||
<appSettings>
|
||
<!-- 探测器类型 | Detector Type -->
|
||
<add key="Detector:Type" value="Varex" />
|
||
|
||
<!-- 网络配置 | Network Configuration -->
|
||
<add key="Detector:IP" value="192.168.1.200" />
|
||
<add key="Detector:Port" value="50000" />
|
||
|
||
<!-- 图像存储配置 | Image Storage Configuration -->
|
||
<add key="Detector:SavePath" value="D:\Images" />
|
||
<add key="Detector:AutoSave" value="true" />
|
||
|
||
<!-- Varex 探测器特定配置 | Varex Detector Specific Configuration -->
|
||
<add key="Varex:ConfigFile" value="detector.xml" />
|
||
<add key="Varex:CalibrationFile" value="calibration.cal" />
|
||
|
||
<!-- iRay 探测器特定配置 | iRay Detector Specific Configuration -->
|
||
<add key="IRay:DeviceID" value="0" />
|
||
<add key="IRay:ExposureTime" value="100" />
|
||
</appSettings>
|
||
</configuration>
|
||
```
|
||
|
||
### 配置参数说明
|
||
|
||
| 参数 | 类型 | 默认值 | 说明 |
|
||
|------|------|--------|------|
|
||
| Type | string | Varex | 探测器类型(Varex/IRay)|
|
||
| IP | string | 192.168.1.200 | 探测器 IP 地址 |
|
||
| Port | int | 50000 | 探测器端口号 |
|
||
| SavePath | string | D:\Images | 图像存储路径 |
|
||
| AutoSave | bool | true | 是否自动保存图像 |
|
||
|
||
---
|
||
## 4. 在 ViewModel 中使用 | Usage in ViewModel
|
||
|
||
### 4.1 注入服务
|
||
|
||
```csharp
|
||
using Prism.Commands;
|
||
using Prism.Events;
|
||
using Prism.Mvvm;
|
||
using System.Threading.Tasks;
|
||
using XP.Common.Logging.Interfaces;
|
||
using XP.Hardware.Detector.Abstractions;
|
||
using XP.Hardware.Detector.Abstractions.Enums;
|
||
using XP.Hardware.Detector.Abstractions.Events;
|
||
using XP.Hardware.Detector.Services;
|
||
|
||
namespace YourNamespace.ViewModels
|
||
{
|
||
public class YourViewModel : BindableBase
|
||
{
|
||
private readonly IDetectorService _detectorService;
|
||
private readonly IEventAggregator _eventAggregator;
|
||
private readonly ILoggerService _logger;
|
||
|
||
/// <summary>
|
||
/// 构造函数,通过依赖注入获取服务 | Constructor with dependency injection
|
||
/// </summary>
|
||
public YourViewModel(
|
||
IDetectorService detectorService,
|
||
IEventAggregator eventAggregator,
|
||
ILoggerService logger)
|
||
{
|
||
_detectorService = detectorService;
|
||
_eventAggregator = eventAggregator;
|
||
_logger = logger.ForModule("YourViewModel");
|
||
|
||
// 订阅事件 | Subscribe to events
|
||
SubscribeEvents();
|
||
}
|
||
|
||
private void SubscribeEvents()
|
||
{
|
||
// 订阅图像采集事件 | Subscribe to image captured event
|
||
_eventAggregator.GetEvent<ImageCapturedEvent>()
|
||
.Subscribe(OnImageCaptured);
|
||
|
||
// 订阅校正完成事件 | Subscribe to correction completed event
|
||
_eventAggregator.GetEvent<CorrectionCompletedEvent>()
|
||
.Subscribe(OnCorrectionCompleted);
|
||
}
|
||
|
||
private void OnImageCaptured(ImageCapturedEventArgs args)
|
||
{
|
||
_logger.Info($"图像已采集: {args.FrameNumber}");
|
||
}
|
||
|
||
private void OnCorrectionCompleted(CorrectionCompletedEventArgs args)
|
||
{
|
||
_logger.Info($"校正完成: {args.CorrectionType}");
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 4.2 初始化探测器
|
||
|
||
```csharp
|
||
/// <summary>
|
||
/// 初始化探测器 | Initialize detector
|
||
/// </summary>
|
||
public async Task InitializeDetectorAsync()
|
||
{
|
||
try
|
||
{
|
||
_logger.Info("开始初始化探测器... | Starting detector initialization...");
|
||
StatusMessage = "正在初始化... | Initializing...";
|
||
|
||
DetectorResult result = await _detectorService.InitializeAsync();
|
||
|
||
if (result.IsSuccess)
|
||
{
|
||
_logger.Info("探测器初始化成功 | Detector initialized successfully");
|
||
StatusMessage = "探测器已就绪 | Detector ready";
|
||
|
||
// 获取探测器信息 | Get detector information
|
||
DetectorInfo info = _detectorService.GetInfo();
|
||
_logger.Info($"探测器型号: {info.Model}, 分辨率: {info.MaxWidth}x{info.MaxHeight}");
|
||
}
|
||
else
|
||
{
|
||
_logger.Error(null, $"探测器初始化失败: {result.ErrorMessage}");
|
||
StatusMessage = $"初始化失败: {result.ErrorMessage}";
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.Error(ex, $"初始化异常: {ex.Message}");
|
||
StatusMessage = $"初始化异常: {ex.Message}";
|
||
}
|
||
}
|
||
```
|
||
|
||
### 4.3 单帧采集
|
||
|
||
```csharp
|
||
/// <summary>
|
||
/// 单帧采集 | Single frame acquisition
|
||
/// </summary>
|
||
public async Task AcquireSingleFrameAsync()
|
||
{
|
||
try
|
||
{
|
||
if (_detectorService.Status != DetectorStatus.Ready)
|
||
{
|
||
_logger.Warn("探测器未就绪,无法采集");
|
||
StatusMessage = "探测器未就绪 | Detector not ready";
|
||
return;
|
||
}
|
||
|
||
_logger.Info("开始单帧采集... | Starting single frame acquisition...");
|
||
StatusMessage = "正在采集... | Acquiring...";
|
||
|
||
DetectorResult result = await _detectorService.AcquireSingleFrameAsync();
|
||
|
||
if (result.IsSuccess)
|
||
{
|
||
_logger.Info("单帧采集成功 | Single frame acquired successfully");
|
||
StatusMessage = "采集完成 | Acquisition completed";
|
||
}
|
||
else
|
||
{
|
||
_logger.Error(null, $"单帧采集失败: {result.ErrorMessage}");
|
||
StatusMessage = $"采集失败: {result.ErrorMessage}";
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.Error(ex, $"单帧采集异常: {ex.Message}");
|
||
StatusMessage = $"采集异常: {ex.Message}";
|
||
}
|
||
}
|
||
```
|
||
|
||
### 4.4 启动连续采集
|
||
|
||
```csharp
|
||
/// <summary>
|
||
/// 启动连续采集 | Start continuous acquisition
|
||
/// </summary>
|
||
public async Task StartAcquisitionAsync()
|
||
{
|
||
try
|
||
{
|
||
if (_detectorService.Status != DetectorStatus.Ready)
|
||
{
|
||
_logger.Warn("探测器未就绪,无法启动采集");
|
||
return;
|
||
}
|
||
|
||
_logger.Info("启动连续采集... | Starting continuous acquisition...");
|
||
StatusMessage = "连续采集中... | Continuous acquisition...";
|
||
|
||
DetectorResult result = await _detectorService.StartAcquisitionAsync();
|
||
|
||
if (result.IsSuccess)
|
||
{
|
||
_logger.Info("连续采集已启动 | Continuous acquisition started");
|
||
IsAcquiring = true;
|
||
}
|
||
else
|
||
{
|
||
_logger.Error(null, $"启动采集失败: {result.ErrorMessage}");
|
||
StatusMessage = $"启动失败: {result.ErrorMessage}";
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.Error(ex, $"启动采集异常: {ex.Message}");
|
||
StatusMessage = $"启动异常: {ex.Message}";
|
||
}
|
||
}
|
||
```
|
||
|
||
### 4.5 停止采集
|
||
|
||
```csharp
|
||
/// <summary>
|
||
/// 停止采集 | Stop acquisition
|
||
/// </summary>
|
||
public async Task StopAcquisitionAsync()
|
||
{
|
||
try
|
||
{
|
||
_logger.Info("停止采集... | Stopping acquisition...");
|
||
StatusMessage = "正在停止... | Stopping...";
|
||
|
||
DetectorResult result = await _detectorService.StopAcquisitionAsync();
|
||
|
||
if (result.IsSuccess)
|
||
{
|
||
_logger.Info("采集已停止 | Acquisition stopped");
|
||
StatusMessage = "已停止 | Stopped";
|
||
IsAcquiring = false;
|
||
}
|
||
else
|
||
{
|
||
_logger.Error(null, $"停止采集失败: {result.ErrorMessage}");
|
||
StatusMessage = $"停止失败: {result.ErrorMessage}";
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.Error(ex, $"停止采集异常: {ex.Message}");
|
||
StatusMessage = $"停止异常: {ex.Message}";
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
## 5. 校正功能 | Correction Functions
|
||
|
||
### 5.1 自动校正
|
||
|
||
```csharp
|
||
/// <summary>
|
||
/// 执行自动校正(暗场+增益+坏像素)| Execute auto correction (dark + gain + bad pixel)
|
||
/// </summary>
|
||
/// <param name="frameCount">采集帧数 | Frame count</param>
|
||
public async Task AutoCorrectionAsync(int frameCount = 10)
|
||
{
|
||
try
|
||
{
|
||
_logger.Info($"开始自动校正,帧数: {frameCount} | Starting auto correction, frames: {frameCount}");
|
||
StatusMessage = "正在校正... | Correcting...";
|
||
|
||
DetectorResult result = await _detectorService.AutoCorrectionAsync(frameCount);
|
||
|
||
if (result.IsSuccess)
|
||
{
|
||
_logger.Info("自动校正完成 | Auto correction completed");
|
||
StatusMessage = "校正完成 | Correction completed";
|
||
}
|
||
else
|
||
{
|
||
_logger.Error(null, $"自动校正失败: {result.ErrorMessage}");
|
||
StatusMessage = $"校正失败: {result.ErrorMessage}";
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.Error(ex, $"自动校正异常: {ex.Message}");
|
||
StatusMessage = $"校正异常: {ex.Message}";
|
||
}
|
||
}
|
||
```
|
||
|
||
### 5.2 获取探测器信息
|
||
|
||
```csharp
|
||
/// <summary>
|
||
/// 获取探测器信息 | Get detector information
|
||
/// </summary>
|
||
public void GetDetectorInfo()
|
||
{
|
||
try
|
||
{
|
||
DetectorInfo info = _detectorService.GetInfo();
|
||
|
||
if (info != null)
|
||
{
|
||
_logger.Info($"探测器信息:");
|
||
_logger.Info($" 型号: {info.Model}");
|
||
_logger.Info($" 序列号: {info.SerialNumber}");
|
||
_logger.Info($" 固件版本: {info.FirmwareVersion}");
|
||
_logger.Info($" 分辨率: {info.MaxWidth}x{info.MaxHeight}");
|
||
_logger.Info($" 像素尺寸: {info.PixelSize}μm");
|
||
_logger.Info($" 位深度: {info.BitDepth}bit");
|
||
|
||
// 更新 UI 显示 | Update UI display
|
||
DetectorModel = info.Model;
|
||
Resolution = $"{info.MaxWidth}x{info.MaxHeight}";
|
||
PixelSize = $"{info.PixelSize}μm";
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.Error(ex, $"获取探测器信息异常: {ex.Message}");
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 6. Prism 事件通讯 | Prism Event Communication
|
||
|
||
模块使用 Prism 事件聚合器实现跨模块通讯,支持以下事件:
|
||
|
||
### 6.1 图像采集事件
|
||
|
||
```csharp
|
||
// 订阅图像采集事件 | Subscribe to image captured event
|
||
_eventAggregator.GetEvent<ImageCapturedEvent>()
|
||
.Subscribe(OnImageCaptured, ThreadOption.UIThread);
|
||
|
||
private void OnImageCaptured(ImageCapturedEventArgs args)
|
||
{
|
||
// args.FrameNumber - 帧编号
|
||
// args.Timestamp - 时间戳
|
||
// args.ImageData - 图像数据(如果有)
|
||
|
||
FrameNumber = args.FrameNumber;
|
||
LastCaptureTime = args.Timestamp;
|
||
|
||
_logger.Info($"图像已采集: 帧 {args.FrameNumber}");
|
||
}
|
||
```
|
||
|
||
### 6.2 校正完成事件
|
||
|
||
```csharp
|
||
// 订阅校正完成事件 | Subscribe to correction completed event
|
||
_eventAggregator.GetEvent<CorrectionCompletedEvent>()
|
||
.Subscribe(OnCorrectionCompleted, ThreadOption.UIThread);
|
||
|
||
private void OnCorrectionCompleted(CorrectionCompletedEventArgs args)
|
||
{
|
||
// args.CorrectionType - 校正类型(暗场/增益/坏像素)
|
||
// args.IsSuccess - 是否成功
|
||
// args.Message - 消息
|
||
|
||
if (args.IsSuccess)
|
||
{
|
||
_logger.Info($"校正完成: {args.CorrectionType}");
|
||
StatusMessage = $"{args.CorrectionType} 校正完成";
|
||
}
|
||
else
|
||
{
|
||
_logger.Error(null, $"校正失败: {args.Message}");
|
||
StatusMessage = $"校正失败: {args.Message}";
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 7. 完整示例 | Complete Example
|
||
|
||
```csharp
|
||
using Prism.Commands;
|
||
using Prism.Events;
|
||
using Prism.Mvvm;
|
||
using System;
|
||
using System.Threading.Tasks;
|
||
using System.Windows.Input;
|
||
using XP.Common.Logging.Interfaces;
|
||
using XP.Hardware.Detector.Abstractions;
|
||
using XP.Hardware.Detector.Abstractions.Enums;
|
||
using XP.Hardware.Detector.Abstractions.Events;
|
||
using XP.Hardware.Detector.Services;
|
||
|
||
namespace YourNamespace.ViewModels
|
||
{
|
||
public class DetectorControlViewModel : BindableBase
|
||
{
|
||
private readonly IDetectorService _detectorService;
|
||
private readonly IEventAggregator _eventAggregator;
|
||
private readonly ILoggerService _logger;
|
||
|
||
#region 属性 | Properties
|
||
|
||
private string _statusMessage;
|
||
public string StatusMessage
|
||
{
|
||
get => _statusMessage;
|
||
set => SetProperty(ref _statusMessage, value);
|
||
}
|
||
|
||
private DetectorStatus _detectorStatus;
|
||
public DetectorStatus DetectorStatus
|
||
{
|
||
get => _detectorStatus;
|
||
set => SetProperty(ref _detectorStatus, value);
|
||
}
|
||
|
||
private bool _isAcquiring;
|
||
public bool IsAcquiring
|
||
{
|
||
get => _isAcquiring;
|
||
set => SetProperty(ref _isAcquiring, value);
|
||
}
|
||
|
||
private int _frameNumber;
|
||
public int FrameNumber
|
||
{
|
||
get => _frameNumber;
|
||
set => SetProperty(ref _frameNumber, value);
|
||
}
|
||
|
||
private string _detectorModel;
|
||
public string DetectorModel
|
||
{
|
||
get => _detectorModel;
|
||
set => SetProperty(ref _detectorModel, value);
|
||
}
|
||
|
||
private string _resolution;
|
||
public string Resolution
|
||
{
|
||
get => _resolution;
|
||
set => SetProperty(ref _resolution, value);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 命令 | Commands
|
||
|
||
public ICommand InitializeCommand { get; }
|
||
public ICommand AcquireSingleFrameCommand { get; }
|
||
public ICommand StartAcquisitionCommand { get; }
|
||
public ICommand StopAcquisitionCommand { get; }
|
||
public ICommand AutoCorrectionCommand { get; }
|
||
public ICommand GetInfoCommand { get; }
|
||
|
||
#endregion
|
||
|
||
public DetectorControlViewModel(
|
||
IDetectorService detectorService,
|
||
IEventAggregator eventAggregator,
|
||
ILoggerService logger)
|
||
{
|
||
_detectorService = detectorService;
|
||
_eventAggregator = eventAggregator;
|
||
_logger = logger.ForModule("DetectorControlViewModel");
|
||
|
||
// 初始化命令 | Initialize commands
|
||
InitializeCommand = new DelegateCommand(async () => await InitializeAsync());
|
||
AcquireSingleFrameCommand = new DelegateCommand(async () => await AcquireSingleFrameAsync(), CanAcquire)
|
||
.ObservesProperty(() => DetectorStatus);
|
||
StartAcquisitionCommand = new DelegateCommand(async () => await StartAcquisitionAsync(), CanStartAcquisition)
|
||
.ObservesProperty(() => DetectorStatus)
|
||
.ObservesProperty(() => IsAcquiring);
|
||
StopAcquisitionCommand = new DelegateCommand(async () => await StopAcquisitionAsync(), CanStopAcquisition)
|
||
.ObservesProperty(() => IsAcquiring);
|
||
AutoCorrectionCommand = new DelegateCommand(async () => await AutoCorrectionAsync(), CanCorrect)
|
||
.ObservesProperty(() => DetectorStatus);
|
||
GetInfoCommand = new DelegateCommand(GetInfo);
|
||
|
||
// 订阅事件 | Subscribe to events
|
||
SubscribeEvents();
|
||
}
|
||
|
||
#region 命令实现 | Command Implementations
|
||
|
||
private async Task InitializeAsync()
|
||
{
|
||
try
|
||
{
|
||
StatusMessage = "正在初始化... | Initializing...";
|
||
DetectorResult result = await _detectorService.InitializeAsync();
|
||
|
||
if (result.IsSuccess)
|
||
{
|
||
DetectorStatus = _detectorService.Status;
|
||
StatusMessage = "探测器已就绪 | Detector ready";
|
||
GetInfo();
|
||
}
|
||
else
|
||
{
|
||
StatusMessage = $"初始化失败: {result.ErrorMessage}";
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.Error(ex, "初始化异常");
|
||
StatusMessage = $"初始化异常: {ex.Message}";
|
||
}
|
||
}
|
||
|
||
private async Task AcquireSingleFrameAsync()
|
||
{
|
||
try
|
||
{
|
||
StatusMessage = "正在采集... | Acquiring...";
|
||
DetectorResult result = await _detectorService.AcquireSingleFrameAsync();
|
||
|
||
if (result.IsSuccess)
|
||
{
|
||
StatusMessage = "采集完成 | Acquisition completed";
|
||
}
|
||
else
|
||
{
|
||
StatusMessage = $"采集失败: {result.ErrorMessage}";
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.Error(ex, "单帧采集异常");
|
||
StatusMessage = $"采集异常: {ex.Message}";
|
||
}
|
||
}
|
||
|
||
private async Task StartAcquisitionAsync()
|
||
{
|
||
try
|
||
{
|
||
StatusMessage = "启动连续采集... | Starting continuous acquisition...";
|
||
DetectorResult result = await _detectorService.StartAcquisitionAsync();
|
||
|
||
if (result.IsSuccess)
|
||
{
|
||
IsAcquiring = true;
|
||
DetectorStatus = _detectorService.Status;
|
||
StatusMessage = "连续采集中... | Continuous acquisition...";
|
||
}
|
||
else
|
||
{
|
||
StatusMessage = $"启动失败: {result.ErrorMessage}";
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.Error(ex, "启动采集异常");
|
||
StatusMessage = $"启动异常: {ex.Message}";
|
||
}
|
||
}
|
||
|
||
private async Task StopAcquisitionAsync()
|
||
{
|
||
try
|
||
{
|
||
StatusMessage = "正在停止... | Stopping...";
|
||
DetectorResult result = await _detectorService.StopAcquisitionAsync();
|
||
|
||
if (result.IsSuccess)
|
||
{
|
||
IsAcquiring = false;
|
||
DetectorStatus = _detectorService.Status;
|
||
StatusMessage = "已停止 | Stopped";
|
||
}
|
||
else
|
||
{
|
||
StatusMessage = $"停止失败: {result.ErrorMessage}";
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.Error(ex, "停止采集异常");
|
||
StatusMessage = $"停止异常: {ex.Message}";
|
||
}
|
||
}
|
||
|
||
private async Task AutoCorrectionAsync()
|
||
{
|
||
try
|
||
{
|
||
StatusMessage = "正在校正... | Correcting...";
|
||
DetectorResult result = await _detectorService.AutoCorrectionAsync(10);
|
||
|
||
if (result.IsSuccess)
|
||
{
|
||
StatusMessage = "校正完成 | Correction completed";
|
||
}
|
||
else
|
||
{
|
||
StatusMessage = $"校正失败: {result.ErrorMessage}";
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.Error(ex, "自动校正异常");
|
||
StatusMessage = $"校正异常: {ex.Message}";
|
||
}
|
||
}
|
||
|
||
private void GetInfo()
|
||
{
|
||
try
|
||
{
|
||
DetectorInfo info = _detectorService.GetInfo();
|
||
if (info != null)
|
||
{
|
||
DetectorModel = info.Model;
|
||
Resolution = $"{info.MaxWidth}x{info.MaxHeight}";
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.Error(ex, "获取信息异常");
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 命令条件 | Command Conditions
|
||
|
||
private bool CanAcquire() => DetectorStatus == DetectorStatus.Ready;
|
||
private bool CanStartAcquisition() => DetectorStatus == DetectorStatus.Ready && !IsAcquiring;
|
||
private bool CanStopAcquisition() => IsAcquiring;
|
||
private bool CanCorrect() => DetectorStatus == DetectorStatus.Ready;
|
||
|
||
#endregion
|
||
|
||
#region 事件处理 | Event Handlers
|
||
|
||
private void SubscribeEvents()
|
||
{
|
||
_eventAggregator.GetEvent<ImageCapturedEvent>()
|
||
.Subscribe(OnImageCaptured, ThreadOption.UIThread);
|
||
|
||
_eventAggregator.GetEvent<CorrectionCompletedEvent>()
|
||
.Subscribe(OnCorrectionCompleted, ThreadOption.UIThread);
|
||
}
|
||
|
||
private void OnImageCaptured(ImageCapturedEventArgs args)
|
||
{
|
||
FrameNumber = args.FrameNumber;
|
||
}
|
||
|
||
private void OnCorrectionCompleted(CorrectionCompletedEventArgs args)
|
||
{
|
||
if (args.IsSuccess)
|
||
{
|
||
StatusMessage = $"{args.CorrectionType} 校正完成";
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
## 8. 在应用退出时释放资源 | Release Resources on Application Exit
|
||
|
||
在 `App.xaml.cs` 的 `OnExit` 方法中添加:
|
||
|
||
```csharp
|
||
protected override void OnExit(ExitEventArgs e)
|
||
{
|
||
// 记录应用退出日志 | Log application exit
|
||
Log.Information("XplorePlane主应用退出(XP.App-OnExit)");
|
||
|
||
// 释放探测器资源 | Release detector resources
|
||
try
|
||
{
|
||
var detectorService = Container.Resolve<IDetectorService>();
|
||
// 探测器服务会在 Dispose 时自动停止采集和释放资源
|
||
// Detector service will automatically stop acquisition and release resources on Dispose
|
||
Log.Information("探测器资源已成功释放 | Detector resources released successfully");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Log.Error(ex, "探测器资源释放失败,忽略该错误继续退出 | Failed to release detector resources");
|
||
}
|
||
|
||
// 释放其他资源... | Release other resources...
|
||
|
||
// 释放Serilog资源(避免日志丢失)| Release Serilog resources
|
||
Log.CloseAndFlush();
|
||
|
||
base.OnExit(e);
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 9. 探测器状态 | Detector Status
|
||
|
||
### 9.1 状态枚举
|
||
|
||
```csharp
|
||
public enum DetectorStatus
|
||
{
|
||
Uninitialized = 0, // 未初始化
|
||
Initializing = 1, // 初始化中
|
||
Ready = 2, // 就绪
|
||
Acquiring = 3, // 采集中
|
||
Correcting = 4, // 校正中
|
||
Error = 5 // 错误
|
||
}
|
||
```
|
||
|
||
### 9.2 状态监控
|
||
|
||
```csharp
|
||
// 监控探测器状态变化 | Monitor detector status changes
|
||
private void MonitorStatus()
|
||
{
|
||
DetectorStatus currentStatus = _detectorService.Status;
|
||
|
||
switch (currentStatus)
|
||
{
|
||
case DetectorStatus.Uninitialized:
|
||
StatusMessage = "未初始化 | Uninitialized";
|
||
break;
|
||
case DetectorStatus.Initializing:
|
||
StatusMessage = "初始化中... | Initializing...";
|
||
break;
|
||
case DetectorStatus.Ready:
|
||
StatusMessage = "就绪 | Ready";
|
||
break;
|
||
case DetectorStatus.Acquiring:
|
||
StatusMessage = "采集中... | Acquiring...";
|
||
break;
|
||
case DetectorStatus.Correcting:
|
||
StatusMessage = "校正中... | Correcting...";
|
||
break;
|
||
case DetectorStatus.Error:
|
||
StatusMessage = "错误 | Error";
|
||
// 获取错误信息 | Get error information
|
||
DetectorResult error = _detectorService.GetLastError();
|
||
_logger.Error(null, $"探测器错误: {error.ErrorMessage}");
|
||
break;
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 10. 异常处理 | Exception Handling
|
||
|
||
### 10.1 DetectorResult 结果处理
|
||
|
||
所有操作返回 `DetectorResult` 对象:
|
||
|
||
```csharp
|
||
DetectorResult result = await _detectorService.InitializeAsync();
|
||
|
||
if (result.IsSuccess)
|
||
{
|
||
// 操作成功 | Operation successful
|
||
_logger.Info("操作成功");
|
||
}
|
||
else
|
||
{
|
||
// 操作失败 | Operation failed
|
||
string error = result.ErrorMessage;
|
||
int errorCode = result.ErrorCode;
|
||
Exception exception = result.Exception;
|
||
|
||
_logger.Error(exception, $"操作失败: {error}, 错误码: {errorCode}");
|
||
}
|
||
```
|
||
|
||
### 10.2 异常捕获
|
||
|
||
```csharp
|
||
try
|
||
{
|
||
DetectorResult result = await _detectorService.AcquireSingleFrameAsync();
|
||
// 处理结果 | Process result
|
||
}
|
||
catch (TimeoutException ex)
|
||
{
|
||
// 超时异常 | Timeout exception
|
||
_logger.Error(ex, "操作超时");
|
||
MessageBox.Show("操作超时,请检查探测器连接", "超时",
|
||
MessageBoxButton.OK, MessageBoxImage.Warning);
|
||
}
|
||
catch (InvalidOperationException ex)
|
||
{
|
||
// 无效操作异常 | Invalid operation exception
|
||
_logger.Error(ex, "无效操作");
|
||
MessageBox.Show($"无效操作: {ex.Message}", "错误",
|
||
MessageBoxButton.OK, MessageBoxImage.Error);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
// 其他异常 | Other exceptions
|
||
_logger.Error(ex, "未知错误");
|
||
MessageBox.Show($"发生错误: {ex.Message}", "错误",
|
||
MessageBoxButton.OK, MessageBoxImage.Error);
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 11. 日志记录 | Logging
|
||
|
||
模块使用 Serilog 进行结构化日志记录:
|
||
|
||
### 11.1 日志级别
|
||
|
||
- **Debug**: 详细的调试信息(帧采集、状态变化等)
|
||
- **Info**: 一般信息(初始化成功、采集开始等)
|
||
- **Warn**: 警告信息(状态异常、参数警告等)
|
||
- **Error**: 错误信息(操作失败、通讯异常等)
|
||
- **Fatal**: 致命错误(系统崩溃等)
|
||
|
||
### 11.2 日志示例
|
||
|
||
```csharp
|
||
// 信息日志 | Info log
|
||
_logger.Info("探测器初始化成功 | Detector initialized successfully");
|
||
|
||
// 警告日志 | Warning log
|
||
_logger.Warn("探测器未就绪 | Detector not ready");
|
||
|
||
// 错误日志 | Error log
|
||
_logger.Error(ex, $"操作失败: {ex.Message} | Operation failed: {ex.Message}");
|
||
|
||
// 调试日志 | Debug log
|
||
_logger.Debug($"采集帧 {frameNumber} | Acquired frame {frameNumber}");
|
||
```
|
||
|
||
---
|
||
|
||
## 12. 性能优化建议 | Performance Optimization Suggestions
|
||
|
||
### 12.1 图像处理
|
||
|
||
避免在 UI 线程处理大图像:
|
||
|
||
```csharp
|
||
// 推荐:在后台线程处理图像 | Recommended: Process images in background thread
|
||
await Task.Run(() =>
|
||
{
|
||
// 图像处理逻辑 | Image processing logic
|
||
ProcessImage(imageData);
|
||
});
|
||
```
|
||
|
||
### 12.2 异步操作
|
||
|
||
所有 I/O 操作使用异步方法:
|
||
|
||
```csharp
|
||
// 正确:异步操作 | Correct: Async operation
|
||
await _detectorService.AcquireSingleFrameAsync();
|
||
|
||
// 错误:同步阻塞 | Wrong: Synchronous blocking
|
||
_detectorService.AcquireSingleFrameAsync().Wait(); // 不要这样做!
|
||
```
|
||
|
||
### 12.3 事件订阅
|
||
|
||
及时取消不再需要的事件订阅:
|
||
|
||
```csharp
|
||
// 保存订阅令牌 | Save subscription token
|
||
private SubscriptionToken _imageCapturedToken;
|
||
|
||
// 订阅事件 | Subscribe to event
|
||
_imageCapturedToken = _eventAggregator.GetEvent<ImageCapturedEvent>()
|
||
.Subscribe(OnImageCaptured, ThreadOption.UIThread);
|
||
|
||
// 取消订阅 | Unsubscribe
|
||
_eventAggregator.GetEvent<ImageCapturedEvent>()
|
||
.Unsubscribe(_imageCapturedToken);
|
||
```
|
||
|
||
---
|
||
|
||
## 13. 故障排查 | Troubleshooting
|
||
|
||
### 13.1 初始化失败
|
||
|
||
**问题**: 探测器初始化失败
|
||
|
||
**可能原因**:
|
||
- 探测器 IP 地址或端口配置错误
|
||
- 探测器未启动或网络不通
|
||
- 探测器驱动未正确安装
|
||
- 配置文件参数错误
|
||
|
||
**解决方案**:
|
||
1. 检查 `App.config` 中的探测器连接参数
|
||
2. 使用 `ping` 命令测试探测器网络连接
|
||
3. 确认探测器驱动和 SDK 已安装
|
||
4. 查看日志文件获取详细错误信息
|
||
|
||
### 13.2 采集失败
|
||
|
||
**问题**: 无法采集图像
|
||
|
||
**可能原因**:
|
||
- 探测器未初始化
|
||
- 探测器处于错误状态
|
||
- 校正未完成
|
||
- 网络通讯异常
|
||
|
||
**解决方案**:
|
||
1. 确认已调用 `InitializeAsync()` 并成功
|
||
2. 检查探测器状态是否为 `Ready`
|
||
3. 执行自动校正 `AutoCorrectionAsync()`
|
||
4. 检查网络连接和通讯日志
|
||
|
||
### 13.3 校正失败
|
||
|
||
**问题**: 校正操作失败
|
||
|
||
**可能原因**:
|
||
- 探测器未就绪
|
||
- 射线源未开启(增益校正需要)
|
||
- 采集帧数不足
|
||
- 环境光干扰
|
||
|
||
**解决方案**:
|
||
1. 确认探测器状态为 `Ready`
|
||
2. 增益校正前确保射线源已开启
|
||
3. 增加采集帧数(建议 10 帧以上)
|
||
4. 检查暗场环境,避免光线干扰
|
||
|
||
### 13.4 通讯超时
|
||
|
||
**问题**: 操作超时
|
||
|
||
**可能原因**:
|
||
- 网络延迟过高
|
||
- 探测器响应慢
|
||
- 超时配置过短
|
||
|
||
**解决方案**:
|
||
1. 检查网络连接质量
|
||
2. 增加配置文件中的超时时间
|
||
3. 检查探测器负载情况
|
||
|
||
---
|
||
|
||
## 14. 注意事项 | Notes
|
||
|
||
1. **线程安全**: `IDetectorService` 是单例,多个 ViewModel 共享同一个实例
|
||
2. **异步操作**: 所有操作都是异步的,避免阻塞 UI 线程
|
||
3. **状态检查**: 操作前检查探测器状态,确保处于正确状态
|
||
4. **资源释放**: 应用退出时探测器会自动停止采集并释放资源
|
||
5. **事件订阅**: 记得在 ViewModel 销毁时取消事件订阅
|
||
6. **校正顺序**: 建议按照暗场→增益→坏像素的顺序进行校正
|
||
7. **日志记录**: 所有关键操作都有详细的日志记录
|
||
8. **错误处理**: 始终检查 `DetectorResult.IsSuccess` 并处理错误
|
||
|
||
---
|
||
|
||
## 15. 文档索引 | Documentation Index
|
||
|
||
- **[GUIDENCE.md](./GUIDENCE.md)** - 本文档,详细使用指南
|
||
- **[README.md](./README.md)** - 项目概述和快速参考
|
||
- **[App.config.example](./App.config.example)** - 配置文件示例
|
||
|
||
---
|
||
|
||
## 16. 技术支持 | Technical Support
|
||
|
||
如有问题或建议,请联系项目维护团队。
|
||
|
||
---
|
||
|
||
**最后更新 | Last Updated**: 2026-03-11
|