diff --git a/XP.Common/Controls/ImageHistogram/ImageHistogramControl.xaml b/XP.Common/Controls/ImageHistogram/ImageHistogramControl.xaml
index 4000334..7d1f974 100644
--- a/XP.Common/Controls/ImageHistogram/ImageHistogramControl.xaml
+++ b/XP.Common/Controls/ImageHistogram/ImageHistogramControl.xaml
@@ -2,12 +2,18 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
+ xmlns:loc="clr-namespace:XP.Common.Localization.Extensions"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="200" d:DesignWidth="400">
+
+
+
+
+
+
+
+
diff --git a/XP.Common/Controls/ImageHistogram/ImageHistogramControl.xaml.cs b/XP.Common/Controls/ImageHistogram/ImageHistogramControl.xaml.cs
index a02cb15..ae98696 100644
--- a/XP.Common/Controls/ImageHistogram/ImageHistogramControl.xaml.cs
+++ b/XP.Common/Controls/ImageHistogram/ImageHistogramControl.xaml.cs
@@ -219,10 +219,24 @@ namespace XP.Common.Controls.ImageHistogram
// 取消帧率限流器中的待处理任务 | Cancel pending tasks in throttler
_frameThrottler.Cancel();
- // 清空图表 | Clear chart
- if (_chartRenderer != null)
+ // 清空图表(捕获局部引用避免异步执行时为 null)| Clear chart (capture local ref to avoid null during async)
+ var renderer = _chartRenderer;
+ if (renderer != null)
{
- Dispatcher.InvokeAsync(() => _chartRenderer.Clear());
+ Dispatcher.InvokeAsync(() =>
+ {
+ try
+ {
+ renderer.Clear();
+
+ // 显示无数据提示 | Show no-data placeholder
+ NoDataPlaceholder.Visibility = Visibility.Visible;
+ }
+ catch
+ {
+ // 控件已卸载时忽略 | Ignore if control already unloaded
+ }
+ });
}
}
catch (Exception ex)
@@ -259,6 +273,9 @@ namespace XP.Common.Controls.ImageHistogram
{
isLog = IsLogarithmic;
_chartRenderer?.UpdateData(histogram, isLog);
+
+ // 隐藏无数据提示 | Hide no-data placeholder
+ NoDataPlaceholder.Visibility = Visibility.Collapsed;
}
catch (Exception ex)
{
diff --git a/XP.Common/Resources/Resources.en-US.resx b/XP.Common/Resources/Resources.en-US.resx
index 3154237..17c92be 100644
--- a/XP.Common/Resources/Resources.en-US.resx
+++ b/XP.Common/Resources/Resources.en-US.resx
@@ -1887,4 +1887,8 @@ Reprojection error: {1:F4} pixels
Image{0}: {1:F4} pixels
+
+ Histogram — No data
+ ImageHistogramControl - Placeholder text when no image data
+
\ No newline at end of file
diff --git a/XP.Common/Resources/Resources.resx b/XP.Common/Resources/Resources.resx
index 7f0cc41..81dfcef 100644
--- a/XP.Common/Resources/Resources.resx
+++ b/XP.Common/Resources/Resources.resx
@@ -1920,4 +1920,8 @@
图像{0}: {1:F4} 像素
+
+ 直方图 — 暂无数据
+ ImageHistogramControl - 无图像输入时的提示文本 | Placeholder text when no image data
+
\ No newline at end of file
diff --git a/XP.Common/Resources/Resources.zh-CN.resx b/XP.Common/Resources/Resources.zh-CN.resx
index 7dc08f9..e7ead9d 100644
--- a/XP.Common/Resources/Resources.zh-CN.resx
+++ b/XP.Common/Resources/Resources.zh-CN.resx
@@ -1881,4 +1881,8 @@
图像{0}: {1:F4} 像素
+
+ 直方图 — 暂无数据
+ ImageHistogramControl - 无图像输入时的提示文本 | Placeholder text when no image data
+
\ No newline at end of file
diff --git a/XP.Common/Resources/Resources.zh-TW.resx b/XP.Common/Resources/Resources.zh-TW.resx
index 946e1f5..630a189 100644
--- a/XP.Common/Resources/Resources.zh-TW.resx
+++ b/XP.Common/Resources/Resources.zh-TW.resx
@@ -1881,4 +1881,8 @@
图像{0}: {1:F4} 像素
+
+ 直方圖 — 暫無資料
+ ImageHistogramControl - 無圖像輸入時的提示文字 | Placeholder text when no image data
+
\ No newline at end of file
diff --git a/XP.Hardware.Detector/Views/DetectorConfigView.xaml b/XP.Hardware.Detector/Views/DetectorConfigView.xaml
index 0c7acd7..9944825 100644
--- a/XP.Hardware.Detector/Views/DetectorConfigView.xaml
+++ b/XP.Hardware.Detector/Views/DetectorConfigView.xaml
@@ -6,8 +6,9 @@
xmlns:prism="http://prismlibrary.com/"
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
xmlns:loc="clr-namespace:XP.Common.Localization.Extensions;assembly=XP.Common"
+ xmlns:hist="clr-namespace:XP.Common.Controls.ImageHistogram;assembly=XP.Common"
mc:Ignorable="d"
- d:DesignWidth="420" d:DesignHeight="210"
+ d:DesignWidth="420" d:DesignHeight="360"
prism:ViewModelLocator.AutoWireViewModel="True"
Background="White">
@@ -22,6 +23,8 @@
+
+
@@ -136,5 +139,12 @@
+
+
+
diff --git a/XP.Hardware.Detector/Views/DetectorConfigView.xaml.cs b/XP.Hardware.Detector/Views/DetectorConfigView.xaml.cs
index 5485bc3..50d4eef 100644
--- a/XP.Hardware.Detector/Views/DetectorConfigView.xaml.cs
+++ b/XP.Hardware.Detector/Views/DetectorConfigView.xaml.cs
@@ -1,15 +1,82 @@
+using System;
+using System.Windows;
using System.Windows.Controls;
+using Prism.Events;
+using Prism.Ioc;
+using XP.Hardware.Detector.Abstractions;
+using XP.Hardware.Detector.Abstractions.Events;
namespace XP.Hardware.Detector.Views
{
///
/// 面阵探测器配置视图 | Area detector configuration view
+ /// 订阅探测器图像采集事件,将图像数据传递给直方图控件
///
public partial class DetectorConfigView : UserControl
{
+ private IEventAggregator _eventAggregator;
+ private SubscriptionToken _imageSubscriptionToken;
+
public DetectorConfigView()
{
InitializeComponent();
+ Loaded += OnLoaded;
+ Unloaded += OnUnloaded;
+ }
+
+ ///
+ /// 加载时订阅图像采集事件 | Subscribe to image captured event on load
+ ///
+ private void OnLoaded(object sender, RoutedEventArgs e)
+ {
+ try
+ {
+ _eventAggregator = ContainerLocator.Current?.Resolve();
+ if (_eventAggregator != null)
+ {
+ _imageSubscriptionToken = _eventAggregator.GetEvent()
+ .Subscribe(OnImageCaptured, ThreadOption.BackgroundThread);
+ }
+ }
+ catch
+ {
+ // 事件聚合器不可用时静默降级 | Silent degradation when event aggregator unavailable
+ }
+ }
+
+ ///
+ /// 卸载时取消订阅 | Unsubscribe on unload
+ ///
+ private void OnUnloaded(object sender, RoutedEventArgs e)
+ {
+ if (_eventAggregator != null && _imageSubscriptionToken != null)
+ {
+ _eventAggregator.GetEvent().Unsubscribe(_imageSubscriptionToken);
+ _imageSubscriptionToken = null;
+ }
+ }
+
+ ///
+ /// 图像采集回调:将 ushort[] 转为 byte[] 后传给直方图控件 | Image captured callback
+ ///
+ private void OnImageCaptured(ImageCapturedEventArgs args)
+ {
+ if (args?.ImageData == null || args.Width == 0 || args.Height == 0)
+ return;
+
+ try
+ {
+ // 将 ushort[] 转换为 little-endian byte[] | Convert ushort[] to little-endian byte[]
+ var rawBytes = new byte[args.ImageData.Length * 2];
+ Buffer.BlockCopy(args.ImageData, 0, rawBytes, 0, rawBytes.Length);
+
+ // 调用直方图控件更新(控件内部支持从非 UI 线程调用)| Update histogram control (supports non-UI thread calls)
+ HistogramControl?.UpdateImage(rawBytes, (int)args.Width, (int)args.Height, 16);
+ }
+ catch
+ {
+ // 异常不影响主流程 | Exception does not affect main flow
+ }
}
}
}
diff --git a/XP.Hardware.Detector/Views/DetectorConfigWindow.xaml b/XP.Hardware.Detector/Views/DetectorConfigWindow.xaml
index 500ec99..2532120 100644
--- a/XP.Hardware.Detector/Views/DetectorConfigWindow.xaml
+++ b/XP.Hardware.Detector/Views/DetectorConfigWindow.xaml
@@ -4,8 +4,8 @@
xmlns:loc="clr-namespace:XP.Common.Localization.Extensions;assembly=XP.Common"
xmlns:detectorViews="clr-namespace:XP.Hardware.Detector.Views"
Title="{loc:Localization Detector_ConfigWindowTitle}"
- Height="230" Width="400"
- MinHeight="230" MinWidth="360"
+ Height="420" Width="400"
+ MinHeight="380" MinWidth="360"
WindowStartupLocation="CenterOwner"
ResizeMode="CanResize">