1、当前根节点选择中是 高亮背景和文字不协调,文字改为黑色
2、延时节点执行时,进度条显示功能失效,修复 3、自动执行,当加载CNC后,点击rabbion中运行,此时没有看到执行中,已执行,等高亮规则
This commit is contained in:
@@ -95,7 +95,7 @@ namespace XplorePlane.Services.Cnc
|
||||
break;
|
||||
}
|
||||
|
||||
progress?.Report(new CncNodeExecutionProgress(node.Id, NodeExecutionState.Running));
|
||||
progress?.Report(new CncNodeExecutionProgress(node.Id, NodeExecutionState.Running, ProgressPercent: 0));
|
||||
|
||||
bool nodeSucceeded = true;
|
||||
|
||||
@@ -106,7 +106,7 @@ namespace XplorePlane.Services.Cnc
|
||||
case WaitDelayNode waitNode:
|
||||
try
|
||||
{
|
||||
await ExecuteWaitDelayWithProgressAsync(waitNode, cancellationToken);
|
||||
await ExecuteWaitDelayWithProgressAsync(waitNode, progress, cancellationToken);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
@@ -324,11 +324,17 @@ namespace XplorePlane.Services.Cnc
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
||||
private static async Task ExecuteWaitDelayWithProgressAsync(WaitDelayNode waitNode, CancellationToken cancellationToken)
|
||||
private static async Task ExecuteWaitDelayWithProgressAsync(
|
||||
WaitDelayNode waitNode,
|
||||
IProgress<CncNodeExecutionProgress> progress,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
int totalMs = waitNode.DelayMilliseconds;
|
||||
if (totalMs <= 0)
|
||||
{
|
||||
progress?.Report(new CncNodeExecutionProgress(waitNode.Id, NodeExecutionState.Running, ProgressPercent: 100));
|
||||
return;
|
||||
}
|
||||
|
||||
const int tickMs = 50;
|
||||
|
||||
@@ -341,6 +347,10 @@ namespace XplorePlane.Services.Cnc
|
||||
int delay = Math.Min(tickMs, remaining);
|
||||
await Task.Delay(delay, cancellationToken);
|
||||
elapsed += delay;
|
||||
progress?.Report(new CncNodeExecutionProgress(
|
||||
waitNode.Id,
|
||||
NodeExecutionState.Running,
|
||||
ProgressPercent: elapsed * 100d / totalMs));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,11 @@ namespace XplorePlane.Services.Cnc
|
||||
/// <summary>
|
||||
/// Progress report for a single CNC node execution.
|
||||
/// ResultImage is non-null when an InspectionModuleNode produces output.
|
||||
/// ProgressPercent is used by long-running nodes such as WaitDelayNode.
|
||||
/// </summary>
|
||||
public record CncNodeExecutionProgress(Guid NodeId, NodeExecutionState State, BitmapSource ResultImage = null);
|
||||
public record CncNodeExecutionProgress(
|
||||
Guid NodeId,
|
||||
NodeExecutionState State,
|
||||
BitmapSource ResultImage = null,
|
||||
double? ProgressPercent = null);
|
||||
}
|
||||
|
||||
@@ -455,6 +455,7 @@ namespace XplorePlane.ViewModels.Cnc
|
||||
private async Task ExecuteRunAsync()
|
||||
{
|
||||
_cts = new CancellationTokenSource();
|
||||
ResetAllNodeStates();
|
||||
IsRunning = true;
|
||||
HasExecutionError = false;
|
||||
ExecutionError = null;
|
||||
@@ -482,7 +483,6 @@ namespace XplorePlane.ViewModels.Cnc
|
||||
finally
|
||||
{
|
||||
IsRunning = false;
|
||||
ResetAllNodeStates();
|
||||
_cts?.Dispose();
|
||||
_cts = null;
|
||||
}
|
||||
@@ -499,6 +499,7 @@ namespace XplorePlane.ViewModels.Cnc
|
||||
if (nodeVm != null)
|
||||
{
|
||||
nodeVm.ExecutionState = progress.State;
|
||||
nodeVm.ExecutionProgressPercent = progress.ProgressPercent ?? (progress.State == NodeExecutionState.Succeeded ? 100d : 0d);
|
||||
if (progress.State == NodeExecutionState.Running)
|
||||
StatusMessage = $"正在执行节点:{nodeVm.Name}({nodeVm.Index + 1}/{_currentProgram?.Nodes?.Count ?? 0})";
|
||||
else if (progress.State == NodeExecutionState.Succeeded)
|
||||
@@ -519,7 +520,10 @@ namespace XplorePlane.ViewModels.Cnc
|
||||
private void ResetAllNodeStates()
|
||||
{
|
||||
foreach (var node in Nodes)
|
||||
{
|
||||
node.ExecutionState = NodeExecutionState.Idle;
|
||||
node.ExecutionProgressPercent = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void RaiseEditCommandsCanExecuteChanged()
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace XplorePlane.ViewModels.Cnc
|
||||
private string _icon;
|
||||
private bool _isExpanded = true;
|
||||
private NodeExecutionState _executionState = NodeExecutionState.Idle;
|
||||
private double _executionProgressPercent;
|
||||
|
||||
/// <summary>执行后缓存的流水线输出图像(仅 InspectionModuleNode)</summary>
|
||||
public BitmapSource ResultImage { get; set; }
|
||||
@@ -72,6 +73,7 @@ namespace XplorePlane.ViewModels.Cnc
|
||||
RaisePropertyChanged(nameof(IsRunningNode));
|
||||
RaisePropertyChanged(nameof(IsSucceededNode));
|
||||
RaisePropertyChanged(nameof(IsFailedNode));
|
||||
RaisePropertyChanged(nameof(IsDelayProgressVisible));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,6 +81,21 @@ namespace XplorePlane.ViewModels.Cnc
|
||||
public bool IsRunningNode => ExecutionState == NodeExecutionState.Running;
|
||||
public bool IsSucceededNode => ExecutionState == NodeExecutionState.Succeeded;
|
||||
public bool IsFailedNode => ExecutionState == NodeExecutionState.Failed;
|
||||
public bool IsDelayProgressVisible => IsWaitDelay && IsRunningNode;
|
||||
|
||||
public double ExecutionProgressPercent
|
||||
{
|
||||
get => _executionProgressPercent;
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _executionProgressPercent, Math.Clamp(value, 0d, 100d)))
|
||||
{
|
||||
RaisePropertyChanged(nameof(ExecutionProgressText));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string ExecutionProgressText => $"{ExecutionProgressPercent:0}%";
|
||||
|
||||
public bool IsReferencePoint => _model is ReferencePointNode;
|
||||
public bool IsSaveNode => _model is SaveNodeNode;
|
||||
@@ -567,6 +584,9 @@ namespace XplorePlane.ViewModels.Cnc
|
||||
RaisePropertyChanged(nameof(IsRunningNode));
|
||||
RaisePropertyChanged(nameof(IsSucceededNode));
|
||||
RaisePropertyChanged(nameof(IsFailedNode));
|
||||
RaisePropertyChanged(nameof(IsDelayProgressVisible));
|
||||
RaisePropertyChanged(nameof(ExecutionProgressPercent));
|
||||
RaisePropertyChanged(nameof(ExecutionProgressText));
|
||||
}
|
||||
|
||||
private enum MotionAxis
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace XplorePlane.ViewModels
|
||||
private PipelineNodeViewModel _selectedNode;
|
||||
private BitmapSource _sourceImage;
|
||||
private BitmapSource _previewImage;
|
||||
private string _pipelineName = "新建流水线";
|
||||
private string _pipelineName = "新建模块";
|
||||
private string _selectedDevice = string.Empty;
|
||||
private bool _isExecuting;
|
||||
private bool _isStatusError;
|
||||
@@ -646,7 +646,7 @@ namespace XplorePlane.ViewModels
|
||||
|
||||
var dialog = new SaveFileDialog
|
||||
{
|
||||
Filter = "XP 模块流水线 (*.xpm)|*.xpm",
|
||||
Filter = "XP 模块 (*.xpm)|*.xpm",
|
||||
DefaultExt = ".xpm",
|
||||
AddExtension = true,
|
||||
FileName = PipelineName,
|
||||
@@ -698,7 +698,7 @@ namespace XplorePlane.ViewModels
|
||||
{
|
||||
var dialog = new OpenFileDialog
|
||||
{
|
||||
Filter = "XP 模块流水线 (*.xpm)|*.xpm",
|
||||
Filter = "XP 模块 (*.xpm)|*.xpm",
|
||||
DefaultExt = ".xpm",
|
||||
InitialDirectory = GetPipelineDirectory()
|
||||
};
|
||||
|
||||
@@ -280,6 +280,7 @@
|
||||
FontFamily="{StaticResource UiFont}"
|
||||
FontSize="12"
|
||||
FontWeight="SemiBold"
|
||||
x:Name="ProgramRootNameText"
|
||||
Text="{Binding DisplayName}"
|
||||
TextTrimming="CharacterEllipsis" />
|
||||
</StackPanel>
|
||||
@@ -288,6 +289,7 @@
|
||||
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=TreeViewItem}}" Value="True">
|
||||
<Setter TargetName="ProgramRootCard" Property="Background" Value="#E7F1FB" />
|
||||
<Setter TargetName="ProgramRootCard" Property="BorderBrush" Value="#9FC6E8" />
|
||||
<Setter TargetName="ProgramRootNameText" Property="Foreground" Value="#111111" />
|
||||
</DataTrigger>
|
||||
</DataTemplate.Triggers>
|
||||
</HierarchicalDataTemplate>
|
||||
@@ -305,6 +307,10 @@
|
||||
BorderThickness="1"
|
||||
CornerRadius="4">
|
||||
<Grid x:Name="NodeRoot" MinHeight="23">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="15" />
|
||||
<ColumnDefinition Width="20" />
|
||||
@@ -312,7 +318,7 @@
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Grid Grid.Column="0">
|
||||
<Grid Grid.RowSpan="2" Grid.Column="0">
|
||||
<Border
|
||||
x:Name="ChildStem"
|
||||
Width="1"
|
||||
@@ -330,6 +336,7 @@
|
||||
</Grid>
|
||||
|
||||
<Border
|
||||
Grid.RowSpan="2"
|
||||
Grid.Column="1"
|
||||
Width="16"
|
||||
Height="16"
|
||||
@@ -346,6 +353,7 @@
|
||||
|
||||
<TextBlock
|
||||
x:Name="NodeNameText"
|
||||
Grid.Row="0"
|
||||
Grid.Column="2"
|
||||
Margin="3,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
@@ -357,6 +365,7 @@
|
||||
|
||||
<StackPanel
|
||||
x:Name="NodeActions"
|
||||
Grid.Row="0"
|
||||
Grid.Column="3"
|
||||
Margin="0,0,2,0"
|
||||
VerticalAlignment="Center"
|
||||
@@ -375,6 +384,31 @@
|
||||
FontSize="10"
|
||||
ToolTip="删除" />
|
||||
</StackPanel>
|
||||
<Grid
|
||||
x:Name="WaitDelayProgressHost"
|
||||
Grid.Row="1"
|
||||
Grid.Column="2"
|
||||
Grid.ColumnSpan="2"
|
||||
Margin="3,2,6,1"
|
||||
Visibility="Collapsed">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ProgressBar
|
||||
Height="6"
|
||||
Minimum="0"
|
||||
Maximum="100"
|
||||
Value="{Binding ExecutionProgressPercent}" />
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
Margin="6,-4,0,0"
|
||||
VerticalAlignment="Center"
|
||||
FontFamily="{StaticResource UiFont}"
|
||||
FontSize="10"
|
||||
Foreground="#444444"
|
||||
Text="{Binding ExecutionProgressText}" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Border>
|
||||
<DataTemplate.Triggers>
|
||||
@@ -387,22 +421,30 @@
|
||||
<Setter TargetName="NodeActions" Property="Visibility" Value="Visible" />
|
||||
<Setter TargetName="NodeCard" Property="Background" Value="#DCEEFF" />
|
||||
<Setter TargetName="NodeCard" Property="BorderBrush" Value="#71A9DB" />
|
||||
<Setter TargetName="NodeNameText" Property="Foreground" Value="#1F2D3D" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding ExecutionState}" Value="Running">
|
||||
<Setter TargetName="NodeCard" Property="Background" Value="#FF1E6FD9" />
|
||||
<Setter TargetName="NodeCard" Property="BorderBrush" Value="#FF1E6FD9" />
|
||||
<Setter TargetName="NodeNameText" Property="Foreground" Value="White" />
|
||||
<Setter TargetName="NodeCard" Property="Background" Value="#FFD54F" />
|
||||
<Setter TargetName="NodeCard" Property="BorderBrush" Value="#C89B00" />
|
||||
<Setter TargetName="NodeNameText" Property="Foreground" Value="#1F1F1F" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding ExecutionState}" Value="Succeeded">
|
||||
<Setter TargetName="NodeCard" Property="Background" Value="#FF2E7D32" />
|
||||
<Setter TargetName="NodeCard" Property="BorderBrush" Value="#FF2E7D32" />
|
||||
<Setter TargetName="NodeCard" Property="BorderBrush" Value="#FF1B5E20" />
|
||||
<Setter TargetName="NodeNameText" Property="Foreground" Value="White" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding ExecutionState}" Value="Failed">
|
||||
<Setter TargetName="NodeCard" Property="Background" Value="#FFC62828" />
|
||||
<Setter TargetName="NodeCard" Property="BorderBrush" Value="#FFC62828" />
|
||||
<Setter TargetName="NodeCard" Property="BorderBrush" Value="#FF8E0000" />
|
||||
<Setter TargetName="NodeNameText" Property="Foreground" Value="White" />
|
||||
</DataTrigger>
|
||||
<MultiDataTrigger>
|
||||
<MultiDataTrigger.Conditions>
|
||||
<Condition Binding="{Binding IsWaitDelay}" Value="True" />
|
||||
<Condition Binding="{Binding IsRunningNode}" Value="True" />
|
||||
</MultiDataTrigger.Conditions>
|
||||
<Setter TargetName="WaitDelayProgressHost" Property="Visibility" Value="Visible" />
|
||||
</MultiDataTrigger>
|
||||
</DataTemplate.Triggers>
|
||||
</HierarchicalDataTemplate>
|
||||
</TreeView.Resources>
|
||||
@@ -569,6 +611,20 @@
|
||||
<StackPanel Margin="10,8,10,6">
|
||||
<TextBlock Style="{StaticResource LabelStyle}" Text="延时 (ms)" />
|
||||
<TextBox Style="{StaticResource EditorBox}" Text="{Binding SelectedNode.DelayMilliseconds, UpdateSourceTrigger=LostFocus}" />
|
||||
<ProgressBar
|
||||
Height="8"
|
||||
Margin="0,2,0,0"
|
||||
Minimum="0"
|
||||
Maximum="100"
|
||||
Value="{Binding SelectedNode.ExecutionProgressPercent}"
|
||||
Visibility="{Binding SelectedNode.IsDelayProgressVisible, Converter={StaticResource BoolToVisibilityConverter}}" />
|
||||
<TextBlock
|
||||
Margin="0,4,0,0"
|
||||
FontFamily="{StaticResource UiFont}"
|
||||
FontSize="10"
|
||||
Foreground="#666666"
|
||||
Text="{Binding SelectedNode.ExecutionProgressText}"
|
||||
Visibility="{Binding SelectedNode.IsDelayProgressVisible, Converter={StaticResource BoolToVisibilityConverter}}" />
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
</StackPanel>
|
||||
|
||||
@@ -19,14 +19,6 @@ namespace XplorePlane.Views.Cnc
|
||||
/// </summary>
|
||||
public partial class CncPageView : UserControl
|
||||
{
|
||||
private static readonly Brush SelectedNodeBackground = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#E7F0F7"));
|
||||
private static readonly Brush SelectedNodeBorder = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#9CB9D1"));
|
||||
private static readonly Brush HoverNodeBackground = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#F6FAFC"));
|
||||
private static readonly Brush HoverNodeBorder = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#D7E4EE"));
|
||||
private static readonly Brush SelectedNodeForeground = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#1F4E79"));
|
||||
private static readonly Brush DefaultNodeForeground = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#202020"));
|
||||
private static readonly Brush TransparentBrush = Brushes.Transparent;
|
||||
|
||||
private CncInspectionModulePipelineViewModel _inspectionModulePipelineViewModel;
|
||||
private readonly Dictionary<TextBox, Label> _textDisplayLabels = new();
|
||||
private readonly Dictionary<CheckBox, Label> _checkDisplayLabels = new();
|
||||
@@ -186,24 +178,9 @@ namespace XplorePlane.Views.Cnc
|
||||
continue;
|
||||
}
|
||||
|
||||
if (item.IsSelected)
|
||||
{
|
||||
card.Background = SelectedNodeBackground;
|
||||
card.BorderBrush = SelectedNodeBorder;
|
||||
ApplyNodeTextForeground(card, SelectedNodeForeground);
|
||||
}
|
||||
else if (card.IsMouseOver)
|
||||
{
|
||||
card.Background = HoverNodeBackground;
|
||||
card.BorderBrush = HoverNodeBorder;
|
||||
ApplyNodeTextForeground(card, DefaultNodeForeground);
|
||||
}
|
||||
else
|
||||
{
|
||||
card.Background = TransparentBrush;
|
||||
card.BorderBrush = TransparentBrush;
|
||||
ApplyNodeTextForeground(card, DefaultNodeForeground);
|
||||
}
|
||||
card.ClearValue(Border.BackgroundProperty);
|
||||
card.ClearValue(Border.BorderBrushProperty);
|
||||
ClearNodeTextForeground(card);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,14 +295,11 @@ namespace XplorePlane.Views.Cnc
|
||||
panel.Children.Insert(index + 1, companionControl);
|
||||
}
|
||||
|
||||
private static void ApplyNodeTextForeground(Border card, Brush foreground)
|
||||
private static void ClearNodeTextForeground(Border card)
|
||||
{
|
||||
foreach (var textBlock in FindVisualDescendants<TextBlock>(card))
|
||||
{
|
||||
if (textBlock.Visibility == Visibility.Visible)
|
||||
{
|
||||
textBlock.Foreground = foreground;
|
||||
}
|
||||
textBlock.ClearValue(TextBlock.ForegroundProperty);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -80,38 +80,25 @@
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
Command="{Binding NewPipelineCommand}"
|
||||
Content="新建"
|
||||
Content="新建配方"
|
||||
Style="{StaticResource ToolbarBtn}"
|
||||
ToolTip="新建流水线" />
|
||||
ToolTip="新建配方" />
|
||||
<Button
|
||||
Command="{Binding SavePipelineCommand}"
|
||||
Content="保存"
|
||||
Content="保存配方"
|
||||
Style="{StaticResource ToolbarBtn}"
|
||||
ToolTip="保存当前流水线" />
|
||||
ToolTip="保存当前配方" />
|
||||
<Button
|
||||
Width="64"
|
||||
Command="{Binding SaveAsPipelineCommand}"
|
||||
Content="另存为"
|
||||
Style="{StaticResource ToolbarBtn}"
|
||||
ToolTip="另存当前流水线" />
|
||||
ToolTip="另存当前配方" />
|
||||
<Button
|
||||
Command="{Binding LoadPipelineCommand}"
|
||||
Content="加载"
|
||||
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="清除截止位置并执行全部节点" />
|
||||
ToolTip="加载配方" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock
|
||||
|
||||
Reference in New Issue
Block a user