From 514eace979016dc9dc3ccc6c996145d40de0da86 Mon Sep 17 00:00:00 2001 From: "zhengxuan.zhang" Date: Tue, 28 Apr 2026 14:13:12 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8DCNC=E8=BF=90=E8=A1=8C=20?= =?UTF-8?q?=E4=B8=8E=E7=AE=97=E5=AD=90=E7=BC=96=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CncInspectionModulePipelineViewModel.cs | 66 ++++++++++++++++++- XplorePlane/Views/Cnc/CncPageView.xaml.cs | 8 ++- 2 files changed, 72 insertions(+), 2 deletions(-) diff --git a/XplorePlane/ViewModels/Cnc/CncInspectionModulePipelineViewModel.cs b/XplorePlane/ViewModels/Cnc/CncInspectionModulePipelineViewModel.cs index d119c0c..24c4b6f 100644 --- a/XplorePlane/ViewModels/Cnc/CncInspectionModulePipelineViewModel.cs +++ b/XplorePlane/ViewModels/Cnc/CncInspectionModulePipelineViewModel.cs @@ -8,11 +8,17 @@ using System.ComponentModel; using System.IO; using System.Linq; using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; using System.Windows; using System.Windows.Input; +using System.Windows.Media.Imaging; +using XplorePlane.Events; using XplorePlane.Models; using XplorePlane.Services; +using XplorePlane.Services.MainViewport; using XP.Common.Logging.Interfaces; +using Prism.Events; namespace XplorePlane.ViewModels.Cnc { @@ -21,6 +27,9 @@ namespace XplorePlane.ViewModels.Cnc private readonly CncEditorViewModel _editorViewModel; private readonly IImageProcessingService _imageProcessingService; private readonly IPipelinePersistenceService _persistenceService; + private readonly IPipelineExecutionService _executionService; + private readonly IMainViewportService _mainViewportService; + private readonly IEventAggregator _eventAggregator; private readonly ILoggerService _logger; private CncNodeViewModel _activeModuleNode; @@ -29,17 +38,26 @@ namespace XplorePlane.ViewModels.Cnc private string _pipelineFileDisplayName = "未命名模块.xpm"; private string _currentFilePath; private bool _isSynchronizing; + private CancellationTokenSource _debounceCts; + + private const int DebounceDelayMs = 300; public CncInspectionModulePipelineViewModel( CncEditorViewModel editorViewModel, IImageProcessingService imageProcessingService, IPipelinePersistenceService persistenceService, - ILoggerService logger) + ILoggerService logger, + IPipelineExecutionService executionService = null, + IMainViewportService mainViewportService = null, + IEventAggregator eventAggregator = null) { _editorViewModel = editorViewModel ?? throw new ArgumentNullException(nameof(editorViewModel)); _imageProcessingService = imageProcessingService ?? throw new ArgumentNullException(nameof(imageProcessingService)); _persistenceService = persistenceService ?? throw new ArgumentNullException(nameof(persistenceService)); _logger = (logger ?? throw new ArgumentNullException(nameof(logger))).ForModule(); + _executionService = executionService; + _mainViewportService = mainViewportService; + _eventAggregator = eventAggregator; PipelineNodes = new ObservableCollection(); @@ -373,6 +391,52 @@ namespace XplorePlane.ViewModels.Cnc _activeModuleNode.Pipeline = BuildPipelineModel(); StatusMessage = statusMessage; + TriggerDebouncedPreview(); + } + + private void TriggerDebouncedPreview() + { + if (_executionService == null || _mainViewportService == null) + return; + + var sourceImage = _mainViewportService.CurrentDisplayImage as BitmapSource + ?? _mainViewportService.LatestManualImage as BitmapSource; + if (sourceImage == null) + { + _logger.Debug("[图像链路][CNC] TriggerDebouncedPreview:无可用源图像,跳过"); + return; + } + + _debounceCts?.Cancel(); + _debounceCts = new CancellationTokenSource(); + var token = _debounceCts.Token; + + Task.Delay(DebounceDelayMs, token).ContinueWith(t => + { + if (!t.IsCanceled) + _ = ExecutePreviewAsync(sourceImage, token); + }, TaskScheduler.FromCurrentSynchronizationContext()); + } + + private async Task ExecutePreviewAsync(BitmapSource sourceImage, CancellationToken token) + { + try + { + _logger.Info("[图像链路][CNC] ExecutePreviewAsync:开始执行,节点数={Count}", PipelineNodes.Count); + var result = await _executionService.ExecutePipelineAsync(PipelineNodes, sourceImage, null, token); + _logger.Info("[图像链路][CNC] ExecutePreviewAsync:执行完成,推送结果图像"); + _mainViewportService.SetManualImage(result, string.Empty); + _eventAggregator?.GetEvent() + .Publish(new PipelinePreviewUpdatedPayload(result, StatusMessage)); + } + catch (OperationCanceledException) + { + _logger.Debug("[图像链路][CNC] ExecutePreviewAsync:已取消"); + } + catch (Exception ex) + { + _logger.Error(ex, "[图像链路][CNC] ExecutePreviewAsync:执行失败"); + } } private PipelineModel BuildPipelineModel() diff --git a/XplorePlane/Views/Cnc/CncPageView.xaml.cs b/XplorePlane/Views/Cnc/CncPageView.xaml.cs index 9c56a20..c69f085 100644 --- a/XplorePlane/Views/Cnc/CncPageView.xaml.cs +++ b/XplorePlane/Views/Cnc/CncPageView.xaml.cs @@ -61,12 +61,18 @@ namespace XplorePlane.Views.Cnc var imageProcessingService = ContainerLocator.Current.Resolve(); var persistenceService = ContainerLocator.Current.Resolve(); var logger = ContainerLocator.Current.Resolve(); + var executionService = ContainerLocator.Current.Resolve(); + var mainViewportService = ContainerLocator.Current.Resolve(); + var eventAggregator = ContainerLocator.Current.Resolve(); _inspectionModulePipelineViewModel = new CncInspectionModulePipelineViewModel( editorViewModel, imageProcessingService, persistenceService, - logger); + logger, + executionService, + mainViewportService, + eventAggregator); InspectionModulePipelineEditor.DataContext = _inspectionModulePipelineViewModel; }