130f39db49
# Conflicts: # XplorePlane/ViewModels/Main/MainViewModel.cs # XplorePlane/Views/Main/MainWindow.xaml
766 lines
32 KiB
C#
766 lines
32 KiB
C#
using Microsoft.Win32;
|
||
using Prism.Commands;
|
||
using Prism.Events;
|
||
using Prism.Ioc;
|
||
using Prism.Mvvm;
|
||
using System;
|
||
using System.Collections.ObjectModel;
|
||
using System.Configuration;
|
||
using System.IO;
|
||
using System.Windows;
|
||
using System.Windows.Media.Imaging;
|
||
using XplorePlane.Events;
|
||
using XplorePlane.Services.MainViewport;
|
||
using XplorePlane.ViewModels.Cnc;
|
||
using XplorePlane.Views;
|
||
using XplorePlane.Views.Cnc;
|
||
using XP.Common.Logging.Interfaces;
|
||
using XP.Common.GeneralForm.Views;
|
||
using XP.Common.PdfViewer.Interfaces;
|
||
using XP.Hardware.MotionControl.Abstractions;
|
||
|
||
namespace XplorePlane.ViewModels
|
||
{
|
||
public class MainViewModel : BindableBase
|
||
{
|
||
private const double CncEditorHostWidth = 502d;
|
||
|
||
private readonly ILoggerService _logger;
|
||
private readonly IContainerProvider _containerProvider;
|
||
private readonly IEventAggregator _eventAggregator;
|
||
private readonly IMainViewportService _mainViewportService;
|
||
private readonly CncEditorViewModel _cncEditorViewModel;
|
||
private readonly CncPageView _cncPageView;
|
||
|
||
public string LicenseInfo
|
||
{
|
||
get => _licenseInfo;
|
||
set => SetProperty(ref _licenseInfo, value);
|
||
}
|
||
|
||
private string _statusMessage = "就绪";
|
||
public string StatusMessage
|
||
{
|
||
get => _statusMessage;
|
||
set => SetProperty(ref _statusMessage, value);
|
||
}
|
||
|
||
public ObservableCollection<object> NavigationTree { get; set; }
|
||
|
||
// 导航命令
|
||
public DelegateCommand NavigateHomeCommand { get; set; }
|
||
public DelegateCommand NavigateInspectCommand { get; set; }
|
||
public DelegateCommand OpenFileCommand { get; set; }
|
||
public DelegateCommand ExportCommand { get; set; }
|
||
public DelegateCommand ClearCommand { get; set; }
|
||
public DelegateCommand EditPropertiesCommand { get; set; }
|
||
|
||
// 窗口打开命令
|
||
public DelegateCommand OpenImageProcessingCommand { get; }
|
||
public DelegateCommand LoadImageCommand { get; }
|
||
public DelegateCommand OpenPipelineEditorCommand { get; }
|
||
public DelegateCommand OpenCncEditorCommand { get; }
|
||
public DelegateCommand OpenMatrixEditorCommand { get; }
|
||
public DelegateCommand OpenToolboxCommand { get; }
|
||
public DelegateCommand OpenLibraryVersionsCommand { get; }
|
||
public DelegateCommand OpenUserManualCommand { get; }
|
||
public DelegateCommand OpenCameraSettingsCommand { get; }
|
||
public DelegateCommand NewCncProgramCommand { get; }
|
||
public DelegateCommand SaveCncProgramCommand { get; }
|
||
public DelegateCommand LoadCncProgramCommand { get; }
|
||
public DelegateCommand InsertReferencePointCommand { get; }
|
||
public DelegateCommand InsertSavePositionCommand { get; }
|
||
public DelegateCommand InsertCompleteProgramCommand { get; }
|
||
public DelegateCommand InsertInspectionMarkerCommand { get; }
|
||
public DelegateCommand InsertInspectionModuleCommand { get; }
|
||
public DelegateCommand InsertSaveNodeCommand { get; }
|
||
public DelegateCommand InsertPauseDialogCommand { get; }
|
||
public DelegateCommand InsertWaitDelayCommand { get; }
|
||
|
||
// 硬件命令
|
||
public DelegateCommand AxisResetCommand { get; }
|
||
public DelegateCommand OpenDetectorConfigCommand { get; }
|
||
public DelegateCommand OpenMotionDebugCommand { get; }
|
||
public DelegateCommand OpenPlcAddrConfigCommand { get; }
|
||
public DelegateCommand OpenRaySourceConfigCommand { get; }
|
||
public DelegateCommand WarmUpCommand { get; }
|
||
|
||
// 测量命令
|
||
public DelegateCommand PointDistanceMeasureCommand { get; }
|
||
public DelegateCommand PointLineDistanceMeasureCommand { get; }
|
||
public DelegateCommand AngleMeasureCommand { get; }
|
||
public DelegateCommand ThroughHoleFillRateMeasureCommand { get; }
|
||
public DelegateCommand BgaVoidMeasureCommand { get; }
|
||
public DelegateCommand BubbleMeasureCommand { get; }
|
||
|
||
// 辅助线命令
|
||
public DelegateCommand ToggleCrosshairCommand { get; }
|
||
|
||
// 设置命令
|
||
public DelegateCommand OpenLanguageSwitcherCommand { get; }
|
||
public DelegateCommand OpenRealTimeLogViewerCommand { get; }
|
||
public DelegateCommand UseLiveDetectorSourceCommand { get; }
|
||
|
||
public bool IsMainViewportRealtimeEnabled
|
||
{
|
||
get => _mainViewportService.IsRealtimeDisplayEnabled;
|
||
set
|
||
{
|
||
if (_mainViewportService.IsRealtimeDisplayEnabled == value)
|
||
return;
|
||
|
||
_mainViewportService.SetRealtimeDisplayEnabled(value);
|
||
RaisePropertyChanged();
|
||
}
|
||
}
|
||
|
||
public bool IsUsingLiveDetectorSource => _mainViewportService.CurrentSourceMode == MainViewportSourceMode.LiveDetector;
|
||
|
||
/// <summary>右侧图像区域内容 | Right-side image panel content</summary>
|
||
public object ImagePanelContent
|
||
{
|
||
get => _imagePanelContent;
|
||
set => SetProperty(ref _imagePanelContent, value);
|
||
}
|
||
|
||
/// <summary>右侧图像区域宽度 | Right-side image panel width</summary>
|
||
public GridLength ImagePanelWidth
|
||
{
|
||
get => _imagePanelWidth;
|
||
set => SetProperty(ref _imagePanelWidth, value);
|
||
}
|
||
|
||
/// <summary>主视图区宽度 | Main viewport width</summary>
|
||
public GridLength ViewportPanelWidth
|
||
{
|
||
get => _viewportPanelWidth;
|
||
set => SetProperty(ref _viewportPanelWidth, value);
|
||
}
|
||
|
||
// 窗口引用(单例窗口防止重复打开)
|
||
|
||
private Window _motionDebugWindow;
|
||
private Window _detectorConfigWindow;
|
||
private Window _plcAddrConfigWindow;
|
||
private Window _realTimeLogViewerWindow;
|
||
private Window _toolboxWindow;
|
||
private Window _raySourceConfigWindow;
|
||
private object _imagePanelContent;
|
||
private GridLength _viewportPanelWidth = new(1, GridUnitType.Star);
|
||
private GridLength _imagePanelWidth = new(320);
|
||
private bool _isCncEditorMode;
|
||
private string _licenseInfo = "当前时间";
|
||
|
||
public MainViewModel(
|
||
ILoggerService logger,
|
||
IContainerProvider containerProvider,
|
||
IEventAggregator eventAggregator,
|
||
IMainViewportService mainViewportService)
|
||
{
|
||
_logger = logger?.ForModule<MainViewModel>() ?? throw new ArgumentNullException(nameof(logger));
|
||
_containerProvider = containerProvider ?? throw new ArgumentNullException(nameof(containerProvider));
|
||
_eventAggregator = eventAggregator ?? throw new ArgumentNullException(nameof(eventAggregator));
|
||
_mainViewportService = mainViewportService ?? throw new ArgumentNullException(nameof(mainViewportService));
|
||
_cncEditorViewModel = _containerProvider.Resolve<CncEditorViewModel>();
|
||
_cncPageView = new CncPageView { DataContext = _cncEditorViewModel };
|
||
|
||
_mainViewportService.StateChanged += OnMainViewportStateChanged;
|
||
_cncEditorViewModel.PropertyChanged += (s, e) =>
|
||
{
|
||
if (e.PropertyName == nameof(CncEditorViewModel.StatusMessage))
|
||
RaisePropertyChanged(nameof(CncStatusMessage));
|
||
else if (e.PropertyName == nameof(CncEditorViewModel.HasExecutionError))
|
||
RaisePropertyChanged(nameof(CncHasExecutionError));
|
||
else if (e.PropertyName == nameof(CncEditorViewModel.IsRunning))
|
||
{
|
||
RunCncCommand.RaiseCanExecuteChanged();
|
||
StopCncCommand.RaiseCanExecuteChanged();
|
||
}
|
||
};
|
||
_cncEditorViewModel.RunCncCommand.CanExecuteChanged += (s, e) => RunCncCommand.RaiseCanExecuteChanged();
|
||
_cncEditorViewModel.StopCncCommand.CanExecuteChanged += (s, e) => StopCncCommand.RaiseCanExecuteChanged();
|
||
|
||
_eventAggregator.GetEvent<PipelinePreviewUpdatedEvent>()
|
||
.Subscribe(OnPipelinePreviewUpdated, ThreadOption.UIThread);
|
||
|
||
NavigationTree = new ObservableCollection<object>();
|
||
|
||
NavigateHomeCommand = new DelegateCommand(OnNavigateHome);
|
||
NavigateInspectCommand = new DelegateCommand(OnNavigateInspect);
|
||
OpenFileCommand = new DelegateCommand(OnOpenFile);
|
||
ExportCommand = new DelegateCommand(OnExport);
|
||
ClearCommand = new DelegateCommand(OnClear);
|
||
EditPropertiesCommand = new DelegateCommand(OnEditProperties);
|
||
|
||
OpenImageProcessingCommand = new DelegateCommand(() => ShowWindow(new Views.ImageProcessingWindow(), "图像处理"));
|
||
LoadImageCommand = new DelegateCommand(ExecuteLoadImage);
|
||
OpenPipelineEditorCommand = new DelegateCommand(() => ShowWindow(new Views.PipelineEditorWindow(), "流水线编辑器"));
|
||
OpenCncEditorCommand = new DelegateCommand(ExecuteOpenCncEditor);
|
||
OpenMatrixEditorCommand = new DelegateCommand(() => ShowWindow(new Views.Cnc.MatrixEditorWindow(), "矩阵编排"));
|
||
OpenToolboxCommand = new DelegateCommand(ExecuteOpenToolbox);
|
||
OpenLibraryVersionsCommand = new DelegateCommand(() => ShowWindow(new Views.LibraryVersionsWindow(), "关于"));
|
||
OpenUserManualCommand = new DelegateCommand(ExecuteOpenUserManual);
|
||
OpenCameraSettingsCommand = new DelegateCommand(ExecuteOpenCameraSettings);
|
||
NewCncProgramCommand = new DelegateCommand(() => ExecuteCncEditorAction(vm => vm.NewProgramCommand.Execute()));
|
||
SaveCncProgramCommand = new DelegateCommand(() => ExecuteCncEditorAction(vm => vm.SaveProgramCommand.Execute()));
|
||
LoadCncProgramCommand = new DelegateCommand(() => ExecuteCncEditorAction(vm => vm.LoadProgramCommand.Execute()));
|
||
InsertReferencePointCommand = new DelegateCommand(() => ExecuteCncEditorAction(vm => vm.InsertReferencePointCommand.Execute()));
|
||
InsertSavePositionCommand = new DelegateCommand(() => ExecuteCncEditorAction(vm => vm.InsertSavePositionCommand.Execute()));
|
||
InsertCompleteProgramCommand = new DelegateCommand(() => ExecuteCncEditorAction(vm => vm.InsertCompleteProgramCommand.Execute()));
|
||
InsertInspectionMarkerCommand = new DelegateCommand(() => ExecuteCncEditorAction(vm => vm.InsertInspectionMarkerCommand.Execute()));
|
||
InsertInspectionModuleCommand = new DelegateCommand(() => ExecuteCncEditorAction(vm => vm.InsertInspectionModuleCommand.Execute()));
|
||
InsertSaveNodeCommand = new DelegateCommand(() => ExecuteCncEditorAction(vm => vm.InsertSaveNodeCommand.Execute()));
|
||
InsertPauseDialogCommand = new DelegateCommand(() => ExecuteCncEditorAction(vm => vm.InsertPauseDialogCommand.Execute()));
|
||
InsertWaitDelayCommand = new DelegateCommand(() => ExecuteCncEditorAction(vm => vm.InsertWaitDelayCommand.Execute()));
|
||
RunCncCommand = new DelegateCommand(
|
||
() => ExecuteCncEditorAction(vm => vm.RunCncCommand.Execute()),
|
||
() => _cncEditorViewModel.RunCncCommand.CanExecute());
|
||
StopCncCommand = new DelegateCommand(
|
||
() => ExecuteCncEditorAction(vm => vm.StopCncCommand.Execute()),
|
||
() => _cncEditorViewModel.StopCncCommand.CanExecute());
|
||
|
||
PointDistanceMeasureCommand = new DelegateCommand(ExecutePointDistanceMeasure);
|
||
PointLineDistanceMeasureCommand = new DelegateCommand(ExecutePointLineDistanceMeasure);
|
||
AngleMeasureCommand = new DelegateCommand(ExecuteAngleMeasure);
|
||
ThroughHoleFillRateMeasureCommand = new DelegateCommand(ExecuteThroughHoleFillRateMeasure);
|
||
BgaVoidMeasureCommand = new DelegateCommand(ExecuteBgaVoidMeasure);
|
||
BubbleMeasureCommand = new DelegateCommand(ExecuteBubbleMeasure);
|
||
|
||
// 辅助线命令
|
||
|
||
ToggleCrosshairCommand = new DelegateCommand(() =>
|
||
_eventAggregator.GetEvent<ToggleCrosshairEvent>().Publish());
|
||
|
||
AxisResetCommand = new DelegateCommand(ExecuteAxisReset);
|
||
OpenDetectorConfigCommand = new DelegateCommand(ExecuteOpenDetectorConfig);
|
||
OpenMotionDebugCommand = new DelegateCommand(ExecuteOpenMotionDebug);
|
||
OpenPlcAddrConfigCommand = new DelegateCommand(ExecuteOpenPlcAddrConfig);
|
||
OpenRaySourceConfigCommand = new DelegateCommand(ExecuteOpenRaySourceConfig);
|
||
WarmUpCommand = new DelegateCommand(ExecuteWarmUp);
|
||
|
||
OpenLanguageSwitcherCommand = new DelegateCommand(ExecuteOpenLanguageSwitcher);
|
||
OpenRealTimeLogViewerCommand = new DelegateCommand(ExecuteOpenRealTimeLogViewer);
|
||
UseLiveDetectorSourceCommand = new DelegateCommand(ExecuteUseLiveDetectorSource);
|
||
|
||
ImagePanelContent = new PipelineEditorView();
|
||
ViewportPanelWidth = new GridLength(1, GridUnitType.Star);
|
||
ImagePanelWidth = new GridLength(320);
|
||
|
||
_logger.Info("MainViewModel 已初始化");
|
||
}
|
||
|
||
public string LicenseInfo
|
||
{
|
||
get => _licenseInfo;
|
||
set => SetProperty(ref _licenseInfo, value);
|
||
}
|
||
|
||
public string CncStatusMessage => _cncEditorViewModel.StatusMessage;
|
||
public bool CncHasExecutionError => _cncEditorViewModel.HasExecutionError;
|
||
|
||
public ObservableCollection<object> NavigationTree { get; set; }
|
||
|
||
public DelegateCommand NavigateHomeCommand { get; set; }
|
||
public DelegateCommand NavigateInspectCommand { get; set; }
|
||
public DelegateCommand OpenFileCommand { get; set; }
|
||
public DelegateCommand ExportCommand { get; set; }
|
||
public DelegateCommand ClearCommand { get; set; }
|
||
public DelegateCommand EditPropertiesCommand { get; set; }
|
||
|
||
public DelegateCommand OpenImageProcessingCommand { get; }
|
||
public DelegateCommand LoadImageCommand { get; }
|
||
public DelegateCommand OpenPipelineEditorCommand { get; }
|
||
public DelegateCommand OpenCncEditorCommand { get; }
|
||
public DelegateCommand OpenMatrixEditorCommand { get; }
|
||
public DelegateCommand OpenToolboxCommand { get; }
|
||
public DelegateCommand OpenLibraryVersionsCommand { get; }
|
||
public DelegateCommand OpenUserManualCommand { get; }
|
||
public DelegateCommand OpenCameraSettingsCommand { get; }
|
||
public DelegateCommand NewCncProgramCommand { get; }
|
||
public DelegateCommand SaveCncProgramCommand { get; }
|
||
public DelegateCommand LoadCncProgramCommand { get; }
|
||
public DelegateCommand InsertReferencePointCommand { get; }
|
||
public DelegateCommand InsertSavePositionCommand { get; }
|
||
public DelegateCommand InsertCompleteProgramCommand { get; }
|
||
public DelegateCommand InsertInspectionMarkerCommand { get; }
|
||
public DelegateCommand InsertInspectionModuleCommand { get; }
|
||
public DelegateCommand InsertSaveNodeCommand { get; }
|
||
public DelegateCommand InsertPauseDialogCommand { get; }
|
||
public DelegateCommand InsertWaitDelayCommand { get; }
|
||
public DelegateCommand RunCncCommand { get; }
|
||
public DelegateCommand StopCncCommand { get; }
|
||
|
||
public DelegateCommand AxisResetCommand { get; }
|
||
public DelegateCommand OpenDetectorConfigCommand { get; }
|
||
public DelegateCommand OpenMotionDebugCommand { get; }
|
||
public DelegateCommand OpenPlcAddrConfigCommand { get; }
|
||
public DelegateCommand OpenRaySourceConfigCommand { get; }
|
||
public DelegateCommand WarmUpCommand { get; }
|
||
|
||
public DelegateCommand PointDistanceMeasureCommand { get; }
|
||
public DelegateCommand PointLineDistanceMeasureCommand { get; }
|
||
public DelegateCommand AngleMeasureCommand { get; }
|
||
public DelegateCommand ThroughHoleFillRateMeasureCommand { get; }
|
||
public DelegateCommand ToggleCrosshairCommand { get; }
|
||
|
||
public DelegateCommand OpenLanguageSwitcherCommand { get; }
|
||
public DelegateCommand OpenRealTimeLogViewerCommand { get; }
|
||
public DelegateCommand UseLiveDetectorSourceCommand { get; }
|
||
|
||
public bool IsMainViewportRealtimeEnabled
|
||
{
|
||
get => _mainViewportService.IsRealtimeDisplayEnabled;
|
||
set
|
||
{
|
||
if (_mainViewportService.IsRealtimeDisplayEnabled == value)
|
||
return;
|
||
|
||
_mainViewportService.SetRealtimeDisplayEnabled(value);
|
||
RaisePropertyChanged();
|
||
}
|
||
}
|
||
|
||
public bool IsUsingLiveDetectorSource => _mainViewportService.CurrentSourceMode == MainViewportSourceMode.LiveDetector;
|
||
|
||
public object ImagePanelContent
|
||
{
|
||
get => _imagePanelContent;
|
||
set => SetProperty(ref _imagePanelContent, value);
|
||
}
|
||
|
||
public GridLength ImagePanelWidth
|
||
{
|
||
get => _imagePanelWidth;
|
||
set => SetProperty(ref _imagePanelWidth, value);
|
||
}
|
||
|
||
public GridLength ViewportPanelWidth
|
||
{
|
||
get => _viewportPanelWidth;
|
||
set => SetProperty(ref _viewportPanelWidth, value);
|
||
}
|
||
|
||
private void ShowWindow(Window window, string name)
|
||
{
|
||
window.Owner = Application.Current.MainWindow;
|
||
window.Show();
|
||
_logger.Info("{Name} 窗口已打开", name);
|
||
}
|
||
|
||
private void ShowOrActivate(Window currentWindow, Action<Window> setWindow, Func<Window> factory, string name)
|
||
{
|
||
if (currentWindow != null && currentWindow.IsLoaded)
|
||
{
|
||
currentWindow.Activate();
|
||
return;
|
||
}
|
||
|
||
var window = factory();
|
||
window.Owner = Application.Current.MainWindow;
|
||
window.ShowInTaskbar = true;
|
||
window.Closed += (s, e) => setWindow(null);
|
||
window.Show();
|
||
setWindow(window);
|
||
_logger.Info("{Name} 窗口已打开", name);
|
||
}
|
||
|
||
private void ExecuteOpenToolbox()
|
||
{
|
||
ShowOrActivate(_toolboxWindow, w => _toolboxWindow = w, () => new Views.OperatorToolboxWindow(), "算子工具箱");
|
||
}
|
||
|
||
private void ExecuteOpenCncEditor()
|
||
{
|
||
if (_isCncEditorMode)
|
||
{
|
||
ImagePanelContent = new PipelineEditorView();
|
||
ViewportPanelWidth = new GridLength(1, GridUnitType.Star);
|
||
ImagePanelWidth = new GridLength(320);
|
||
_isCncEditorMode = false;
|
||
_logger.Info("已退出 CNC 编辑模式");
|
||
return;
|
||
}
|
||
|
||
ShowCncEditor();
|
||
}
|
||
|
||
private void ExecuteCncEditorAction(Action<CncEditorViewModel> action)
|
||
{
|
||
ArgumentNullException.ThrowIfNull(action);
|
||
ShowCncEditor();
|
||
action(_cncEditorViewModel);
|
||
}
|
||
|
||
private void ShowCncEditor()
|
||
{
|
||
ImagePanelContent = _cncPageView;
|
||
ViewportPanelWidth = new GridLength(1, GridUnitType.Star);
|
||
ImagePanelWidth = new GridLength(CncEditorHostWidth);
|
||
_isCncEditorMode = true;
|
||
_logger.Info("CNC 编辑器已切换到主界面图像区域");
|
||
}
|
||
|
||
private void ExecuteOpenUserManual()
|
||
{
|
||
try
|
||
{
|
||
var manualPath = ConfigurationManager.AppSettings["UserManual"];
|
||
if (string.IsNullOrEmpty(manualPath))
|
||
{
|
||
_logger.Warn("未配置用户手册路径");
|
||
MessageBox.Show("未配置用户手册路径,请检查 App.config 中的 UserManual 配置项。",
|
||
"提示", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||
return;
|
||
}
|
||
|
||
if (!File.Exists(manualPath))
|
||
{
|
||
_logger.Warn("用户手册文件不存在:{Path}", manualPath);
|
||
MessageBox.Show($"用户手册文件不存在:\n{manualPath}",
|
||
"提示", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||
return;
|
||
}
|
||
|
||
var pdfViewerService = _containerProvider.Resolve<IPdfViewerService>();
|
||
var stream = File.OpenRead(manualPath);
|
||
var fileName = Path.GetFileName(manualPath);
|
||
pdfViewerService.OpenViewer(stream, fileName);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.Error(ex, "打开用户手册失败");
|
||
MessageBox.Show($"打开用户手册失败:{ex.Message}",
|
||
"错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||
}
|
||
}
|
||
|
||
private void ExecuteOpenCameraSettings()
|
||
{
|
||
try
|
||
{
|
||
var vm = _containerProvider.Resolve<NavigationPropertyPanelViewModel>();
|
||
if (!vm.IsCameraConnected)
|
||
{
|
||
MessageBox.Show("请先连接相机", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
||
return;
|
||
}
|
||
|
||
var window = new Views.CameraSettingsWindow(vm) { Owner = Application.Current.MainWindow };
|
||
window.Show();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.Error(ex, "打开相机设置失败");
|
||
}
|
||
}
|
||
|
||
private void ExecuteAxisReset()
|
||
{
|
||
var result = MessageBox.Show("确认执行轴复位操作?", "轴复位",
|
||
MessageBoxButton.OKCancel, MessageBoxImage.Question);
|
||
if (result != MessageBoxResult.OK)
|
||
return;
|
||
|
||
try
|
||
{
|
||
var motionSystem = _containerProvider.Resolve<IMotionSystem>();
|
||
var resetResult = motionSystem.AxisReset.Reset();
|
||
if (!resetResult.Success)
|
||
{
|
||
MessageBox.Show($"轴复位失败:{resetResult.ErrorMessage}", "错误",
|
||
MessageBoxButton.OK, MessageBoxImage.Warning);
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.Error(ex, "轴复位异常");
|
||
MessageBox.Show($"轴复位异常:{ex.Message}", "错误",
|
||
MessageBoxButton.OK, MessageBoxImage.Error);
|
||
}
|
||
}
|
||
|
||
private void ExecuteOpenDetectorConfig()
|
||
{
|
||
try
|
||
{
|
||
ShowOrActivate(_detectorConfigWindow, w => _detectorConfigWindow = w,
|
||
() => new XP.Hardware.Detector.Views.DetectorConfigWindow(), "探测器配置");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.Error(ex, "打开探测器配置窗口失败");
|
||
MessageBox.Show($"打开探测器配置窗口失败:\n{ex.InnerException?.Message ?? ex.Message}",
|
||
"错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||
}
|
||
}
|
||
|
||
private void ExecuteOpenMotionDebug()
|
||
{
|
||
ShowOrActivate(_motionDebugWindow, w => _motionDebugWindow = w,
|
||
() => new XP.Hardware.MotionControl.Views.MotionDebugWindow(), "运动调试");
|
||
}
|
||
|
||
private void ExecuteOpenPlcAddrConfig()
|
||
{
|
||
ShowOrActivate(_plcAddrConfigWindow, w => _plcAddrConfigWindow = w,
|
||
() => _containerProvider.Resolve<XP.Hardware.PLC.Views.PlcAddrConfigEditorWindow>(), "PLC 地址配置");
|
||
}
|
||
|
||
private void ExecuteOpenRaySourceConfig()
|
||
{
|
||
ShowOrActivate(_raySourceConfigWindow, w => _raySourceConfigWindow = w,
|
||
() => new XP.Hardware.RaySource.Views.RaySourceConfigWindow(), "射线源配置");
|
||
}
|
||
|
||
private void ExecuteLoadImage()
|
||
{
|
||
var dialog = new OpenFileDialog
|
||
{
|
||
Title = "加载图像",
|
||
Filter = "图像文件|*.bmp;*.png;*.jpg;*.jpeg;*.tif;*.tiff|所有文件|*.*"
|
||
};
|
||
|
||
if (dialog.ShowDialog() != true)
|
||
return;
|
||
|
||
try
|
||
{
|
||
var bitmap = new BitmapImage();
|
||
bitmap.BeginInit();
|
||
bitmap.UriSource = new Uri(dialog.FileName, UriKind.Absolute);
|
||
bitmap.CacheOption = BitmapCacheOption.OnLoad;
|
||
bitmap.EndInit();
|
||
bitmap.Freeze();
|
||
|
||
_logger.Info("[图像链路] ExecuteLoadImage:加载图像 {Path},准备推送到 MainViewportService 和 ManualImageLoadedEvent", dialog.FileName);
|
||
_mainViewportService.SetManualImage(bitmap, dialog.FileName);
|
||
|
||
// 同时发布事件,让 PipelineEditorViewModel 收到图像并触发流水线执行
|
||
_eventAggregator.GetEvent<ManualImageLoadedEvent>()
|
||
.Publish(new ManualImageLoadedPayload(bitmap, dialog.FileName));
|
||
_logger.Info("[图像链路] ManualImageLoadedEvent 已发布");
|
||
|
||
RaisePropertyChanged(nameof(IsUsingLiveDetectorSource));
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.Error(ex, "加载图像失败:{Path}", dialog.FileName);
|
||
MessageBox.Show($"加载图像失败:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||
}
|
||
}
|
||
|
||
private void ExecuteUseLiveDetectorSource()
|
||
{
|
||
_mainViewportService.SetSourceMode(MainViewportSourceMode.LiveDetector);
|
||
RaisePropertyChanged(nameof(IsUsingLiveDetectorSource));
|
||
}
|
||
|
||
private void ExecuteWarmUp()
|
||
{
|
||
var messageBoxResult = MessageBox.Show("确认执行射线源暖机操作?", "暖机",
|
||
MessageBoxButton.OKCancel, MessageBoxImage.Question);
|
||
if (messageBoxResult != MessageBoxResult.OK)
|
||
return;
|
||
|
||
try
|
||
{
|
||
var raySourceService = _containerProvider.Resolve<XP.Hardware.RaySource.Services.IRaySourceService>();
|
||
var result = raySourceService.WarmUp();
|
||
if (!result.Success)
|
||
{
|
||
MessageBox.Show($"暖机失败:{result.ErrorMessage}", "错误",
|
||
MessageBoxButton.OK, MessageBoxImage.Warning);
|
||
}
|
||
else
|
||
{
|
||
_logger.Info("暖机命令已发送");
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.Error(ex, "暖机异常");
|
||
MessageBox.Show($"暖机异常:{ex.Message}", "错误",
|
||
MessageBoxButton.OK, MessageBoxImage.Error);
|
||
}
|
||
}
|
||
|
||
#region 测量命令实现
|
||
|
||
private bool CheckImageLoaded()
|
||
{
|
||
try
|
||
{
|
||
var viewportVm = _containerProvider.Resolve<ViewportPanelViewModel>();
|
||
if (viewportVm?.ImageSource != null) return true;
|
||
}
|
||
catch { }
|
||
HexMessageBox.Show("请先加载图像", MessageBoxButton.OK, MessageBoxImage.Information);
|
||
return false;
|
||
}
|
||
|
||
|
||
private void ExecutePointDistanceMeasure()
|
||
{
|
||
if (!CheckImageLoaded()) return;
|
||
_logger.Info("点点距测量功能已触发");
|
||
_eventAggregator.GetEvent<MeasurementToolEvent>().Publish(MeasurementToolMode.PointDistance);
|
||
}
|
||
|
||
private void ExecutePointLineDistanceMeasure()
|
||
{
|
||
if (!CheckImageLoaded()) return;
|
||
_logger.Info("点线距测量功能已触发");
|
||
_eventAggregator.GetEvent<MeasurementToolEvent>().Publish(MeasurementToolMode.PointLineDistance);
|
||
}
|
||
|
||
private void ExecuteAngleMeasure()
|
||
{
|
||
if (!CheckImageLoaded()) return;
|
||
_logger.Info("角度测量功能已触发");
|
||
_eventAggregator.GetEvent<MeasurementToolEvent>().Publish(MeasurementToolMode.Angle);
|
||
}
|
||
|
||
private void ExecuteThroughHoleFillRateMeasure()
|
||
{
|
||
if (!CheckImageLoaded()) return;
|
||
_logger.Info("通孔填锡率测量功能已触发");
|
||
_eventAggregator.GetEvent<MeasurementToolEvent>().Publish(MeasurementToolMode.ThroughHoleFillRate);
|
||
}
|
||
|
||
private Window _bgaMeasurePanel;
|
||
|
||
private void ExecuteBgaVoidMeasure()
|
||
{
|
||
if (!CheckImageLoaded()) return;
|
||
_logger.Info("BGA空隙测量功能已触发");
|
||
_eventAggregator.GetEvent<MeasurementToolEvent>().Publish(MeasurementToolMode.BgaVoid);
|
||
|
||
if (_bgaMeasurePanel != null && _bgaMeasurePanel.IsVisible)
|
||
{
|
||
_bgaMeasurePanel.Activate();
|
||
return;
|
||
}
|
||
|
||
_bgaMeasurePanel = new Views.ImageProcessing.BgaMeasurePanel
|
||
{
|
||
Owner = System.Windows.Application.Current.MainWindow
|
||
};
|
||
_bgaMeasurePanel.Closed += (s, e) =>
|
||
{
|
||
_eventAggregator.GetEvent<MeasurementToolEvent>().Publish(MeasurementToolMode.None);
|
||
};
|
||
_bgaMeasurePanel.Show();
|
||
}
|
||
|
||
private Window _bubbleMeasurePanel;
|
||
|
||
private void ExecuteBubbleMeasure()
|
||
{
|
||
if (!CheckImageLoaded()) return;
|
||
_logger.Info("气泡测量功能已触发");
|
||
|
||
// 进入气泡测量模式
|
||
_eventAggregator.GetEvent<MeasurementToolEvent>().Publish(MeasurementToolMode.BubbleMeasure);
|
||
|
||
// 弹出工具面板
|
||
if (_bubbleMeasurePanel != null && _bubbleMeasurePanel.IsVisible)
|
||
{
|
||
_bubbleMeasurePanel.Activate();
|
||
return;
|
||
}
|
||
|
||
_bubbleMeasurePanel = new Views.ImageProcessing.BubbleMeasurePanel
|
||
{
|
||
Owner = System.Windows.Application.Current.MainWindow
|
||
};
|
||
_bubbleMeasurePanel.Closed += (s, e) =>
|
||
{
|
||
// 关闭面板时退出气泡测量模式
|
||
_eventAggregator.GetEvent<MeasurementToolEvent>().Publish(MeasurementToolMode.None);
|
||
};
|
||
_bubbleMeasurePanel.Show();
|
||
|
||
}
|
||
|
||
private void ExecuteOpenLanguageSwitcher()
|
||
{
|
||
try
|
||
{
|
||
var viewModel = _containerProvider.Resolve<XP.Common.Localization.ViewModels.LanguageSwitcherViewModel>();
|
||
var window = new XP.Common.Localization.Views.LanguageSwitcherWindow(viewModel)
|
||
{
|
||
Owner = Application.Current.MainWindow,
|
||
ShowInTaskbar = true
|
||
};
|
||
window.ShowDialog();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.Error(ex, "打开语言设置失败");
|
||
}
|
||
}
|
||
|
||
private void ExecuteOpenRealTimeLogViewer()
|
||
{
|
||
ShowOrActivate(_realTimeLogViewerWindow, w => _realTimeLogViewerWindow = w,
|
||
() => new XP.Common.GeneralForm.Views.RealTimeLogViewer(), "实时日志");
|
||
}
|
||
|
||
private void OnNavigateHome()
|
||
{
|
||
_logger.Info("导航到主页");
|
||
LicenseInfo = "主页";
|
||
}
|
||
|
||
private void OnNavigateInspect()
|
||
{
|
||
_logger.Info("导航到检测页面");
|
||
LicenseInfo = "检测页面";
|
||
}
|
||
|
||
private void OnOpenFile()
|
||
{
|
||
_logger.Info("打开文件");
|
||
LicenseInfo = "打开文件";
|
||
}
|
||
|
||
private void OnExport()
|
||
{
|
||
_logger.Info("导出数据");
|
||
LicenseInfo = "导出数据";
|
||
}
|
||
|
||
private void OnClear()
|
||
{
|
||
_logger.Info("清除数据");
|
||
LicenseInfo = "清除数据";
|
||
}
|
||
|
||
private void OnEditProperties()
|
||
{
|
||
_logger.Info("编辑属性");
|
||
LicenseInfo = "编辑属性";
|
||
}
|
||
|
||
private void OnMainViewportStateChanged(object sender, EventArgs e)
|
||
{
|
||
Application.Current?.Dispatcher?.BeginInvoke(new Action(() =>
|
||
{
|
||
RaisePropertyChanged(nameof(IsMainViewportRealtimeEnabled));
|
||
RaisePropertyChanged(nameof(IsUsingLiveDetectorSource));
|
||
}));
|
||
}
|
||
|
||
private void OnPipelinePreviewUpdated(PipelinePreviewUpdatedPayload payload)
|
||
{
|
||
if (payload?.Image == null)
|
||
{
|
||
_logger.Warn("[图像链路] OnPipelinePreviewUpdated:payload 或 Image 为 null,跳过");
|
||
return;
|
||
}
|
||
_logger.Info("[图像链路] OnPipelinePreviewUpdated:收到流水线结果图像,推送到 MainViewportService");
|
||
_mainViewportService.SetManualImage(payload.Image, string.Empty);
|
||
}
|
||
}
|
||
}
|