修复CNC模式下,+号订阅事件;修复CNC和普通模式的切换问题

This commit is contained in:
zhengxuan.zhang
2026-05-07 13:31:14 +08:00
parent 3c9b3a2731
commit 8500f8b5ed
5 changed files with 73 additions and 2 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

@@ -324,6 +324,9 @@ namespace XplorePlane.ViewModels.Cnc
} }
} }
/// <summary>供外部直接 await 的保存方法</summary>
public Task SaveAsync() => ExecuteSaveProgramAsync();
private async Task ExecuteSaveProgramAsync() private async Task ExecuteSaveProgramAsync()
{ {
if (_currentProgram == null) if (_currentProgram == null)
@@ -77,6 +77,9 @@ namespace XplorePlane.ViewModels.Cnc
_editorViewModel.PropertyChanged += OnEditorPropertyChanged; _editorViewModel.PropertyChanged += OnEditorPropertyChanged;
RefreshFromSelection(); RefreshFromSelection();
_eventAggregator?.GetEvent<AddOperatorRequestedEvent>()
.Subscribe(key => { if (CanAddOperator(key)) AddOperator(key); });
} }
public ObservableCollection<PipelineNodeViewModel> PipelineNodes { get; } public ObservableCollection<PipelineNodeViewModel> PipelineNodes { get; }
@@ -174,6 +177,9 @@ namespace XplorePlane.ViewModels.Cnc
RaiseCommandCanExecuteChanged(); RaiseCommandCanExecuteChanged();
} }
private bool CanAddOperator(string operatorKey) =>
HasActiveModule && !string.IsNullOrWhiteSpace(operatorKey);
private void AddOperator(string operatorKey) private void AddOperator(string operatorKey)
{ {
if (!HasActiveModule || string.IsNullOrWhiteSpace(operatorKey)) if (!HasActiveModule || string.IsNullOrWhiteSpace(operatorKey))
@@ -42,6 +42,7 @@ namespace XplorePlane.ViewModels
private string _pipelineFileDisplayName = DefaultPipelineFileDisplayName; private string _pipelineFileDisplayName = DefaultPipelineFileDisplayName;
private string _currentFilePath; private string _currentFilePath;
private PipelineNodeViewModel _executionEndNode; private PipelineNodeViewModel _executionEndNode;
private bool _isModified;
private CancellationTokenSource _executionCts; private CancellationTokenSource _executionCts;
private CancellationTokenSource _debounceCts; private CancellationTokenSource _debounceCts;
@@ -172,6 +173,13 @@ namespace XplorePlane.ViewModels
private set => SetProperty(ref _pipelineFileDisplayName, value); private set => SetProperty(ref _pipelineFileDisplayName, value);
} }
/// <summary>流水线是否有未保存的修改</summary>
public bool IsModified
{
get => _isModified;
private set => SetProperty(ref _isModified, value);
}
public PipelineNodeViewModel ExecutionEndNode public PipelineNodeViewModel ExecutionEndNode
{ {
get => _executionEndNode; get => _executionEndNode;
@@ -266,6 +274,7 @@ namespace XplorePlane.ViewModels
_logger.Info("节点已添加到 PipelineNodes{Key} ({DisplayName}),当前节点数={Count}", _logger.Info("节点已添加到 PipelineNodes{Key} ({DisplayName}),当前节点数={Count}",
operatorKey, displayName, PipelineNodes.Count); operatorKey, displayName, PipelineNodes.Count);
SetInfoStatus($"已添加算子:{displayName}"); SetInfoStatus($"已添加算子:{displayName}");
IsModified = true;
TriggerDebouncedExecution(); TriggerDebouncedExecution();
} }
@@ -283,6 +292,7 @@ namespace XplorePlane.ViewModels
SelectNeighborAfterRemoval(removedIndex); SelectNeighborAfterRemoval(removedIndex);
SetInfoStatus($"已移除算子:{node.DisplayName}"); SetInfoStatus($"已移除算子:{node.DisplayName}");
IsModified = true;
TriggerDebouncedExecution(); TriggerDebouncedExecution();
} }
@@ -294,6 +304,7 @@ namespace XplorePlane.ViewModels
PipelineNodes.Move(index, index - 1); PipelineNodes.Move(index, index - 1);
RenumberNodes(); RenumberNodes();
UpdateExecutionRangeState(); UpdateExecutionRangeState();
IsModified = true;
TriggerDebouncedExecution(); TriggerDebouncedExecution();
} }
@@ -305,6 +316,7 @@ namespace XplorePlane.ViewModels
PipelineNodes.Move(index, index + 1); PipelineNodes.Move(index, index + 1);
RenumberNodes(); RenumberNodes();
UpdateExecutionRangeState(); UpdateExecutionRangeState();
IsModified = true;
TriggerDebouncedExecution(); TriggerDebouncedExecution();
} }
@@ -325,6 +337,7 @@ namespace XplorePlane.ViewModels
UpdateExecutionRangeState(); UpdateExecutionRangeState();
SelectedNode = node; SelectedNode = node;
SetInfoStatus($"已调整算子顺序:{node.DisplayName}"); SetInfoStatus($"已调整算子顺序:{node.DisplayName}");
IsModified = true;
TriggerDebouncedExecution(); TriggerDebouncedExecution();
} }
@@ -337,6 +350,7 @@ namespace XplorePlane.ViewModels
SetInfoStatus(node.IsEnabled SetInfoStatus(node.IsEnabled
? $"已启用算子:{node.DisplayName}" ? $"已启用算子:{node.DisplayName}"
: $"已停用算子:{node.DisplayName}"); : $"已停用算子:{node.DisplayName}");
IsModified = true;
TriggerDebouncedExecution(); TriggerDebouncedExecution();
} }
@@ -406,6 +420,7 @@ namespace XplorePlane.ViewModels
{ {
if (e.PropertyName == nameof(ProcessorParameterVM.Value)) if (e.PropertyName == nameof(ProcessorParameterVM.Value))
{ {
IsModified = true;
if (TryReportInvalidParameters()) if (TryReportInvalidParameters())
return; return;
@@ -623,9 +638,13 @@ namespace XplorePlane.ViewModels
PreviewImage = null; PreviewImage = null;
_currentFilePath = null; _currentFilePath = null;
PipelineFileDisplayName = DefaultPipelineFileDisplayName; PipelineFileDisplayName = DefaultPipelineFileDisplayName;
IsModified = false;
SetInfoStatus("已新建流水线"); SetInfoStatus("已新建流水线");
} }
/// <summary>供外部直接 await 的保存方法</summary>
public Task SaveAsync() => SavePipelineAsync();
private async Task SavePipelineAsync() private async Task SavePipelineAsync()
{ {
if (string.IsNullOrWhiteSpace(PipelineName) || PipelineName.Length > 100) if (string.IsNullOrWhiteSpace(PipelineName) || PipelineName.Length > 100)
@@ -674,6 +693,7 @@ namespace XplorePlane.ViewModels
var model = BuildPipelineModel(); var model = BuildPipelineModel();
await _persistenceService.SaveAsync(model, filePath); await _persistenceService.SaveAsync(model, filePath);
PipelineFileDisplayName = FormatPipelinePath(filePath); PipelineFileDisplayName = FormatPipelinePath(filePath);
IsModified = false;
SetInfoStatus($"流水线已保存:{Path.GetFileName(filePath)}"); SetInfoStatus($"流水线已保存:{Path.GetFileName(filePath)}");
} }
catch (IOException ex) catch (IOException ex)
@@ -750,6 +770,7 @@ namespace XplorePlane.ViewModels
UpdateExecutionRangeState(); UpdateExecutionRangeState();
_logger.Info("流水线已加载:{Name},节点数={Count}", model.Name, PipelineNodes.Count); _logger.Info("流水线已加载:{Name},节点数={Count}", model.Name, PipelineNodes.Count);
IsModified = false;
SetInfoStatus($"已加载流水线:{model.Name}{PipelineNodes.Count} 个节点)"); SetInfoStatus($"已加载流水线:{model.Name}{PipelineNodes.Count} 个节点)");
} }
catch (Exception ex) catch (Exception ex)
+43 -2
View File
@@ -36,6 +36,8 @@ namespace XplorePlane.ViewModels
private readonly IXpDataPathService _xpDataPathService; private readonly IXpDataPathService _xpDataPathService;
private readonly CncEditorViewModel _cncEditorViewModel; private readonly CncEditorViewModel _cncEditorViewModel;
private readonly CncPageView _cncPageView; private readonly CncPageView _cncPageView;
private readonly PipelineEditorViewModel _pipelineEditorViewModel;
private readonly PipelineEditorView _pipelineEditorView;
public string LicenseInfo public string LicenseInfo
{ {
@@ -212,6 +214,8 @@ namespace XplorePlane.ViewModels
_xpDataPathService = xpDataPathService ?? throw new ArgumentNullException(nameof(xpDataPathService)); _xpDataPathService = xpDataPathService ?? throw new ArgumentNullException(nameof(xpDataPathService));
_cncEditorViewModel = _containerProvider.Resolve<CncEditorViewModel>(); _cncEditorViewModel = _containerProvider.Resolve<CncEditorViewModel>();
_cncPageView = new CncPageView { DataContext = _cncEditorViewModel }; _cncPageView = new CncPageView { DataContext = _cncEditorViewModel };
_pipelineEditorViewModel = _containerProvider.Resolve<PipelineEditorViewModel>();
_pipelineEditorView = new PipelineEditorView { DataContext = _pipelineEditorViewModel };
_mainViewportService.StateChanged += OnMainViewportStateChanged; _mainViewportService.StateChanged += OnMainViewportStateChanged;
_cncEditorViewModel.PropertyChanged += (s, e) => _cncEditorViewModel.PropertyChanged += (s, e) =>
@@ -310,7 +314,7 @@ namespace XplorePlane.ViewModels
OpenRealTimeLogViewerCommand = new DelegateCommand(ExecuteOpenRealTimeLogViewer); OpenRealTimeLogViewerCommand = new DelegateCommand(ExecuteOpenRealTimeLogViewer);
UseLiveDetectorSourceCommand = new DelegateCommand(ExecuteUseLiveDetectorSource); UseLiveDetectorSourceCommand = new DelegateCommand(ExecuteUseLiveDetectorSource);
ImagePanelContent = new PipelineEditorView(); ImagePanelContent = _pipelineEditorView;
ViewportPanelWidth = new GridLength(1, GridUnitType.Star); ViewportPanelWidth = new GridLength(1, GridUnitType.Star);
ImagePanelWidth = new GridLength(320); ImagePanelWidth = new GridLength(320);
DataRootPath = _xpDataPathService.RootPath; DataRootPath = _xpDataPathService.RootPath;
@@ -352,10 +356,31 @@ namespace XplorePlane.ViewModels
} }
private void ExecuteOpenCncEditor() private void ExecuteOpenCncEditor()
{
_ = ExecuteOpenCncEditorAsync();
}
private async Task ExecuteOpenCncEditorAsync()
{ {
if (_isCncEditorMode) if (_isCncEditorMode)
{ {
ImagePanelContent = new PipelineEditorView(); // CNC → 普通模式:检查 CNC 程序是否有未保存修改
if (_cncEditorViewModel.IsModified)
{
var result = MessageBox.Show(
"CNC 程序有未保存的修改,是否保存?",
"未保存的修改",
MessageBoxButton.YesNoCancel,
MessageBoxImage.Warning);
if (result == MessageBoxResult.Cancel)
return;
if (result == MessageBoxResult.Yes)
await _cncEditorViewModel.SaveAsync();
}
ImagePanelContent = _pipelineEditorView;
ViewportPanelWidth = new GridLength(1, GridUnitType.Star); ViewportPanelWidth = new GridLength(1, GridUnitType.Star);
ImagePanelWidth = new GridLength(320); ImagePanelWidth = new GridLength(320);
_isCncEditorMode = false; _isCncEditorMode = false;
@@ -363,6 +388,22 @@ namespace XplorePlane.ViewModels
return; return;
} }
// 普通 → CNC 模式:检查流水线是否有未保存修改
if (_pipelineEditorViewModel.IsModified)
{
var result = MessageBox.Show(
"图像处理流水线有未保存的修改,是否保存?",
"未保存的修改",
MessageBoxButton.YesNoCancel,
MessageBoxImage.Warning);
if (result == MessageBoxResult.Cancel)
return;
if (result == MessageBoxResult.Yes)
await _pipelineEditorViewModel.SaveAsync();
}
ShowCncEditor(); ShowCncEditor();
} }