对 流程图 新增 4个状态 已启用 已停用 执行到此 未参与本次执行 和右键菜单,执行到此,执行全部
This commit is contained in:
@@ -37,6 +37,7 @@ namespace XplorePlane.ViewModels.Cnc
|
||||
private string _statusMessage = "请选择检测模块以编辑其流水线。";
|
||||
private string _pipelineFileDisplayName = "未命名模块.xpm";
|
||||
private string _currentFilePath;
|
||||
private PipelineNodeViewModel _executionEndNode;
|
||||
private bool _isSynchronizing;
|
||||
private CancellationTokenSource _debounceCts;
|
||||
|
||||
@@ -65,6 +66,8 @@ namespace XplorePlane.ViewModels.Cnc
|
||||
RemoveOperatorCommand = new DelegateCommand<PipelineNodeViewModel>(RemoveOperator);
|
||||
ReorderOperatorCommand = new DelegateCommand<PipelineReorderArgs>(ReorderOperator);
|
||||
ToggleOperatorEnabledCommand = new DelegateCommand<PipelineNodeViewModel>(ToggleOperatorEnabled);
|
||||
ExecuteToNodeCommand = new DelegateCommand<PipelineNodeViewModel>(ExecuteToNode);
|
||||
ClearExecutionRangeCommand = new DelegateCommand(ClearExecutionRange);
|
||||
MoveNodeUpCommand = new DelegateCommand<PipelineNodeViewModel>(MoveNodeUp);
|
||||
MoveNodeDownCommand = new DelegateCommand<PipelineNodeViewModel>(MoveNodeDown);
|
||||
NewPipelineCommand = new DelegateCommand(NewPipeline);
|
||||
@@ -98,6 +101,16 @@ namespace XplorePlane.ViewModels.Cnc
|
||||
private set => SetProperty(ref _pipelineFileDisplayName, value);
|
||||
}
|
||||
|
||||
public PipelineNodeViewModel ExecutionEndNode
|
||||
{
|
||||
get => _executionEndNode;
|
||||
private set
|
||||
{
|
||||
if (SetProperty(ref _executionEndNode, value))
|
||||
UpdateExecutionRangeState();
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasActiveModule => _activeModuleNode?.IsInspectionModule == true;
|
||||
|
||||
public Visibility EditorVisibility => HasActiveModule ? Visibility.Visible : Visibility.Collapsed;
|
||||
@@ -112,6 +125,10 @@ namespace XplorePlane.ViewModels.Cnc
|
||||
|
||||
public ICommand ToggleOperatorEnabledCommand { get; }
|
||||
|
||||
public ICommand ExecuteToNodeCommand { get; }
|
||||
|
||||
public ICommand ClearExecutionRangeCommand { get; }
|
||||
|
||||
public ICommand MoveNodeUpCommand { get; }
|
||||
|
||||
public ICommand MoveNodeDownCommand { get; }
|
||||
@@ -179,6 +196,7 @@ namespace XplorePlane.ViewModels.Cnc
|
||||
LoadNodeParameters(node, null);
|
||||
PipelineNodes.Add(node);
|
||||
SelectedNode = node;
|
||||
UpdateExecutionRangeState();
|
||||
PersistActiveModule($"已添加算子:{displayName}");
|
||||
}
|
||||
|
||||
@@ -190,6 +208,10 @@ namespace XplorePlane.ViewModels.Cnc
|
||||
var removedIndex = PipelineNodes.IndexOf(node);
|
||||
PipelineNodes.Remove(node);
|
||||
RenumberNodes();
|
||||
if (ReferenceEquals(ExecutionEndNode, node))
|
||||
ExecutionEndNode = null;
|
||||
else
|
||||
UpdateExecutionRangeState();
|
||||
SelectNeighborAfterRemoval(removedIndex);
|
||||
|
||||
PersistActiveModule($"已移除算子:{node.DisplayName}");
|
||||
@@ -206,6 +228,7 @@ namespace XplorePlane.ViewModels.Cnc
|
||||
|
||||
PipelineNodes.Move(index, index - 1);
|
||||
RenumberNodes();
|
||||
UpdateExecutionRangeState();
|
||||
PersistActiveModule($"已上移算子:{node.DisplayName}");
|
||||
}
|
||||
|
||||
@@ -225,6 +248,7 @@ namespace XplorePlane.ViewModels.Cnc
|
||||
var node = PipelineNodes[oldIndex];
|
||||
PipelineNodes.Move(oldIndex, newIndex);
|
||||
RenumberNodes();
|
||||
UpdateExecutionRangeState();
|
||||
SelectedNode = node;
|
||||
PersistActiveModule($"已调整算子顺序:{node.DisplayName}");
|
||||
}
|
||||
@@ -240,6 +264,7 @@ namespace XplorePlane.ViewModels.Cnc
|
||||
|
||||
PipelineNodes.Move(index, index + 1);
|
||||
RenumberNodes();
|
||||
UpdateExecutionRangeState();
|
||||
PersistActiveModule($"已下移算子:{node.DisplayName}");
|
||||
}
|
||||
|
||||
@@ -255,6 +280,25 @@ namespace XplorePlane.ViewModels.Cnc
|
||||
: $"已停用算子:{node.DisplayName}");
|
||||
}
|
||||
|
||||
private void ExecuteToNode(PipelineNodeViewModel node)
|
||||
{
|
||||
if (!HasActiveModule || node == null || !PipelineNodes.Contains(node))
|
||||
return;
|
||||
|
||||
SelectedNode = node;
|
||||
ExecutionEndNode = node;
|
||||
PersistActiveModule($"已设置执行截止点:{node.DisplayName}");
|
||||
}
|
||||
|
||||
private void ClearExecutionRange()
|
||||
{
|
||||
if (!HasActiveModule || ExecutionEndNode == null)
|
||||
return;
|
||||
|
||||
ExecutionEndNode = null;
|
||||
PersistActiveModule("已切换为执行全部节点");
|
||||
}
|
||||
|
||||
private void NewPipeline()
|
||||
{
|
||||
if (!HasActiveModule)
|
||||
@@ -262,6 +306,7 @@ namespace XplorePlane.ViewModels.Cnc
|
||||
|
||||
PipelineNodes.Clear();
|
||||
SelectedNode = null;
|
||||
ExecutionEndNode = null;
|
||||
_currentFilePath = null;
|
||||
PipelineFileDisplayName = GetActivePipelineFileDisplayName();
|
||||
PersistActiveModule("已为当前检测模块新建空流水线。");
|
||||
@@ -326,6 +371,7 @@ namespace XplorePlane.ViewModels.Cnc
|
||||
{
|
||||
PipelineNodes.Clear();
|
||||
SelectedNode = null;
|
||||
ExecutionEndNode = null;
|
||||
|
||||
var orderedNodes = (pipeline?.Nodes ?? new List<PipelineNodeModel>())
|
||||
.OrderBy(node => node.Order)
|
||||
@@ -346,6 +392,7 @@ namespace XplorePlane.ViewModels.Cnc
|
||||
}
|
||||
|
||||
SelectedNode = PipelineNodes.FirstOrDefault();
|
||||
UpdateExecutionRangeState();
|
||||
if (string.IsNullOrEmpty(_currentFilePath))
|
||||
PipelineFileDisplayName = GetActivePipelineFileDisplayName();
|
||||
StatusMessage = HasActiveModule
|
||||
@@ -423,7 +470,7 @@ namespace XplorePlane.ViewModels.Cnc
|
||||
try
|
||||
{
|
||||
_logger.Info("[图像链路][CNC] ExecutePreviewAsync:开始执行,节点数={Count}", PipelineNodes.Count);
|
||||
var result = await _executionService.ExecutePipelineAsync(PipelineNodes, sourceImage, null, token);
|
||||
var result = await _executionService.ExecutePipelineAsync(GetNodesInExecutionScope(), sourceImage, null, token);
|
||||
_logger.Info("[图像链路][CNC] ExecutePreviewAsync:执行完成,推送结果图像");
|
||||
_mainViewportService.SetManualImage(result, string.Empty);
|
||||
_eventAggregator?.GetEvent<PipelinePreviewUpdatedEvent>()
|
||||
@@ -459,6 +506,15 @@ namespace XplorePlane.ViewModels.Cnc
|
||||
};
|
||||
}
|
||||
|
||||
private IEnumerable<PipelineNodeViewModel> GetNodesInExecutionScope()
|
||||
{
|
||||
var orderedNodes = PipelineNodes.OrderBy(node => node.Order);
|
||||
if (ExecutionEndNode == null)
|
||||
return orderedNodes;
|
||||
|
||||
return orderedNodes.Where(node => node.Order <= ExecutionEndNode.Order);
|
||||
}
|
||||
|
||||
private string GetActivePipelineName()
|
||||
{
|
||||
if (!HasActiveModule)
|
||||
@@ -492,6 +548,19 @@ namespace XplorePlane.ViewModels.Cnc
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateExecutionRangeState()
|
||||
{
|
||||
if (_executionEndNode != null && !PipelineNodes.Contains(_executionEndNode))
|
||||
_executionEndNode = null;
|
||||
|
||||
var endOrder = _executionEndNode?.Order;
|
||||
foreach (var node in PipelineNodes)
|
||||
{
|
||||
node.IsExecutionEndNode = endOrder.HasValue && node.Order == endOrder.Value;
|
||||
node.IsSkippedByExecutionRange = endOrder.HasValue && node.Order > endOrder.Value;
|
||||
}
|
||||
}
|
||||
|
||||
private void SelectNeighborAfterRemoval(int removedIndex)
|
||||
{
|
||||
if (PipelineNodes.Count == 0)
|
||||
|
||||
@@ -23,6 +23,10 @@ namespace XplorePlane.ViewModels
|
||||
|
||||
ICommand ToggleOperatorEnabledCommand { get; }
|
||||
|
||||
ICommand ExecuteToNodeCommand { get; }
|
||||
|
||||
ICommand ClearExecutionRangeCommand { get; }
|
||||
|
||||
ICommand MoveNodeUpCommand { get; }
|
||||
|
||||
ICommand MoveNodeDownCommand { get; }
|
||||
|
||||
@@ -39,6 +39,7 @@ namespace XplorePlane.ViewModels
|
||||
private string _statusMessage = string.Empty;
|
||||
private string _pipelineFileDisplayName = DefaultPipelineFileDisplayName;
|
||||
private string _currentFilePath;
|
||||
private PipelineNodeViewModel _executionEndNode;
|
||||
|
||||
private CancellationTokenSource _executionCts;
|
||||
private CancellationTokenSource _debounceCts;
|
||||
@@ -64,6 +65,8 @@ namespace XplorePlane.ViewModels
|
||||
ReorderOperatorCommand = new DelegateCommand<PipelineReorderArgs>(ReorderOperator);
|
||||
ToggleOperatorEnabledCommand = new DelegateCommand<PipelineNodeViewModel>(ToggleOperatorEnabled);
|
||||
ExecutePipelineCommand = new DelegateCommand(async () => await ExecutePipelineAsync(), () => !IsExecuting && SourceImage != null);
|
||||
ExecuteToNodeCommand = new DelegateCommand<PipelineNodeViewModel>(async node => await ExecuteToNodeAsync(node), CanExecuteToNode);
|
||||
ClearExecutionRangeCommand = new DelegateCommand(async () => await ClearExecutionRangeAsync(), CanClearExecutionRange);
|
||||
CancelExecutionCommand = new DelegateCommand(CancelExecution, () => IsExecuting);
|
||||
NewPipelineCommand = new DelegateCommand(NewPipeline);
|
||||
SavePipelineCommand = new DelegateCommand(async () => await SavePipelineAsync());
|
||||
@@ -162,6 +165,20 @@ namespace XplorePlane.ViewModels
|
||||
private set => SetProperty(ref _pipelineFileDisplayName, value);
|
||||
}
|
||||
|
||||
public PipelineNodeViewModel ExecutionEndNode
|
||||
{
|
||||
get => _executionEndNode;
|
||||
private set
|
||||
{
|
||||
if (SetProperty(ref _executionEndNode, value))
|
||||
{
|
||||
UpdateExecutionRangeState();
|
||||
ExecuteToNodeCommand.RaiseCanExecuteChanged();
|
||||
ClearExecutionRangeCommand.RaiseCanExecuteChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Commands ──────────────────────────────────────────────────
|
||||
|
||||
public DelegateCommand<string> AddOperatorCommand { get; }
|
||||
@@ -169,6 +186,8 @@ namespace XplorePlane.ViewModels
|
||||
public DelegateCommand<PipelineReorderArgs> ReorderOperatorCommand { get; }
|
||||
public DelegateCommand<PipelineNodeViewModel> ToggleOperatorEnabledCommand { get; }
|
||||
public DelegateCommand ExecutePipelineCommand { get; }
|
||||
public DelegateCommand<PipelineNodeViewModel> ExecuteToNodeCommand { get; }
|
||||
public DelegateCommand ClearExecutionRangeCommand { get; }
|
||||
public DelegateCommand CancelExecutionCommand { get; }
|
||||
public DelegateCommand NewPipelineCommand { get; }
|
||||
public DelegateCommand SavePipelineCommand { get; }
|
||||
@@ -184,6 +203,8 @@ namespace XplorePlane.ViewModels
|
||||
ICommand IPipelineEditorHostViewModel.RemoveOperatorCommand => RemoveOperatorCommand;
|
||||
ICommand IPipelineEditorHostViewModel.ReorderOperatorCommand => ReorderOperatorCommand;
|
||||
ICommand IPipelineEditorHostViewModel.ToggleOperatorEnabledCommand => ToggleOperatorEnabledCommand;
|
||||
ICommand IPipelineEditorHostViewModel.ExecuteToNodeCommand => ExecuteToNodeCommand;
|
||||
ICommand IPipelineEditorHostViewModel.ClearExecutionRangeCommand => ClearExecutionRangeCommand;
|
||||
ICommand IPipelineEditorHostViewModel.MoveNodeUpCommand => MoveNodeUpCommand;
|
||||
ICommand IPipelineEditorHostViewModel.MoveNodeDownCommand => MoveNodeDownCommand;
|
||||
ICommand IPipelineEditorHostViewModel.NewPipelineCommand => NewPipelineCommand;
|
||||
@@ -234,6 +255,7 @@ namespace XplorePlane.ViewModels
|
||||
LoadNodeParameters(node);
|
||||
PipelineNodes.Add(node);
|
||||
SelectedNode = node;
|
||||
UpdateExecutionRangeState();
|
||||
_logger.Info("节点已添加到 PipelineNodes:{Key} ({DisplayName}),当前节点数={Count}",
|
||||
operatorKey, displayName, PipelineNodes.Count);
|
||||
SetInfoStatus($"已添加算子:{displayName}");
|
||||
@@ -247,6 +269,10 @@ namespace XplorePlane.ViewModels
|
||||
var removedIndex = PipelineNodes.IndexOf(node);
|
||||
PipelineNodes.Remove(node);
|
||||
RenumberNodes();
|
||||
if (ReferenceEquals(ExecutionEndNode, node))
|
||||
ExecutionEndNode = null;
|
||||
else
|
||||
UpdateExecutionRangeState();
|
||||
SelectNeighborAfterRemoval(removedIndex);
|
||||
|
||||
SetInfoStatus($"已移除算子:{node.DisplayName}");
|
||||
@@ -260,6 +286,7 @@ namespace XplorePlane.ViewModels
|
||||
if (index <= 0) return;
|
||||
PipelineNodes.Move(index, index - 1);
|
||||
RenumberNodes();
|
||||
UpdateExecutionRangeState();
|
||||
TriggerDebouncedExecution();
|
||||
}
|
||||
|
||||
@@ -270,6 +297,7 @@ namespace XplorePlane.ViewModels
|
||||
if (index < 0 || index >= PipelineNodes.Count - 1) return;
|
||||
PipelineNodes.Move(index, index + 1);
|
||||
RenumberNodes();
|
||||
UpdateExecutionRangeState();
|
||||
TriggerDebouncedExecution();
|
||||
}
|
||||
|
||||
@@ -287,6 +315,7 @@ namespace XplorePlane.ViewModels
|
||||
PipelineNodes.RemoveAt(oldIndex);
|
||||
PipelineNodes.Insert(newIndex, node);
|
||||
RenumberNodes();
|
||||
UpdateExecutionRangeState();
|
||||
SelectedNode = node;
|
||||
SetInfoStatus($"已调整算子顺序:{node.DisplayName}");
|
||||
TriggerDebouncedExecution();
|
||||
@@ -304,6 +333,34 @@ namespace XplorePlane.ViewModels
|
||||
TriggerDebouncedExecution();
|
||||
}
|
||||
|
||||
private bool CanExecuteToNode(PipelineNodeViewModel node) =>
|
||||
node != null && PipelineNodes.Contains(node) && !IsExecuting && SourceImage != null;
|
||||
|
||||
private async Task ExecuteToNodeAsync(PipelineNodeViewModel node)
|
||||
{
|
||||
if (!CanExecuteToNode(node))
|
||||
return;
|
||||
|
||||
SelectedNode = node;
|
||||
ExecutionEndNode = node;
|
||||
await ExecutePipelineAsync();
|
||||
}
|
||||
|
||||
private bool CanClearExecutionRange() =>
|
||||
ExecutionEndNode != null && !IsExecuting;
|
||||
|
||||
private async Task ClearExecutionRangeAsync()
|
||||
{
|
||||
if (ExecutionEndNode == null)
|
||||
return;
|
||||
|
||||
ExecutionEndNode = null;
|
||||
SetInfoStatus("已切换为执行全部节点");
|
||||
|
||||
if (SourceImage != null)
|
||||
await ExecutePipelineAsync();
|
||||
}
|
||||
|
||||
private void RenumberNodes()
|
||||
{
|
||||
for (int i = 0; i < PipelineNodes.Count; i++)
|
||||
@@ -367,10 +424,15 @@ namespace XplorePlane.ViewModels
|
||||
_executionCts?.Cancel();
|
||||
_executionCts = new CancellationTokenSource();
|
||||
var token = _executionCts.Token;
|
||||
var executionNodes = GetNodesInExecutionScope()
|
||||
.Where(n => n.IsEnabled)
|
||||
.OrderBy(n => n.Order)
|
||||
.ToList();
|
||||
|
||||
IsExecuting = true;
|
||||
SetInfoStatus("正在执行流水线...");
|
||||
_logger.Info("[图像链路] ExecutePipelineAsync:开始执行,节点数={Count}", PipelineNodes.Count);
|
||||
SetInfoStatus(BuildExecutionStartMessage(executionNodes.Count));
|
||||
_logger.Info("[图像链路] ExecutePipelineAsync:开始执行,范围节点数={Count},截止节点={Node}",
|
||||
executionNodes.Count, ExecutionEndNode?.DisplayName ?? "<all>");
|
||||
|
||||
try
|
||||
{
|
||||
@@ -378,10 +440,10 @@ namespace XplorePlane.ViewModels
|
||||
SetInfoStatus($"执行中:{p.CurrentOperator} ({p.CurrentStep}/{p.TotalSteps})"));
|
||||
|
||||
var result = await _executionService.ExecutePipelineAsync(
|
||||
PipelineNodes, SourceImage, progress, token);
|
||||
executionNodes, SourceImage, progress, token);
|
||||
|
||||
PreviewImage = result;
|
||||
SetInfoStatus("流水线执行完成");
|
||||
SetInfoStatus(BuildExecutionCompletedMessage(executionNodes.Count));
|
||||
_logger.Info("[图像链路] ExecutePipelineAsync:执行完成,准备发布 PipelinePreviewUpdatedEvent");
|
||||
PublishPipelinePreviewUpdated(result, StatusMessage);
|
||||
}
|
||||
@@ -408,7 +470,7 @@ namespace XplorePlane.ViewModels
|
||||
|
||||
private bool TryReportInvalidParameters()
|
||||
{
|
||||
var firstInvalidNode = PipelineNodes
|
||||
var firstInvalidNode = GetNodesInExecutionScope()
|
||||
.Where(n => n.IsEnabled)
|
||||
.OrderBy(n => n.Order)
|
||||
.FirstOrDefault(n => n.Parameters.Any(p => !p.IsValueValid));
|
||||
@@ -549,6 +611,7 @@ namespace XplorePlane.ViewModels
|
||||
{
|
||||
PipelineNodes.Clear();
|
||||
SelectedNode = null;
|
||||
ExecutionEndNode = null;
|
||||
PipelineName = "新建流水线";
|
||||
PreviewImage = null;
|
||||
_currentFilePath = null;
|
||||
@@ -648,6 +711,7 @@ namespace XplorePlane.ViewModels
|
||||
|
||||
PipelineNodes.Clear();
|
||||
SelectedNode = null;
|
||||
ExecutionEndNode = null;
|
||||
|
||||
PipelineName = model.Name;
|
||||
SelectedDevice = model.DeviceId;
|
||||
@@ -676,6 +740,8 @@ namespace XplorePlane.ViewModels
|
||||
PipelineNodes.Add(node);
|
||||
}
|
||||
|
||||
UpdateExecutionRangeState();
|
||||
|
||||
_logger.Info("流水线已加载:{Name},节点数={Count}", model.Name, PipelineNodes.Count);
|
||||
SetInfoStatus($"已加载流水线:{model.Name}({PipelineNodes.Count} 个节点)");
|
||||
}
|
||||
@@ -704,6 +770,44 @@ namespace XplorePlane.ViewModels
|
||||
};
|
||||
}
|
||||
|
||||
private System.Collections.Generic.IEnumerable<PipelineNodeViewModel> GetNodesInExecutionScope()
|
||||
{
|
||||
var orderedNodes = PipelineNodes.OrderBy(n => n.Order);
|
||||
if (ExecutionEndNode == null)
|
||||
return orderedNodes;
|
||||
|
||||
return orderedNodes.Where(n => n.Order <= ExecutionEndNode.Order);
|
||||
}
|
||||
|
||||
private void UpdateExecutionRangeState()
|
||||
{
|
||||
if (_executionEndNode != null && !PipelineNodes.Contains(_executionEndNode))
|
||||
_executionEndNode = null;
|
||||
|
||||
var endOrder = _executionEndNode?.Order;
|
||||
foreach (var node in PipelineNodes)
|
||||
{
|
||||
node.IsExecutionEndNode = endOrder.HasValue && node.Order == endOrder.Value;
|
||||
node.IsSkippedByExecutionRange = endOrder.HasValue && node.Order > endOrder.Value;
|
||||
}
|
||||
}
|
||||
|
||||
private string BuildExecutionStartMessage(int executionCount)
|
||||
{
|
||||
if (ExecutionEndNode == null)
|
||||
return "正在执行流水线...";
|
||||
|
||||
return $"正在执行到“{ExecutionEndNode.DisplayName}” ({executionCount} 个有效节点)...";
|
||||
}
|
||||
|
||||
private string BuildExecutionCompletedMessage(int executionCount)
|
||||
{
|
||||
if (ExecutionEndNode == null)
|
||||
return "流水线执行完成";
|
||||
|
||||
return $"已执行到“{ExecutionEndNode.DisplayName}” ({executionCount} 个有效节点)";
|
||||
}
|
||||
|
||||
private static string GetPipelineDirectory()
|
||||
{
|
||||
var dir = Path.Combine(
|
||||
|
||||
@@ -11,6 +11,8 @@ namespace XplorePlane.ViewModels
|
||||
private int _order;
|
||||
private bool _isSelected;
|
||||
private bool _isEnabled = true;
|
||||
private bool _isExecutionEndNode;
|
||||
private bool _isSkippedByExecutionRange;
|
||||
|
||||
public PipelineNodeViewModel(string operatorKey, string displayName, string iconPath = null)
|
||||
{
|
||||
@@ -51,9 +53,49 @@ namespace XplorePlane.ViewModels
|
||||
public bool IsEnabled
|
||||
{
|
||||
get => _isEnabled;
|
||||
set => SetProperty(ref _isEnabled, value);
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _isEnabled, value))
|
||||
RaisePropertyChanged(nameof(NodeStateText));
|
||||
}
|
||||
}
|
||||
|
||||
public ObservableCollection<ProcessorParameterVM> Parameters { get; }
|
||||
|
||||
public bool IsExecutionEndNode
|
||||
{
|
||||
get => _isExecutionEndNode;
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _isExecutionEndNode, value))
|
||||
RaisePropertyChanged(nameof(NodeStateText));
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsSkippedByExecutionRange
|
||||
{
|
||||
get => _isSkippedByExecutionRange;
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _isSkippedByExecutionRange, value))
|
||||
RaisePropertyChanged(nameof(NodeStateText));
|
||||
}
|
||||
}
|
||||
|
||||
public string NodeStateText
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsExecutionEndNode && !IsEnabled)
|
||||
return "执行到此(停用)";
|
||||
if (IsExecutionEndNode)
|
||||
return "执行到此";
|
||||
if (!IsEnabled)
|
||||
return "已停用";
|
||||
if (IsSkippedByExecutionRange)
|
||||
return "未参与本次执行";
|
||||
return "已启用";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,7 +205,7 @@ namespace XplorePlane.ViewModels
|
||||
|
||||
|
||||
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);
|
||||
|
||||
@@ -99,6 +99,19 @@
|
||||
Content="加载"
|
||||
Style="{StaticResource ToolbarBtn}"
|
||||
ToolTip="加载流水线" />
|
||||
<Button
|
||||
Width="84"
|
||||
Command="{Binding ExecuteToNodeCommand}"
|
||||
CommandParameter="{Binding SelectedNode}"
|
||||
Content="执行到当前"
|
||||
Style="{StaticResource ToolbarBtn}"
|
||||
ToolTip="执行到当前选中的节点" />
|
||||
<Button
|
||||
Width="68"
|
||||
Command="{Binding ClearExecutionRangeCommand}"
|
||||
Content="执行全部"
|
||||
Style="{StaticResource ToolbarBtn}"
|
||||
ToolTip="清除截止位置并执行全部节点" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock
|
||||
@@ -132,10 +145,20 @@
|
||||
x:Name="NodeContainer"
|
||||
Margin="2"
|
||||
Padding="2"
|
||||
Tag="{Binding DataContext, ElementName=RootControl}"
|
||||
Background="Transparent"
|
||||
BorderBrush="Transparent"
|
||||
BorderThickness="1"
|
||||
CornerRadius="3">
|
||||
<Border.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem Header="执行到此处"
|
||||
Command="{Binding PlacementTarget.Tag.ExecuteToNodeCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
|
||||
CommandParameter="{Binding}" />
|
||||
<MenuItem Header="执行全部"
|
||||
Command="{Binding PlacementTarget.Tag.ClearExecutionRangeCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
|
||||
</ContextMenu>
|
||||
</Border.ContextMenu>
|
||||
<Grid x:Name="NodeRoot" MinHeight="48">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="44" />
|
||||
@@ -193,7 +216,7 @@
|
||||
FontFamily="{StaticResource UiFont}"
|
||||
FontSize="10"
|
||||
Foreground="#6E6E6E"
|
||||
Text="已启用" />
|
||||
Text="{Binding NodeStateText}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
@@ -209,13 +232,37 @@
|
||||
<Setter TargetName="IconBorder" Property="BorderBrush" Value="{StaticResource DisabledNodeLine}" />
|
||||
<Setter TargetName="IconBorder" Property="Background" Value="#ECECEC" />
|
||||
<Setter TargetName="NodeTitle" Property="Foreground" Value="{StaticResource DisabledNodeText}" />
|
||||
<Setter TargetName="NodeState" Property="Text" Value="已停用" />
|
||||
<Setter TargetName="NodeState" Property="Foreground" Value="#9A6767" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding IsExecutionEndNode}" Value="True">
|
||||
<Setter TargetName="NodeContainer" Property="Background" Value="#E8F6EA" />
|
||||
<Setter TargetName="NodeContainer" Property="BorderBrush" Value="#4F9D69" />
|
||||
<Setter TargetName="IconBorder" Property="Background" Value="#E8F6EA" />
|
||||
<Setter TargetName="IconBorder" Property="BorderBrush" Value="#4F9D69" />
|
||||
<Setter TargetName="NodeState" Property="Foreground" Value="#2E7D32" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding IsSkippedByExecutionRange}" Value="True">
|
||||
<Setter TargetName="NodeContainer" Property="Background" Value="#FAFAFA" />
|
||||
<Setter TargetName="NodeContainer" Property="Opacity" Value="0.72" />
|
||||
<Setter TargetName="TopLine" Property="Stroke" Value="#D0D0D0" />
|
||||
<Setter TargetName="BottomLine" Property="Stroke" Value="#D0D0D0" />
|
||||
<Setter TargetName="IconBorder" Property="BorderBrush" Value="#C8C8C8" />
|
||||
<Setter TargetName="IconBorder" Property="Background" Value="#F4F4F4" />
|
||||
<Setter TargetName="NodeTitle" Property="Foreground" Value="#909090" />
|
||||
<Setter TargetName="NodeState" Property="Foreground" Value="#A0A0A0" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem}, Path=IsSelected}" Value="True">
|
||||
<Setter TargetName="NodeContainer" Property="Background" Value="#D9ECFF" />
|
||||
<Setter TargetName="NodeContainer" Property="BorderBrush" Value="#5B9BD5" />
|
||||
</DataTrigger>
|
||||
<MultiDataTrigger>
|
||||
<MultiDataTrigger.Conditions>
|
||||
<Condition Binding="{Binding IsExecutionEndNode}" Value="True" />
|
||||
<Condition Binding="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem}, Path=IsSelected}" Value="True" />
|
||||
</MultiDataTrigger.Conditions>
|
||||
<Setter TargetName="NodeContainer" Property="Background" Value="#DFF0E3" />
|
||||
<Setter TargetName="NodeContainer" Property="BorderBrush" Value="#3F8A58" />
|
||||
</MultiDataTrigger>
|
||||
<MultiDataTrigger>
|
||||
<MultiDataTrigger.Conditions>
|
||||
<Condition Binding="{Binding IsEnabled}" Value="False" />
|
||||
@@ -225,6 +272,15 @@
|
||||
<Setter TargetName="NodeContainer" Property="BorderBrush" Value="#7E9AB6" />
|
||||
<Setter TargetName="NodeContainer" Property="Opacity" Value="1" />
|
||||
</MultiDataTrigger>
|
||||
<MultiDataTrigger>
|
||||
<MultiDataTrigger.Conditions>
|
||||
<Condition Binding="{Binding IsSkippedByExecutionRange}" Value="True" />
|
||||
<Condition Binding="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem}, Path=IsSelected}" Value="True" />
|
||||
</MultiDataTrigger.Conditions>
|
||||
<Setter TargetName="NodeContainer" Property="Background" Value="#EEF1F4" />
|
||||
<Setter TargetName="NodeContainer" Property="BorderBrush" Value="#AAB4BF" />
|
||||
<Setter TargetName="NodeContainer" Property="Opacity" Value="0.9" />
|
||||
</MultiDataTrigger>
|
||||
</DataTemplate.Triggers>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
|
||||
@@ -59,6 +59,8 @@ namespace XplorePlane.Views
|
||||
PipelineListBox.PreviewMouseMove += OnPreviewMouseMove;
|
||||
PipelineListBox.PreviewMouseLeftButtonUp -= OnPreviewMouseLeftButtonUp;
|
||||
PipelineListBox.PreviewMouseLeftButtonUp += OnPreviewMouseLeftButtonUp;
|
||||
PipelineListBox.PreviewMouseRightButtonDown -= OnPreviewMouseRightButtonDown;
|
||||
PipelineListBox.PreviewMouseRightButtonDown += OnPreviewMouseRightButtonDown;
|
||||
PipelineListBox.MouseDoubleClick -= OnMouseDoubleClick;
|
||||
PipelineListBox.MouseDoubleClick += OnMouseDoubleClick;
|
||||
PipelineListBox.PreviewKeyDown -= OnPreviewKeyDown;
|
||||
@@ -133,6 +135,16 @@ namespace XplorePlane.Views
|
||||
ResetDragState();
|
||||
}
|
||||
|
||||
private void OnPreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
var clickedNode = FindNodeFromOriginalSource(e.OriginalSource);
|
||||
if (clickedNode == null || IsInteractiveChild(e.OriginalSource))
|
||||
return;
|
||||
|
||||
PipelineListBox.SelectedItem = clickedNode;
|
||||
PipelineListBox.Focus();
|
||||
}
|
||||
|
||||
private void OnMouseDoubleClick(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
var vm = DataContext as IPipelineEditorHostViewModel;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
<Page Remove="MainWindow.xaml" />
|
||||
<Page Remove="Views\ImageProcessing\ImageProcessingPanelView.xaml" />
|
||||
<Page Remove="Views\ImageProcessing\ImageProcessingWindow.xaml" />
|
||||
<Page Remove="Views\ImageProcessing\PipelineEditorWindow.xaml" />
|
||||
<Page Remove="Views\Main\MainWindowB.xaml" />
|
||||
<Page Remove="Views\Main\NavigationPanelView.xaml" />
|
||||
</ItemGroup>
|
||||
@@ -151,6 +152,7 @@
|
||||
</None>
|
||||
<Compile Remove="Views\ImageProcessing\ImageProcessingPanelView.xaml.cs" />
|
||||
<Compile Remove="Views\ImageProcessing\ImageProcessingWindow.xaml.cs" />
|
||||
<Compile Remove="Views\ImageProcessing\PipelineEditorWindow.xaml.cs" />
|
||||
<Compile Remove="Views\Main\MainWindowB.xaml.cs" />
|
||||
<Compile Remove="Views\Main\NavigationPanelView.xaml.cs" />
|
||||
<Content Include="XplorerPlane.ico">
|
||||
|
||||
Reference in New Issue
Block a user