Files
XplorePlane/XP.Hardware.Detector/Documents/GUIDENCE.md
T

1032 lines
30 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.
# 探测器模块使用指南 | 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