修复实时模式下图像预览区仍可拖动的问题;非实时模式下鼠标跟随蓝色十字线功能

This commit is contained in:
zhengxuan.zhang
2026-06-30 13:51:21 +08:00
parent e86d2381e8
commit 7f2dd8f822
4 changed files with 122 additions and 3 deletions
@@ -190,6 +190,20 @@ namespace XP.ImageProcessing.RoiControl.Controls
set => SetValue(IsWheelZoomEnabledProperty, value); set => SetValue(IsWheelZoomEnabledProperty, value);
} }
/// <summary>
/// 是否允许拖动画布平移图像(默认允许)。
/// 实时图像显示过程中可设为 false 以禁止图像拖动。
/// </summary>
public static readonly DependencyProperty IsImagePanEnabledProperty =
DependencyProperty.Register(nameof(IsImagePanEnabled), typeof(bool), typeof(PolygonRoiCanvas),
new PropertyMetadata(true));
public bool IsImagePanEnabled
{
get => (bool)GetValue(IsImagePanEnabledProperty);
set => SetValue(IsImagePanEnabledProperty, value);
}
public static readonly DependencyProperty PanOffsetXProperty = public static readonly DependencyProperty PanOffsetXProperty =
DependencyProperty.Register(nameof(PanOffsetX), typeof(double), typeof(PolygonRoiCanvas), DependencyProperty.Register(nameof(PanOffsetX), typeof(double), typeof(PolygonRoiCanvas),
new PropertyMetadata(0.0, OnPanOffsetChanged)); new PropertyMetadata(0.0, OnPanOffsetChanged));
@@ -2355,6 +2369,10 @@ namespace XP.ImageProcessing.RoiControl.Controls
lastMousePosition = e.GetPosition(imageDisplayGrid); lastMousePosition = e.GetPosition(imageDisplayGrid);
isDragging = false; isDragging = false;
if (!IsImagePanEnabled)
{
return;
}
mainCanvas.CaptureMouse(); mainCanvas.CaptureMouse();
} }
@@ -2447,7 +2465,7 @@ namespace XP.ImageProcessing.RoiControl.Controls
return; return;
} }
if (e.LeftButton == MouseButtonState.Pressed && mainCanvas.IsMouseCaptured) if (IsImagePanEnabled && e.LeftButton == MouseButtonState.Pressed && mainCanvas.IsMouseCaptured)
{ {
Point currentPosition = e.GetPosition(imageDisplayGrid); Point currentPosition = e.GetPosition(imageDisplayGrid);
Vector delta = currentPosition - lastMousePosition; Vector delta = currentPosition - lastMousePosition;
@@ -131,6 +131,7 @@ using XP.Common.Controls.ImageHistogram;
{ {
_mainViewportService.SetRealtimeDisplayEnabled(value); _mainViewportService.SetRealtimeDisplayEnabled(value);
RaisePropertyChanged(nameof(IsWheelZoomEnabled)); RaisePropertyChanged(nameof(IsWheelZoomEnabled));
RaisePropertyChanged(nameof(IsImagePanEnabled));
} }
} }
} }
@@ -140,6 +141,11 @@ using XP.Common.Controls.ImageHistogram;
/// </summary> /// </summary>
public bool IsWheelZoomEnabled => !_isRealtimeEnabled; public bool IsWheelZoomEnabled => !_isRealtimeEnabled;
/// <summary>
/// 是否允许拖动图像:实时显示过程中禁用,停止实时后可拖动。
/// </summary>
public bool IsImagePanEnabled => !_isRealtimeEnabled;
// Task 5.3: IsDetectorConnected property (read-only, private setter) // Task 5.3: IsDetectorConnected property (read-only, private setter)
public bool IsDetectorConnected public bool IsDetectorConnected
{ {
@@ -322,6 +328,7 @@ using XP.Common.Controls.ImageHistogram;
_isRealtimeEnabled = _mainViewportService.IsRealtimeDisplayEnabled; _isRealtimeEnabled = _mainViewportService.IsRealtimeDisplayEnabled;
RaisePropertyChanged(nameof(IsRealtimeEnabled)); RaisePropertyChanged(nameof(IsRealtimeEnabled));
RaisePropertyChanged(nameof(IsWheelZoomEnabled)); RaisePropertyChanged(nameof(IsWheelZoomEnabled));
RaisePropertyChanged(nameof(IsImagePanEnabled));
// Task 5.8: Sync _isCncRunning from service and raise IsAnimatedSwitchEnabled // Task 5.8: Sync _isCncRunning from service and raise IsAnimatedSwitchEnabled
_isCncRunning = _mainViewportService.IsCncRunning; _isCncRunning = _mainViewportService.IsCncRunning;
@@ -31,10 +31,11 @@
Text="实时图像" /> Text="实时图像" />
</Border> </Border>
<Grid Grid.Row="1"> <Grid Grid.Row="1" x:Name="ImageAreaGrid">
<roi:PolygonRoiCanvas <roi:PolygonRoiCanvas
x:Name="RoiCanvas" x:Name="RoiCanvas"
ImageSource="{Binding ImageSource}" ImageSource="{Binding ImageSource}"
IsImagePanEnabled="{Binding IsImagePanEnabled}"
IsWheelZoomEnabled="{Binding IsWheelZoomEnabled}" IsWheelZoomEnabled="{Binding IsWheelZoomEnabled}"
ScaleBarMmPerPixel="0.139" ScaleBarMmPerPixel="0.139"
ShowScaleBar="{Binding DataContext.IsScaleBarVisible, RelativeSource={RelativeSource AncestorType=Window}}"> ShowScaleBar="{Binding DataContext.IsScaleBarVisible, RelativeSource={RelativeSource AncestorType=Window}}">
@@ -66,6 +67,11 @@
IsHitTestVisible="False" IsHitTestVisible="False"
Visibility="Collapsed" /> Visibility="Collapsed" />
<!-- 鼠标跟随蓝色十字线叠加层(实时关闭时显示) -->
<Canvas x:Name="MouseCrosshairOverlay"
IsHitTestVisible="False"
Visibility="Collapsed" />
<!-- 灰度直方图叠加层 --> <!-- 灰度直方图叠加层 -->
<histogram:ImageHistogramControl <histogram:ImageHistogramControl
x:Name="HistogramOverlay" x:Name="HistogramOverlay"
@@ -41,6 +41,7 @@ namespace XplorePlane.Views
public ViewportPanelView() public ViewportPanelView()
{ {
InitializeComponent(); InitializeComponent();
InitializeMouseCrosshair();
DataContextChanged += OnDataContextChanged; DataContextChanged += OnDataContextChanged;
AttachHistogramViewModel(DataContext as INotifyPropertyChanged); AttachHistogramViewModel(DataContext as INotifyPropertyChanged);
Loaded += (_, _) => UpdateHistogramFromCurrentImage(); Loaded += (_, _) => UpdateHistogramFromCurrentImage();
@@ -568,6 +569,88 @@ namespace XplorePlane.Views
#endregion #endregion
#region 线
private System.Windows.Shapes.Line _mouseCrosshairH;
private System.Windows.Shapes.Line _mouseCrosshairV;
/// <summary>
/// 初始化鼠标跟随十字线(在构造函数中调用)。
/// </summary>
private void InitializeMouseCrosshair()
{
var brush = new SolidColorBrush(Color.FromArgb(200, 0, 120, 255));
brush.Freeze();
_mouseCrosshairH = new System.Windows.Shapes.Line
{
Stroke = brush,
StrokeThickness = 1,
IsHitTestVisible = false,
SnapsToDevicePixels = true
};
_mouseCrosshairV = new System.Windows.Shapes.Line
{
Stroke = brush,
StrokeThickness = 1,
IsHitTestVisible = false,
SnapsToDevicePixels = true
};
MouseCrosshairOverlay.Children.Add(_mouseCrosshairH);
MouseCrosshairOverlay.Children.Add(_mouseCrosshairV);
// 在图像区域 Grid 上监听鼠标事件
ImageAreaGrid.MouseMove += OnImageAreaMouseMove;
ImageAreaGrid.MouseLeave += OnImageAreaMouseLeave;
}
private void OnImageAreaMouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
var vm = DataContext as ViewportPanelViewModel;
if (vm == null || vm.IsRealtimeEnabled)
{
MouseCrosshairOverlay.Visibility = Visibility.Collapsed;
return;
}
MouseCrosshairOverlay.Visibility = Visibility.Visible;
var pos = e.GetPosition(ImageAreaGrid);
double w = ImageAreaGrid.ActualWidth;
double h = ImageAreaGrid.ActualHeight;
_mouseCrosshairH.X1 = 0;
_mouseCrosshairH.Y1 = pos.Y;
_mouseCrosshairH.X2 = w;
_mouseCrosshairH.Y2 = pos.Y;
_mouseCrosshairV.X1 = pos.X;
_mouseCrosshairV.Y1 = 0;
_mouseCrosshairV.X2 = pos.X;
_mouseCrosshairV.Y2 = h;
}
private void OnImageAreaMouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
{
MouseCrosshairOverlay.Visibility = Visibility.Collapsed;
}
/// <summary>
/// 当 IsRealtimeEnabled 变化时,隐藏鼠标十字线(开启实时后不再显示)。
/// </summary>
private void OnRealtimeStateChangedForMouseCrosshair()
{
var vm = DataContext as ViewportPanelViewModel;
if (vm != null && vm.IsRealtimeEnabled)
{
MouseCrosshairOverlay.Visibility = Visibility.Collapsed;
}
}
#endregion
private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e) private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{ {
AttachHistogramViewModel(e.NewValue as INotifyPropertyChanged); AttachHistogramViewModel(e.NewValue as INotifyPropertyChanged);
@@ -596,6 +679,11 @@ namespace XplorePlane.Views
{ {
UpdateHistogramFromCurrentImage(); UpdateHistogramFromCurrentImage();
} }
if (e.PropertyName == nameof(ViewportPanelViewModel.IsRealtimeEnabled))
{
OnRealtimeStateChangedForMouseCrosshair();
}
} }
private void UpdateHistogramFromCurrentImage() private void UpdateHistogramFromCurrentImage()