将流程图作为3级节点在左侧显示 ;优化布局宽度显示 ; 右侧详情面板的显示级别1级或2级
This commit is contained in:
@@ -15,12 +15,12 @@ namespace XP.Hardware.Detector.Config
|
||||
/// <summary>
|
||||
/// 合成帧宽度(像素)| Synthetic frame width (pixels)
|
||||
/// </summary>
|
||||
public int Width { get; set; } = 256;
|
||||
public int Width { get; set; } = 2800;
|
||||
|
||||
/// <summary>
|
||||
/// 合成帧高度(像素)| Synthetic frame height (pixels)
|
||||
/// </summary>
|
||||
public int Height { get; set; } = 256;
|
||||
public int Height { get; set; } = 2800;
|
||||
|
||||
/// <summary>
|
||||
/// 模拟帧率(帧/秒)| Simulated frame rate (fps)
|
||||
|
||||
@@ -32,6 +32,7 @@ namespace XplorePlane.ViewModels.Cnc
|
||||
private readonly ICncExecutionService _cncExecutionService;
|
||||
private readonly IXpDataPathService _dataPathService;
|
||||
private readonly IPipelinePersistenceService _pipelinePersistenceService;
|
||||
private readonly IImageProcessingService _imageProcessingService;
|
||||
|
||||
private CncProgram _currentProgram;
|
||||
private ObservableCollection<CncNodeViewModel> _nodes;
|
||||
@@ -57,7 +58,8 @@ namespace XplorePlane.ViewModels.Cnc
|
||||
ILoggerService logger,
|
||||
ICncExecutionService cncExecutionService,
|
||||
IXpDataPathService dataPathService,
|
||||
IPipelinePersistenceService pipelinePersistenceService)
|
||||
IPipelinePersistenceService pipelinePersistenceService,
|
||||
IImageProcessingService imageProcessingService = null)
|
||||
{
|
||||
_cncProgramService = cncProgramService ?? throw new ArgumentNullException(nameof(cncProgramService));
|
||||
ArgumentNullException.ThrowIfNull(appStateService);
|
||||
@@ -66,6 +68,7 @@ namespace XplorePlane.ViewModels.Cnc
|
||||
_cncExecutionService = cncExecutionService ?? throw new ArgumentNullException(nameof(cncExecutionService));
|
||||
_dataPathService = dataPathService ?? throw new ArgumentNullException(nameof(dataPathService));
|
||||
_pipelinePersistenceService = pipelinePersistenceService ?? throw new ArgumentNullException(nameof(pipelinePersistenceService));
|
||||
_imageProcessingService = imageProcessingService; // optional — used for pipeline step display names
|
||||
|
||||
_nodes = new ObservableCollection<CncNodeViewModel>();
|
||||
_treeNodes = new ObservableCollection<CncNodeViewModel>();
|
||||
@@ -661,6 +664,12 @@ namespace XplorePlane.ViewModels.Cnc
|
||||
IsExpanded = expansionState.TryGetValue(node.Id, out var isExpanded) ? isExpanded : true
|
||||
};
|
||||
|
||||
// 为检测模块节点填充流水线步骤(三级树节点)
|
||||
if (node is InspectionModuleNode imNode)
|
||||
{
|
||||
vm.SyncPipelineSteps(imNode.Pipeline, _imageProcessingService);
|
||||
}
|
||||
|
||||
flatNodes.Add(vm);
|
||||
|
||||
if (vm.IsSavePosition)
|
||||
|
||||
@@ -3,6 +3,7 @@ using Prism.Commands;
|
||||
using Prism.Mvvm;
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media.Imaging;
|
||||
using XplorePlane.Models;
|
||||
@@ -30,10 +31,18 @@ namespace XplorePlane.ViewModels.Cnc
|
||||
_modelChangedCallback = modelChangedCallback ?? throw new ArgumentNullException(nameof(modelChangedCallback));
|
||||
_icon = GetIconForNodeType(model.NodeType);
|
||||
Children = new ObservableCollection<CncNodeViewModel>();
|
||||
PipelineSteps = new ObservableCollection<CncPipelineStepViewModel>();
|
||||
}
|
||||
|
||||
public ObservableCollection<CncNodeViewModel> Children { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 检测模块的流水线步骤列表(三级节点)。
|
||||
/// 仅 IsInspectionModule == true 时有内容。
|
||||
/// Pipeline steps for InspectionModule nodes (3rd-level tree nodes).
|
||||
/// </summary>
|
||||
public ObservableCollection<CncPipelineStepViewModel> PipelineSteps { get; }
|
||||
|
||||
public CncNode Model => _model;
|
||||
|
||||
public Guid Id => _model.Id;
|
||||
@@ -415,6 +424,7 @@ namespace XplorePlane.ViewModels.Cnc
|
||||
if (_model is InspectionModuleNode im)
|
||||
{
|
||||
UpdateModel(im with { Pipeline = value ?? new PipelineModel() });
|
||||
SyncPipelineSteps(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -684,6 +694,7 @@ namespace XplorePlane.ViewModels.Cnc
|
||||
RaisePropertyChanged(nameof(ManualImagePath));
|
||||
RaisePropertyChanged(nameof(Pipeline));
|
||||
RaisePropertyChanged(nameof(PipelineName));
|
||||
RaisePropertyChanged(nameof(PipelineSteps));
|
||||
RaisePropertyChanged(nameof(MarkerType));
|
||||
RaisePropertyChanged(nameof(MarkerX));
|
||||
RaisePropertyChanged(nameof(MarkerY));
|
||||
@@ -699,6 +710,38 @@ namespace XplorePlane.ViewModels.Cnc
|
||||
RaisePropertyChanged(nameof(ExecutionProgressText));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 树形子节点集合:
|
||||
/// - 对于检测模块节点,返回 PipelineSteps(流水线步骤作为三级节点)
|
||||
/// - 对于其他节点,返回 Children(CNC 子节点)
|
||||
/// Tree children: PipelineSteps for InspectionModule nodes, Children otherwise.
|
||||
/// </summary>
|
||||
public System.Collections.IEnumerable TreeChildren =>
|
||||
IsInspectionModule ? (System.Collections.IEnumerable)PipelineSteps : Children;
|
||||
|
||||
/// <summary>
|
||||
/// 将 PipelineModel 的节点同步到 PipelineSteps 集合(三级树节点)。
|
||||
/// Syncs PipelineModel nodes into the PipelineSteps collection (3rd-level tree nodes).
|
||||
/// </summary>
|
||||
public void SyncPipelineSteps(PipelineModel pipeline, Services.IImageProcessingService imageProcessingService = null)
|
||||
{
|
||||
PipelineSteps.Clear();
|
||||
if (pipeline?.Nodes == null)
|
||||
return;
|
||||
|
||||
foreach (var node in pipeline.Nodes.OrderBy(n => n.Order))
|
||||
{
|
||||
// 优先使用服务获取中文显示名,回退到 OperatorKey
|
||||
var displayName = imageProcessingService?.GetProcessorDisplayName(node.OperatorKey)
|
||||
?? node.OperatorKey;
|
||||
var icon = Services.ProcessorUiMetadata.GetOperatorIcon(node.OperatorKey);
|
||||
PipelineSteps.Add(new CncPipelineStepViewModel(
|
||||
displayName: displayName,
|
||||
isEnabled: node.IsEnabled,
|
||||
iconPath: icon));
|
||||
}
|
||||
}
|
||||
|
||||
private enum MotionAxis
|
||||
{
|
||||
StageX,
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
using Prism.Mvvm;
|
||||
|
||||
namespace XplorePlane.ViewModels.Cnc
|
||||
{
|
||||
/// <summary>
|
||||
/// 检测模块流水线步骤的轻量 ViewModel,用于在 CNC 树形结构中作为三级节点显示。
|
||||
/// Lightweight ViewModel for a pipeline step inside an InspectionModule node,
|
||||
/// displayed as a 3rd-level node in the CNC tree.
|
||||
/// </summary>
|
||||
public class CncPipelineStepViewModel : BindableBase
|
||||
{
|
||||
private string _displayName;
|
||||
private bool _isEnabled;
|
||||
private string _iconPath;
|
||||
|
||||
public CncPipelineStepViewModel(string displayName, bool isEnabled, string iconPath = null)
|
||||
{
|
||||
_displayName = displayName;
|
||||
_isEnabled = isEnabled;
|
||||
_iconPath = iconPath ?? string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>算子显示名称(中文)| Operator display name</summary>
|
||||
public string DisplayName
|
||||
{
|
||||
get => _displayName;
|
||||
set => SetProperty(ref _displayName, value);
|
||||
}
|
||||
|
||||
/// <summary>是否启用 | Whether the step is enabled</summary>
|
||||
public bool IsEnabled
|
||||
{
|
||||
get => _isEnabled;
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _isEnabled, value))
|
||||
RaisePropertyChanged(nameof(StateText));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>图标路径 | Icon path</summary>
|
||||
public string IconPath
|
||||
{
|
||||
get => _iconPath;
|
||||
set => SetProperty(ref _iconPath, value);
|
||||
}
|
||||
|
||||
/// <summary>状态文字(已启用 / 已停用)| State text</summary>
|
||||
public string StateText => _isEnabled ? "已启用" : "已停用";
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,7 @@ namespace XplorePlane.ViewModels
|
||||
{
|
||||
public class MainViewModel : BindableBase
|
||||
{
|
||||
private const double CncEditorHostWidth = 452d;
|
||||
private const double CncEditorHostWidth = 560d;
|
||||
private readonly ILoggerService _logger;
|
||||
private readonly IContainerProvider _containerProvider;
|
||||
private readonly IEventAggregator _eventAggregator;
|
||||
|
||||
@@ -114,8 +114,8 @@
|
||||
</UserControl.Resources>
|
||||
|
||||
<Border
|
||||
Width="452"
|
||||
MinWidth="452"
|
||||
Width="560"
|
||||
MinWidth="560"
|
||||
HorizontalAlignment="Left"
|
||||
Background="{StaticResource PanelBg}"
|
||||
BorderBrush="{StaticResource PanelBorder}"
|
||||
@@ -123,7 +123,7 @@
|
||||
CornerRadius="4">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180" />
|
||||
<ColumnDefinition Width="260" />
|
||||
<ColumnDefinition Width="1" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
@@ -141,6 +141,16 @@
|
||||
BorderBrush="{StaticResource SeparatorBrush}"
|
||||
BorderThickness="0,0,0,1">
|
||||
<StackPanel>
|
||||
<!-- 文件名标签:显示当前打开的程序文件名 -->
|
||||
<TextBlock
|
||||
Margin="2,0,0,4"
|
||||
FontFamily="{StaticResource UiFont}"
|
||||
FontSize="12"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="#2B8A3E"
|
||||
Text="{Binding ProgramTreeRoots[0].DisplayName}"
|
||||
TextTrimming="CharacterEllipsis"
|
||||
ToolTip="{Binding ProgramTreeRoots[0].DisplayName}" />
|
||||
<WrapPanel/>
|
||||
<WrapPanel Margin="0,4,0,0" Visibility="Collapsed">
|
||||
<Button
|
||||
@@ -251,53 +261,19 @@
|
||||
Padding="3,5"
|
||||
Background="Transparent"
|
||||
BorderThickness="0"
|
||||
ItemsSource="{Binding ProgramTreeRoots}"
|
||||
ItemsSource="{Binding ProgramTreeRoots[0].Children}"
|
||||
PreviewKeyDown="CncTreeView_PreviewKeyDown"
|
||||
SelectedItemChanged="CncTreeView_SelectedItemChanged">
|
||||
<TreeView.Resources>
|
||||
<HierarchicalDataTemplate
|
||||
DataType="{x:Type vm:CncProgramTreeRootViewModel}"
|
||||
ItemContainerStyle="{StaticResource TreeItemStyle}"
|
||||
ItemsSource="{Binding Children}">
|
||||
<Border
|
||||
x:Name="ProgramRootCard"
|
||||
Margin="0,1,0,3"
|
||||
Padding="0,2"
|
||||
Background="Transparent"
|
||||
BorderBrush="Transparent"
|
||||
BorderThickness="1"
|
||||
CornerRadius="4">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Margin="1,0,4,0"
|
||||
VerticalAlignment="Center"
|
||||
FontFamily="{StaticResource UiFont}"
|
||||
FontSize="12"
|
||||
Foreground="#2B8A3E"
|
||||
Text="◆" />
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
FontFamily="{StaticResource UiFont}"
|
||||
FontSize="12"
|
||||
FontWeight="SemiBold"
|
||||
x:Name="ProgramRootNameText"
|
||||
Text="{Binding DisplayName}"
|
||||
TextTrimming="CharacterEllipsis" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<DataTemplate.Triggers>
|
||||
<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>
|
||||
|
||||
<HierarchicalDataTemplate
|
||||
DataType="{x:Type vm:CncNodeViewModel}"
|
||||
ItemContainerStyle="{StaticResource TreeItemStyle}"
|
||||
ItemsSource="{Binding Children}">
|
||||
ItemsSource="{Binding TreeChildren}">
|
||||
<HierarchicalDataTemplate.ItemContainerStyle>
|
||||
<!-- 三级节点(流水线步骤)的 TreeViewItem:取消额外缩进 -->
|
||||
<Style BasedOn="{StaticResource TreeItemStyle}" TargetType="TreeViewItem">
|
||||
<Setter Property="Margin" Value="-16,0,0,0" />
|
||||
</Style>
|
||||
</HierarchicalDataTemplate.ItemContainerStyle>
|
||||
<Border
|
||||
x:Name="NodeCard"
|
||||
Margin="0,1,0,1"
|
||||
@@ -447,6 +423,83 @@
|
||||
</MultiDataTrigger>
|
||||
</DataTemplate.Triggers>
|
||||
</HierarchicalDataTemplate>
|
||||
|
||||
<!-- 三级节点:检测模块的流水线步骤 -->
|
||||
<DataTemplate DataType="{x:Type vm:CncPipelineStepViewModel}">
|
||||
<Border
|
||||
x:Name="StepCard"
|
||||
Margin="0,1,0,1"
|
||||
Padding="2,2,4,2"
|
||||
Background="Transparent"
|
||||
BorderBrush="Transparent"
|
||||
BorderThickness="1"
|
||||
CornerRadius="3">
|
||||
<Grid MinHeight="20">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="18" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- 图标 -->
|
||||
<Border
|
||||
Grid.Column="0"
|
||||
Width="14"
|
||||
Height="14"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Background="Transparent"
|
||||
CornerRadius="3">
|
||||
<Image
|
||||
Width="12"
|
||||
Height="12"
|
||||
Source="{Binding IconPath}"
|
||||
Stretch="Uniform" />
|
||||
</Border>
|
||||
|
||||
<!-- 名称 -->
|
||||
<TextBlock
|
||||
x:Name="StepNameText"
|
||||
Grid.Column="1"
|
||||
Margin="3,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
FontFamily="{StaticResource UiFont}"
|
||||
FontSize="10.5"
|
||||
Text="{Binding DisplayName}"
|
||||
TextTrimming="CharacterEllipsis" />
|
||||
|
||||
<!-- 启用状态标签 -->
|
||||
<Border
|
||||
x:Name="StepStateBadge"
|
||||
Grid.Column="2"
|
||||
Margin="4,0,0,0"
|
||||
Padding="4,1"
|
||||
VerticalAlignment="Center"
|
||||
Background="#E8F5E9"
|
||||
BorderBrush="#A5D6A7"
|
||||
BorderThickness="1"
|
||||
CornerRadius="3">
|
||||
<TextBlock
|
||||
x:Name="StepStateText"
|
||||
FontFamily="{StaticResource UiFont}"
|
||||
FontSize="9.5"
|
||||
Foreground="#2E7D32"
|
||||
Text="{Binding StateText}" />
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
<DataTemplate.Triggers>
|
||||
<!-- 已停用:灰色文字 + 橙色徽章 -->
|
||||
<DataTrigger Binding="{Binding IsEnabled}" Value="False">
|
||||
<Setter TargetName="StepNameText" Property="Foreground" Value="#999999" />
|
||||
<Setter TargetName="StepNameText" Property="TextDecorations" Value="Strikethrough" />
|
||||
<Setter TargetName="StepStateBadge" Property="Background" Value="#FFF3E0" />
|
||||
<Setter TargetName="StepStateBadge" Property="BorderBrush" Value="#FFCC80" />
|
||||
<Setter TargetName="StepStateText" Property="Foreground" Value="#E65100" />
|
||||
</DataTrigger>
|
||||
</DataTemplate.Triggers>
|
||||
</DataTemplate>
|
||||
|
||||
</TreeView.Resources>
|
||||
<TreeView.ItemContainerStyle>
|
||||
<Style BasedOn="{StaticResource TreeItemStyle}" TargetType="TreeViewItem">
|
||||
|
||||
@@ -85,7 +85,13 @@ namespace XplorePlane.Views.Cnc
|
||||
{
|
||||
if (DataContext is CncEditorViewModel viewModel)
|
||||
{
|
||||
viewModel.SelectedNode = e.NewValue as CncNodeViewModel;
|
||||
// 三级节点(CncPipelineStepViewModel)点击时,保持当前 2 级节点选中不变
|
||||
// Only update SelectedNode when a CncNodeViewModel is selected (1st or 2nd level)
|
||||
if (e.NewValue is CncNodeViewModel nodeVm)
|
||||
{
|
||||
viewModel.SelectedNode = nodeVm;
|
||||
}
|
||||
// else: pipeline step clicked — keep existing SelectedNode unchanged
|
||||
}
|
||||
|
||||
UpdateNodeVisualState();
|
||||
|
||||
Reference in New Issue
Block a user