diff --git a/XP.Hardware.Detector/bin/Debug/net8.0-windows7.0/XP.Hardware.Detector.deps.json b/XP.Hardware.Detector/bin/Debug/net8.0-windows7.0/XP.Hardware.Detector.deps.json index 3f740dc..54eff8d 100644 --- a/XP.Hardware.Detector/bin/Debug/net8.0-windows7.0/XP.Hardware.Detector.deps.json +++ b/XP.Hardware.Detector/bin/Debug/net8.0-windows7.0/XP.Hardware.Detector.deps.json @@ -1878,7 +1878,10 @@ "Telerik.UI.for.Wpf.NetCore.Xaml": "2024.1.408" }, "runtime": { - "XP.Common.dll": {} + "XP.Common.dll": { + "assemblyVersion": "1.4.16.1", + "fileVersion": "1.4.16.1" + } }, "resources": { "en-US/XP.Common.resources.dll": { diff --git a/XplorePlane/Events/MeasurementToolEvent.cs b/XplorePlane/Events/MeasurementToolEvent.cs index 329af92..7d8b129 100644 --- a/XplorePlane/Events/MeasurementToolEvent.cs +++ b/XplorePlane/Events/MeasurementToolEvent.cs @@ -18,4 +18,9 @@ namespace XplorePlane.Events /// 测量工具激活事件,由 MainViewModel 发布,ViewportPanelViewModel 订阅 /// public class MeasurementToolEvent : PubSubEvent { } + + /// + /// 十字辅助线切换事件 + /// + public class ToggleCrosshairEvent : PubSubEvent { } } diff --git a/XplorePlane/ViewModels/Main/MainViewModel.cs b/XplorePlane/ViewModels/Main/MainViewModel.cs index e28dcbf..96fc3bd 100644 --- a/XplorePlane/ViewModels/Main/MainViewModel.cs +++ b/XplorePlane/ViewModels/Main/MainViewModel.cs @@ -81,6 +81,9 @@ namespace XplorePlane.ViewModels public DelegateCommand AngleMeasureCommand { get; } public DelegateCommand ThroughHoleFillRateMeasureCommand { get; } + // 辅助线命令 + public DelegateCommand ToggleCrosshairCommand { get; } + // 设置命令 public DelegateCommand OpenLanguageSwitcherCommand { get; } public DelegateCommand OpenRealTimeLogViewerCommand { get; } @@ -164,6 +167,10 @@ namespace XplorePlane.ViewModels AngleMeasureCommand = new DelegateCommand(ExecuteAngleMeasure); ThroughHoleFillRateMeasureCommand = new DelegateCommand(ExecuteThroughHoleFillRateMeasure); + // 辅助线命令 + ToggleCrosshairCommand = new DelegateCommand(() => + _eventAggregator.GetEvent().Publish()); + // 硬件命令 AxisResetCommand = new DelegateCommand(ExecuteAxisReset); OpenDetectorConfigCommand = new DelegateCommand(ExecuteOpenDetectorConfig); diff --git a/XplorePlane/ViewModels/Main/ViewportPanelViewModel.cs b/XplorePlane/ViewModels/Main/ViewportPanelViewModel.cs index 899db50..d41512f 100644 --- a/XplorePlane/ViewModels/Main/ViewportPanelViewModel.cs +++ b/XplorePlane/ViewModels/Main/ViewportPanelViewModel.cs @@ -154,6 +154,10 @@ namespace XplorePlane.ViewModels // 订阅测量工具事件 eventAggregator.GetEvent() .Subscribe(OnMeasurementToolActivated, ThreadOption.UIThread); + + // 订阅十字辅助线切换事件 + eventAggregator.GetEvent() + .Subscribe(OnToggleCrosshair, ThreadOption.UIThread); } private void OnMeasurementToolActivated(MeasurementToolMode mode) @@ -162,6 +166,23 @@ namespace XplorePlane.ViewModels _logger?.Info("测量工具模式切换: {Mode}", mode); } + #region 十字辅助线 + + private bool _showCrosshair; + public bool ShowCrosshair + { + get => _showCrosshair; + set => SetProperty(ref _showCrosshair, value); + } + + private void OnToggleCrosshair() + { + ShowCrosshair = !ShowCrosshair; + _logger?.Info("十字辅助线: {State}", ShowCrosshair ? "显示" : "隐藏"); + } + + #endregion + private void OnImageCaptured(ImageCapturedEventArgs args) { if (args?.ImageData == null || args.Width == 0 || args.Height == 0) return; diff --git a/XplorePlane/Views/HalfValueConverter.cs b/XplorePlane/Views/HalfValueConverter.cs new file mode 100644 index 0000000..226d40c --- /dev/null +++ b/XplorePlane/Views/HalfValueConverter.cs @@ -0,0 +1,16 @@ +using System; +using System.Globalization; +using System.Windows.Data; + +namespace XplorePlane.Views +{ + /// 返回输入值的一半,用于十字线居中定位 + public class HalfValueConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + => value is double d ? d / 2.0 : 0.0; + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + => throw new NotSupportedException(); + } +} diff --git a/XplorePlane/Views/Main/MainWindow.xaml b/XplorePlane/Views/Main/MainWindow.xaml index 223e1fd..05f345a 100644 --- a/XplorePlane/Views/Main/MainWindow.xaml +++ b/XplorePlane/Views/Main/MainWindow.xaml @@ -146,6 +146,7 @@ diff --git a/XplorePlane/Views/Main/ViewportPanelView.xaml b/XplorePlane/Views/Main/ViewportPanelView.xaml index 93561c1..cb1571e 100644 --- a/XplorePlane/Views/Main/ViewportPanelView.xaml +++ b/XplorePlane/Views/Main/ViewportPanelView.xaml @@ -6,12 +6,14 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:prism="http://prismlibrary.com/" xmlns:roi="clr-namespace:XP.ImageProcessing.RoiControl.Controls;assembly=XP.ImageProcessing.RoiControl" + xmlns:local="clr-namespace:XplorePlane.Views" prism:ViewModelLocator.AutoWireViewModel="True" d:DesignHeight="400" d:DesignWidth="600" mc:Ignorable="d"> + @@ -55,6 +57,8 @@ + + diff --git a/XplorePlane/Views/Main/ViewportPanelView.xaml.cs b/XplorePlane/Views/Main/ViewportPanelView.xaml.cs index 6b129a4..94aeaa0 100644 --- a/XplorePlane/Views/Main/ViewportPanelView.xaml.cs +++ b/XplorePlane/Views/Main/ViewportPanelView.xaml.cs @@ -10,6 +10,7 @@ using System.Windows.Media.Imaging; using System.Windows.Shapes; using Microsoft.Win32; using XP.ImageProcessing.RoiControl.Controls; +using Prism.Ioc; using XplorePlane.Events; using XplorePlane.ViewModels; @@ -65,10 +66,25 @@ namespace XplorePlane.Views if (e is CanvasClickedEventArgs args) OnCanvasClicked(args.Position); }; + + // 直接订阅 Prism 事件,不依赖 DataContext 的 PropertyChanged + try + { + var ea = Prism.Ioc.ContainerLocator.Current?.Resolve(); + ea?.GetEvent().Subscribe(() => + { + _crosshairVisible = !_crosshairVisible; + ToggleCrosshairOnCanvas(_crosshairVisible); + }, Prism.Events.ThreadOption.UIThread); + } + catch { /* 设计时或容器未初始化时忽略 */ } } + private bool _crosshairVisible; + private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e) { + System.Diagnostics.Debug.WriteLine($"[VP] DataContextChanged: old={e.OldValue?.GetType().Name}, new={e.NewValue?.GetType().Name}"); if (e.OldValue is INotifyPropertyChanged oldVm) oldVm.PropertyChanged -= OnVmPropertyChanged; if (e.NewValue is INotifyPropertyChanged newVm) @@ -78,6 +94,7 @@ namespace XplorePlane.Views private void OnVmPropertyChanged(object sender, PropertyChangedEventArgs e) { if (sender is not ViewportPanelViewModel vm) return; + System.Diagnostics.Debug.WriteLine($"[VP] PropertyChanged: {e.PropertyName}"); if (e.PropertyName == nameof(ViewportPanelViewModel.CurrentMeasurementMode)) { if (vm.CurrentMeasurementMode != MeasurementToolMode.None) @@ -86,6 +103,10 @@ namespace XplorePlane.Views else RemoveOverlay(); } + else if (e.PropertyName == nameof(ViewportPanelViewModel.ShowCrosshair)) + { + // 十字线通过直接订阅 ToggleCrosshairEvent 处理 + } } #region 覆盖层管理 @@ -324,6 +345,47 @@ namespace XplorePlane.Views return null; } + private void UpdateCrosshairLines() + { + // 十字线位置通过 XAML 绑定自动计算 + } + + private Line _crosshairH, _crosshairV; + + private void ToggleCrosshairOnCanvas(bool show) + { + var mainCanvas = FindChildByName(RoiCanvas, "mainCanvas"); + System.Diagnostics.Debug.WriteLine($"[VP] ToggleCrosshair show={show}, mainCanvas={mainCanvas != null}, W={RoiCanvas.CanvasWidth}, H={RoiCanvas.CanvasHeight}"); + if (mainCanvas == null) return; + + if (show) + { + double w = RoiCanvas.CanvasWidth; + double h = RoiCanvas.CanvasHeight; + if (w <= 0 || h <= 0) return; + + _crosshairH = new Line + { + X1 = 0, Y1 = h / 2, X2 = w, Y2 = h / 2, + Stroke = Brushes.Red, StrokeThickness = 1, Opacity = 0.7, + IsHitTestVisible = false + }; + _crosshairV = new Line + { + X1 = w / 2, Y1 = 0, X2 = w / 2, Y2 = h, + Stroke = Brushes.Red, StrokeThickness = 1, Opacity = 0.7, + IsHitTestVisible = false + }; + mainCanvas.Children.Add(_crosshairH); + mainCanvas.Children.Add(_crosshairV); + } + else + { + if (_crosshairH != null) { mainCanvas.Children.Remove(_crosshairH); _crosshairH = null; } + if (_crosshairV != null) { mainCanvas.Children.Remove(_crosshairV); _crosshairV = null; } + } + } + #endregion #region 右键菜单