Files
XplorePlane/XplorePlane/ViewModels/Main/MainViewModel.cs
T
2026-04-24 11:18:44 +08:00

491 lines
20 KiB
C#

using Prism.Commands;
using Prism.Events;
using Prism.Ioc;
using Prism.Mvvm;
using Microsoft.Win32;
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.ViewModels.Cnc;
using XplorePlane.Views;
using XplorePlane.Views.Cnc;
using XP.Common.Logging.Interfaces;
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 CncEditorViewModel _cncEditorViewModel;
private readonly CncPageView _cncPageView;
private string _licenseInfo = "当前时间";
public string LicenseInfo
{
get => _licenseInfo;
set => SetProperty(ref _licenseInfo, 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 OpenLanguageSwitcherCommand { get; }
public DelegateCommand OpenRealTimeLogViewerCommand { get; }
/// <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 GridLength(1, GridUnitType.Star);
private GridLength _imagePanelWidth = new GridLength(320);
private bool _isCncEditorMode;
public MainViewModel(ILoggerService logger, IContainerProvider containerProvider, IEventAggregator eventAggregator)
{
_logger = logger?.ForModule<MainViewModel>() ?? throw new ArgumentNullException(nameof(logger));
_containerProvider = containerProvider ?? throw new ArgumentNullException(nameof(containerProvider));
_eventAggregator = eventAggregator ?? throw new ArgumentNullException(nameof(eventAggregator));
_cncEditorViewModel = _containerProvider.Resolve<CncEditorViewModel>();
_cncPageView = new CncPageView { DataContext = _cncEditorViewModel };
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()));
// 硬件命令
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);
ImagePanelContent = new PipelineEditorView();
ViewportPanelWidth = new GridLength(1, GridUnitType.Star);
ImagePanelWidth = new GridLength(320);
_logger.Info("MainViewModel 已初始化");
}
#region
/// <summary>
/// 显示一个新窗口(非模态)
/// </summary>
private void ShowWindow(Window window, string name)
{
window.Owner = Application.Current.MainWindow;
window.Show();
_logger.Info("{Name} 窗口已打开", name);
}
/// <summary>
/// 显示或激活单例窗口(非模态,防止重复打开)
/// </summary>
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);
}
#endregion
#region
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, "打开相机设置失败");
}
}
#endregion
#region
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();
_eventAggregator.GetEvent<ManualImageLoadedEvent>()
.Publish(new ManualImageLoadedPayload(bitmap, dialog.FileName));
}
catch (Exception ex)
{
_logger.Error(ex, "加载图像失败:{Path}", dialog.FileName);
MessageBox.Show($"加载图像失败:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
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);
}
}
#endregion
#region
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(), "实时日志");
}
#endregion
#region
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 = "编辑属性";
}
#endregion
}
}