Compare commits
2 Commits
8beed66ef0
...
6a96befac4
| Author | SHA1 | Date | |
|---|---|---|---|
| 6a96befac4 | |||
| 3211dbc473 |
@@ -33,6 +33,7 @@ namespace XplorePlane.ViewModels.Cnc
|
|||||||
private CncNodeViewModel _selectedNode;
|
private CncNodeViewModel _selectedNode;
|
||||||
private bool _isModified;
|
private bool _isModified;
|
||||||
private string _programName;
|
private string _programName;
|
||||||
|
private Guid? _preferredSelectedNodeId;
|
||||||
|
|
||||||
public CncEditorViewModel(
|
public CncEditorViewModel(
|
||||||
ICncProgramService cncProgramService,
|
ICncProgramService cncProgramService,
|
||||||
@@ -136,8 +137,9 @@ namespace XplorePlane.ViewModels.Cnc
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var node = _cncProgramService.CreateNode(nodeType);
|
var node = _cncProgramService.CreateNode(nodeType);
|
||||||
int afterIndex = SelectedNode?.Index ?? _currentProgram.Nodes.Count - 1;
|
int afterIndex = ResolveInsertAfterIndex(nodeType);
|
||||||
_currentProgram = _cncProgramService.InsertNode(_currentProgram, afterIndex, node);
|
_currentProgram = _cncProgramService.InsertNode(_currentProgram, afterIndex, node);
|
||||||
|
_preferredSelectedNodeId = node.Id;
|
||||||
|
|
||||||
OnProgramEdited();
|
OnProgramEdited();
|
||||||
_logger.Info("Inserted node: Type={NodeType}", nodeType);
|
_logger.Info("Inserted node: Type={NodeType}", nodeType);
|
||||||
@@ -155,7 +157,19 @@ namespace XplorePlane.ViewModels.Cnc
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_currentProgram = _cncProgramService.RemoveNode(_currentProgram, SelectedNode.Index);
|
if (SelectedNode.IsSavePosition)
|
||||||
|
{
|
||||||
|
var nodes = _currentProgram.Nodes.ToList();
|
||||||
|
int startIndex = SelectedNode.Index;
|
||||||
|
int endIndex = GetSavePositionBlockEndIndex(startIndex);
|
||||||
|
nodes.RemoveRange(startIndex, endIndex - startIndex + 1);
|
||||||
|
_currentProgram = ReplaceProgramNodes(nodes);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_currentProgram = _cncProgramService.RemoveNode(_currentProgram, SelectedNode.Index);
|
||||||
|
}
|
||||||
|
|
||||||
OnProgramEdited();
|
OnProgramEdited();
|
||||||
_logger.Info("Deleted node at index: {Index}", SelectedNode.Index);
|
_logger.Info("Deleted node at index: {Index}", SelectedNode.Index);
|
||||||
}
|
}
|
||||||
@@ -179,10 +193,18 @@ namespace XplorePlane.ViewModels.Cnc
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_currentProgram = _cncProgramService.MoveNode(_currentProgram, nodeVm.Index, nodeVm.Index - 1);
|
if (IsSavePositionChild(nodeVm.NodeType))
|
||||||
|
{
|
||||||
|
MoveSavePositionChild(nodeVm, moveDown: false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MoveRootBlock(nodeVm, moveDown: false);
|
||||||
|
}
|
||||||
|
|
||||||
OnProgramEdited();
|
OnProgramEdited();
|
||||||
}
|
}
|
||||||
catch (ArgumentOutOfRangeException ex)
|
catch (Exception ex) when (ex is ArgumentOutOfRangeException or InvalidOperationException)
|
||||||
{
|
{
|
||||||
_logger.Warn("Move node up failed: {Message}", ex.Message);
|
_logger.Warn("Move node up failed: {Message}", ex.Message);
|
||||||
}
|
}
|
||||||
@@ -195,10 +217,18 @@ namespace XplorePlane.ViewModels.Cnc
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_currentProgram = _cncProgramService.MoveNode(_currentProgram, nodeVm.Index, nodeVm.Index + 1);
|
if (IsSavePositionChild(nodeVm.NodeType))
|
||||||
|
{
|
||||||
|
MoveSavePositionChild(nodeVm, moveDown: true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MoveRootBlock(nodeVm, moveDown: true);
|
||||||
|
}
|
||||||
|
|
||||||
OnProgramEdited();
|
OnProgramEdited();
|
||||||
}
|
}
|
||||||
catch (ArgumentOutOfRangeException ex)
|
catch (Exception ex) when (ex is ArgumentOutOfRangeException or InvalidOperationException)
|
||||||
{
|
{
|
||||||
_logger.Warn("Move node down failed: {Message}", ex.Message);
|
_logger.Warn("Move node down failed: {Message}", ex.Message);
|
||||||
}
|
}
|
||||||
@@ -349,12 +379,12 @@ namespace XplorePlane.ViewModels.Cnc
|
|||||||
|
|
||||||
private void RefreshNodes()
|
private void RefreshNodes()
|
||||||
{
|
{
|
||||||
var selectedId = SelectedNode?.Id;
|
var selectedId = _preferredSelectedNodeId ?? SelectedNode?.Id;
|
||||||
var expansionState = Nodes.ToDictionary(node => node.Id, node => node.IsExpanded);
|
var expansionState = Nodes.ToDictionary(node => node.Id, node => node.IsExpanded);
|
||||||
|
|
||||||
var flatNodes = new List<CncNodeViewModel>();
|
var flatNodes = new List<CncNodeViewModel>();
|
||||||
var rootNodes = new List<CncNodeViewModel>();
|
var rootNodes = new List<CncNodeViewModel>();
|
||||||
CncNodeViewModel currentModule = null;
|
CncNodeViewModel currentSavePosition = null;
|
||||||
|
|
||||||
if (_currentProgram?.Nodes != null)
|
if (_currentProgram?.Nodes != null)
|
||||||
{
|
{
|
||||||
@@ -367,21 +397,21 @@ namespace XplorePlane.ViewModels.Cnc
|
|||||||
|
|
||||||
flatNodes.Add(vm);
|
flatNodes.Add(vm);
|
||||||
|
|
||||||
if (vm.IsInspectionModule)
|
if (vm.IsSavePosition)
|
||||||
{
|
{
|
||||||
rootNodes.Add(vm);
|
rootNodes.Add(vm);
|
||||||
currentModule = vm;
|
currentSavePosition = vm;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentModule != null && IsModuleChild(vm.NodeType))
|
if (currentSavePosition != null && IsSavePositionChild(vm.NodeType))
|
||||||
{
|
{
|
||||||
currentModule.Children.Add(vm);
|
currentSavePosition.Children.Add(vm);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
rootNodes.Add(vm);
|
rootNodes.Add(vm);
|
||||||
currentModule = null;
|
currentSavePosition = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -391,13 +421,199 @@ namespace XplorePlane.ViewModels.Cnc
|
|||||||
SelectedNode = selectedId.HasValue
|
SelectedNode = selectedId.HasValue
|
||||||
? Nodes.FirstOrDefault(node => node.Id == selectedId.Value) ?? Nodes.LastOrDefault()
|
? Nodes.FirstOrDefault(node => node.Id == selectedId.Value) ?? Nodes.LastOrDefault()
|
||||||
: Nodes.LastOrDefault();
|
: Nodes.LastOrDefault();
|
||||||
|
|
||||||
|
_preferredSelectedNodeId = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsModuleChild(CncNodeType type)
|
private int ResolveInsertAfterIndex(CncNodeType nodeType)
|
||||||
|
{
|
||||||
|
if (_currentProgram == null || _currentProgram.Nodes.Count == 0)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsSavePositionChild(nodeType))
|
||||||
|
{
|
||||||
|
return SelectedNode?.Index ?? _currentProgram.Nodes.Count - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int? savePositionIndex = FindOwningSavePositionIndex(SelectedNode?.Index);
|
||||||
|
if (!savePositionIndex.HasValue)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("请先选择一个“保存位置”节点,再插入标记点或检测模块。");
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetSavePositionBlockEndIndex(savePositionIndex.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MoveSavePositionChild(CncNodeViewModel nodeVm, bool moveDown)
|
||||||
|
{
|
||||||
|
int? parentIndex = FindOwningSavePositionIndex(nodeVm.Index);
|
||||||
|
if (!parentIndex.HasValue)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("当前子节点未归属于任何保存位置,无法移动。");
|
||||||
|
}
|
||||||
|
|
||||||
|
int childStartIndex = parentIndex.Value + 1;
|
||||||
|
int childEndIndex = GetSavePositionBlockEndIndex(parentIndex.Value);
|
||||||
|
int targetIndex = moveDown ? nodeVm.Index + 1 : nodeVm.Index - 1;
|
||||||
|
|
||||||
|
if (targetIndex < childStartIndex || targetIndex > childEndIndex)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_currentProgram = _cncProgramService.MoveNode(_currentProgram, nodeVm.Index, targetIndex);
|
||||||
|
_preferredSelectedNodeId = nodeVm.Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MoveRootBlock(CncNodeViewModel nodeVm, bool moveDown)
|
||||||
|
{
|
||||||
|
var blocks = BuildRootBlocks(_currentProgram.Nodes);
|
||||||
|
int blockIndex = blocks.FindIndex(block => block.Start == nodeVm.Index);
|
||||||
|
if (blockIndex < 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!moveDown && blockIndex == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (moveDown && blockIndex >= blocks.Count - 1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentBlock = blocks[blockIndex];
|
||||||
|
var targetBlock = blocks[moveDown ? blockIndex + 1 : blockIndex - 1];
|
||||||
|
var nodes = _currentProgram.Nodes.ToList();
|
||||||
|
var movingNodes = nodes.GetRange(currentBlock.Start, currentBlock.End - currentBlock.Start + 1);
|
||||||
|
|
||||||
|
nodes.RemoveRange(currentBlock.Start, movingNodes.Count);
|
||||||
|
|
||||||
|
int insertAt = moveDown
|
||||||
|
? targetBlock.End - movingNodes.Count + 1
|
||||||
|
: targetBlock.Start;
|
||||||
|
|
||||||
|
nodes.InsertRange(insertAt, movingNodes);
|
||||||
|
|
||||||
|
_currentProgram = ReplaceProgramNodes(nodes);
|
||||||
|
_preferredSelectedNodeId = nodeVm.Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int? FindOwningSavePositionIndex(int? startIndex)
|
||||||
|
{
|
||||||
|
if (!startIndex.HasValue || _currentProgram == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
int index = startIndex.Value;
|
||||||
|
if (index < 0 || index >= _currentProgram.Nodes.Count)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var selectedType = _currentProgram.Nodes[index].NodeType;
|
||||||
|
if (_currentProgram.Nodes[index].NodeType == CncNodeType.SavePosition)
|
||||||
|
{
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsSavePositionChild(selectedType))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = index - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
var type = _currentProgram.Nodes[i].NodeType;
|
||||||
|
if (type == CncNodeType.SavePosition)
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsSavePositionChild(type))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int GetSavePositionBlockEndIndex(int savePositionIndex)
|
||||||
|
{
|
||||||
|
if (_currentProgram == null)
|
||||||
|
{
|
||||||
|
return savePositionIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
int endIndex = savePositionIndex;
|
||||||
|
for (int i = savePositionIndex + 1; i < _currentProgram.Nodes.Count; i++)
|
||||||
|
{
|
||||||
|
if (!IsSavePositionChild(_currentProgram.Nodes[i].NodeType))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
endIndex = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return endIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<(int Start, int End)> BuildRootBlocks(IReadOnlyList<CncNode> nodes)
|
||||||
|
{
|
||||||
|
var blocks = new List<(int Start, int End)>();
|
||||||
|
|
||||||
|
for (int i = 0; i < nodes.Count; i++)
|
||||||
|
{
|
||||||
|
if (IsSavePositionChild(nodes[i].NodeType))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int end = i;
|
||||||
|
if (nodes[i].NodeType == CncNodeType.SavePosition)
|
||||||
|
{
|
||||||
|
for (int j = i + 1; j < nodes.Count; j++)
|
||||||
|
{
|
||||||
|
if (!IsSavePositionChild(nodes[j].NodeType))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
end = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
blocks.Add((i, end));
|
||||||
|
}
|
||||||
|
|
||||||
|
return blocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CncProgram ReplaceProgramNodes(List<CncNode> nodes)
|
||||||
|
{
|
||||||
|
var renumberedNodes = nodes
|
||||||
|
.Select((node, index) => node with { Index = index })
|
||||||
|
.ToList()
|
||||||
|
.AsReadOnly();
|
||||||
|
|
||||||
|
return _currentProgram with
|
||||||
|
{
|
||||||
|
Nodes = renumberedNodes,
|
||||||
|
UpdatedAt = DateTime.UtcNow
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsSavePositionChild(CncNodeType type)
|
||||||
{
|
{
|
||||||
return type is CncNodeType.InspectionMarker
|
return type is CncNodeType.InspectionMarker
|
||||||
or CncNodeType.PauseDialog
|
or CncNodeType.InspectionModule;
|
||||||
or CncNodeType.WaitDelay;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PublishProgramChanged()
|
private void PublishProgramChanged()
|
||||||
|
|||||||
@@ -64,7 +64,15 @@ namespace XplorePlane.ViewModels.Cnc
|
|||||||
public bool IsPauseDialog => _model is PauseDialogNode;
|
public bool IsPauseDialog => _model is PauseDialogNode;
|
||||||
public bool IsWaitDelay => _model is WaitDelayNode;
|
public bool IsWaitDelay => _model is WaitDelayNode;
|
||||||
public bool IsCompleteProgram => _model is CompleteProgramNode;
|
public bool IsCompleteProgram => _model is CompleteProgramNode;
|
||||||
|
public bool IsPositionChild => _model is InspectionModuleNode or InspectionMarkerNode;
|
||||||
public bool IsMotionSnapshotNode => _model is ReferencePointNode or SaveNodeNode or SaveNodeWithImageNode or SavePositionNode;
|
public bool IsMotionSnapshotNode => _model is ReferencePointNode or SaveNodeNode or SaveNodeWithImageNode or SavePositionNode;
|
||||||
|
public string RelationTag => _model switch
|
||||||
|
{
|
||||||
|
SavePositionNode => "位置",
|
||||||
|
InspectionModuleNode => "检测模块",
|
||||||
|
InspectionMarkerNode => "检测标记",
|
||||||
|
_ => string.Empty
|
||||||
|
};
|
||||||
|
|
||||||
public double XM
|
public double XM
|
||||||
{
|
{
|
||||||
@@ -504,7 +512,9 @@ namespace XplorePlane.ViewModels.Cnc
|
|||||||
RaisePropertyChanged(nameof(IsPauseDialog));
|
RaisePropertyChanged(nameof(IsPauseDialog));
|
||||||
RaisePropertyChanged(nameof(IsWaitDelay));
|
RaisePropertyChanged(nameof(IsWaitDelay));
|
||||||
RaisePropertyChanged(nameof(IsCompleteProgram));
|
RaisePropertyChanged(nameof(IsCompleteProgram));
|
||||||
|
RaisePropertyChanged(nameof(IsPositionChild));
|
||||||
RaisePropertyChanged(nameof(IsMotionSnapshotNode));
|
RaisePropertyChanged(nameof(IsMotionSnapshotNode));
|
||||||
|
RaisePropertyChanged(nameof(RelationTag));
|
||||||
RaisePropertyChanged(nameof(XM));
|
RaisePropertyChanged(nameof(XM));
|
||||||
RaisePropertyChanged(nameof(YM));
|
RaisePropertyChanged(nameof(YM));
|
||||||
RaisePropertyChanged(nameof(ZT));
|
RaisePropertyChanged(nameof(ZT));
|
||||||
|
|||||||
@@ -21,6 +21,10 @@
|
|||||||
<SolidColorBrush x:Key="PanelBorder" Color="#CDCBCB" />
|
<SolidColorBrush x:Key="PanelBorder" Color="#CDCBCB" />
|
||||||
<SolidColorBrush x:Key="SeparatorBrush" Color="#E5E5E5" />
|
<SolidColorBrush x:Key="SeparatorBrush" Color="#E5E5E5" />
|
||||||
<SolidColorBrush x:Key="HeaderBg" Color="#F7F7F7" />
|
<SolidColorBrush x:Key="HeaderBg" Color="#F7F7F7" />
|
||||||
|
<SolidColorBrush x:Key="TreeParentBg" Color="#F6F8FB" />
|
||||||
|
<SolidColorBrush x:Key="TreeChildBg" Color="#FBFCFE" />
|
||||||
|
<SolidColorBrush x:Key="TreeAccentBrush" Color="#2E6FA3" />
|
||||||
|
<SolidColorBrush x:Key="TreeChildLineBrush" Color="#B9CDE0" />
|
||||||
<FontFamily x:Key="UiFont">Microsoft YaHei UI</FontFamily>
|
<FontFamily x:Key="UiFont">Microsoft YaHei UI</FontFamily>
|
||||||
|
|
||||||
<Style x:Key="TreeItemStyle" TargetType="TreeViewItem">
|
<Style x:Key="TreeItemStyle" TargetType="TreeViewItem">
|
||||||
@@ -109,7 +113,7 @@
|
|||||||
FontFamily="{StaticResource UiFont}"
|
FontFamily="{StaticResource UiFont}"
|
||||||
FontSize="10"
|
FontSize="10"
|
||||||
Foreground="#666666"
|
Foreground="#666666"
|
||||||
Text="模块节点下会自动显示标记、等待、消息等子节点。"
|
Text="保存位置节点下会自动显示检测标记和检测模块,清晰表达当前检测位置与检测内容的父子关系。"
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
@@ -124,97 +128,133 @@
|
|||||||
SelectedItemChanged="CncTreeView_SelectedItemChanged">
|
SelectedItemChanged="CncTreeView_SelectedItemChanged">
|
||||||
<TreeView.Resources>
|
<TreeView.Resources>
|
||||||
<HierarchicalDataTemplate DataType="{x:Type vm:CncNodeViewModel}" ItemsSource="{Binding Children}">
|
<HierarchicalDataTemplate DataType="{x:Type vm:CncNodeViewModel}" ItemsSource="{Binding Children}">
|
||||||
<Grid x:Name="NodeRoot" MinHeight="34">
|
<Border
|
||||||
<Grid.ColumnDefinitions>
|
x:Name="NodeCard"
|
||||||
<ColumnDefinition Width="30" />
|
Margin="0,1,0,1"
|
||||||
<ColumnDefinition Width="*" />
|
Padding="0"
|
||||||
<ColumnDefinition Width="Auto" />
|
Background="Transparent"
|
||||||
</Grid.ColumnDefinitions>
|
BorderBrush="Transparent"
|
||||||
|
BorderThickness="1"
|
||||||
|
CornerRadius="4">
|
||||||
|
<Grid x:Name="NodeRoot" MinHeight="28">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="18" />
|
||||||
|
<ColumnDefinition Width="24" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
<Border
|
<Grid Grid.Column="0">
|
||||||
Grid.Column="0"
|
<Border
|
||||||
Width="22"
|
x:Name="ChildStem"
|
||||||
Height="22"
|
Width="2"
|
||||||
HorizontalAlignment="Center"
|
Margin="8,0,0,0"
|
||||||
VerticalAlignment="Center"
|
HorizontalAlignment="Left"
|
||||||
Background="Transparent"
|
Background="{StaticResource TreeChildLineBrush}"
|
||||||
CornerRadius="4">
|
Visibility="Collapsed" />
|
||||||
<Image
|
<Border
|
||||||
Width="15"
|
x:Name="ChildBranch"
|
||||||
Height="15"
|
Width="10"
|
||||||
Source="{Binding Icon}"
|
Height="2"
|
||||||
Stretch="Uniform" />
|
Margin="8,0,0,0"
|
||||||
</Border>
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Background="{StaticResource TreeChildLineBrush}"
|
||||||
|
Visibility="Collapsed" />
|
||||||
|
</Grid>
|
||||||
|
|
||||||
<StackPanel
|
<Border
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Margin="4,0,0,0"
|
Width="18"
|
||||||
VerticalAlignment="Center"
|
Height="18"
|
||||||
Orientation="Horizontal">
|
HorizontalAlignment="Center"
|
||||||
<TextBlock
|
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
FontFamily="{StaticResource UiFont}"
|
Background="Transparent"
|
||||||
FontSize="10.5"
|
CornerRadius="4">
|
||||||
Foreground="#888888"
|
<Image
|
||||||
Text="{Binding Index, StringFormat='[{0}] '}" />
|
Width="14"
|
||||||
<TextBlock
|
Height="14"
|
||||||
VerticalAlignment="Center"
|
Source="{Binding Icon}"
|
||||||
FontFamily="{StaticResource UiFont}"
|
Stretch="Uniform" />
|
||||||
FontSize="11.5"
|
</Border>
|
||||||
Text="{Binding Name}" />
|
|
||||||
</StackPanel>
|
|
||||||
|
|
||||||
<StackPanel
|
<StackPanel
|
||||||
x:Name="NodeActions"
|
Grid.Column="2"
|
||||||
Grid.Column="2"
|
Margin="3,0,0,0"
|
||||||
Margin="0,0,2,0"
|
VerticalAlignment="Center"
|
||||||
VerticalAlignment="Center"
|
Orientation="Horizontal">
|
||||||
Orientation="Horizontal"
|
<TextBlock
|
||||||
Visibility="Collapsed">
|
VerticalAlignment="Center"
|
||||||
<Button
|
FontFamily="{StaticResource UiFont}"
|
||||||
Width="20"
|
FontSize="10.5"
|
||||||
Height="20"
|
Foreground="#888888"
|
||||||
Margin="1,0"
|
Text="{Binding Index, StringFormat='[{0}] '}" />
|
||||||
Background="White"
|
<TextBlock
|
||||||
BorderBrush="#CDCBCB"
|
VerticalAlignment="Center"
|
||||||
BorderThickness="1"
|
FontFamily="{StaticResource UiFont}"
|
||||||
Command="{Binding DataContext.MoveNodeUpCommand, RelativeSource={RelativeSource AncestorType=TreeView}}"
|
FontSize="11.5"
|
||||||
CommandParameter="{Binding}"
|
FontWeight="SemiBold"
|
||||||
Content="上"
|
Text="{Binding Name}" />
|
||||||
Cursor="Hand"
|
</StackPanel>
|
||||||
FontSize="10"
|
|
||||||
ToolTip="上移" />
|
<StackPanel
|
||||||
<Button
|
x:Name="NodeActions"
|
||||||
Width="20"
|
Grid.Column="3"
|
||||||
Height="20"
|
Margin="0,0,2,0"
|
||||||
Margin="1,0"
|
VerticalAlignment="Center"
|
||||||
Background="White"
|
Orientation="Horizontal"
|
||||||
BorderBrush="#CDCBCB"
|
Visibility="Collapsed">
|
||||||
BorderThickness="1"
|
<Button
|
||||||
Command="{Binding DataContext.MoveNodeDownCommand, RelativeSource={RelativeSource AncestorType=TreeView}}"
|
Width="20"
|
||||||
CommandParameter="{Binding}"
|
Height="20"
|
||||||
Content="下"
|
Margin="1,0"
|
||||||
Cursor="Hand"
|
Background="White"
|
||||||
FontSize="10"
|
BorderBrush="#CDCBCB"
|
||||||
ToolTip="下移" />
|
BorderThickness="1"
|
||||||
<Button
|
Command="{Binding DataContext.MoveNodeUpCommand, RelativeSource={RelativeSource AncestorType=TreeView}}"
|
||||||
Width="20"
|
CommandParameter="{Binding}"
|
||||||
Height="20"
|
Content="↑"
|
||||||
Margin="1,0"
|
Cursor="Hand"
|
||||||
Background="White"
|
FontSize="10"
|
||||||
BorderBrush="#E05050"
|
ToolTip="上移" />
|
||||||
BorderThickness="1"
|
<Button
|
||||||
Command="{Binding DataContext.DeleteNodeCommand, RelativeSource={RelativeSource AncestorType=TreeView}}"
|
Width="20"
|
||||||
Content="删"
|
Height="20"
|
||||||
Cursor="Hand"
|
Margin="1,0"
|
||||||
FontSize="10"
|
Background="White"
|
||||||
ToolTip="删除" />
|
BorderBrush="#CDCBCB"
|
||||||
</StackPanel>
|
BorderThickness="1"
|
||||||
</Grid>
|
Command="{Binding DataContext.MoveNodeDownCommand, RelativeSource={RelativeSource AncestorType=TreeView}}"
|
||||||
|
CommandParameter="{Binding}"
|
||||||
|
Content="↓"
|
||||||
|
Cursor="Hand"
|
||||||
|
FontSize="10"
|
||||||
|
ToolTip="下移" />
|
||||||
|
<Button
|
||||||
|
Width="20"
|
||||||
|
Height="20"
|
||||||
|
Margin="1,0"
|
||||||
|
Background="White"
|
||||||
|
BorderBrush="#E05050"
|
||||||
|
BorderThickness="1"
|
||||||
|
Command="{Binding DataContext.DeleteNodeCommand, RelativeSource={RelativeSource AncestorType=TreeView}}"
|
||||||
|
Content="×"
|
||||||
|
Cursor="Hand"
|
||||||
|
FontSize="10"
|
||||||
|
ToolTip="删除" />
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
<DataTemplate.Triggers>
|
<DataTemplate.Triggers>
|
||||||
<Trigger SourceName="NodeRoot" Property="IsMouseOver" Value="True">
|
<Trigger SourceName="NodeRoot" Property="IsMouseOver" Value="True">
|
||||||
<Setter TargetName="NodeActions" Property="Visibility" Value="Visible" />
|
<Setter TargetName="NodeActions" Property="Visibility" Value="Visible" />
|
||||||
|
<Setter TargetName="NodeCard" Property="Background" Value="#F3F7FB" />
|
||||||
|
<Setter TargetName="NodeCard" Property="BorderBrush" Value="#D7E4F1" />
|
||||||
</Trigger>
|
</Trigger>
|
||||||
|
<DataTrigger Binding="{Binding IsPositionChild}" Value="True">
|
||||||
|
<Setter TargetName="ChildStem" Property="Visibility" Value="Visible" />
|
||||||
|
<Setter TargetName="ChildBranch" Property="Visibility" Value="Visible" />
|
||||||
|
</DataTrigger>
|
||||||
</DataTemplate.Triggers>
|
</DataTemplate.Triggers>
|
||||||
</HierarchicalDataTemplate>
|
</HierarchicalDataTemplate>
|
||||||
</TreeView.Resources>
|
</TreeView.Resources>
|
||||||
@@ -237,7 +277,7 @@
|
|||||||
<TextBlock Style="{StaticResource LabelStyle}" Text="名称" />
|
<TextBlock Style="{StaticResource LabelStyle}" Text="名称" />
|
||||||
<TextBox Style="{StaticResource EditorBox}" Text="{Binding SelectedNode.Name, UpdateSourceTrigger=PropertyChanged}" />
|
<TextBox Style="{StaticResource EditorBox}" Text="{Binding SelectedNode.Name, UpdateSourceTrigger=PropertyChanged}" />
|
||||||
|
|
||||||
<UniformGrid Columns="2" Margin="0,0,0,8">
|
<UniformGrid Margin="0,0,0,8" Columns="2">
|
||||||
<StackPanel Margin="0,0,6,0">
|
<StackPanel Margin="0,0,6,0">
|
||||||
<TextBlock Style="{StaticResource LabelStyle}" Text="索引" />
|
<TextBlock Style="{StaticResource LabelStyle}" Text="索引" />
|
||||||
<TextBox Style="{StaticResource EditorBox}" IsReadOnly="True" Text="{Binding SelectedNode.Index, Mode=OneWay}" />
|
<TextBox Style="{StaticResource EditorBox}" IsReadOnly="True" Text="{Binding SelectedNode.Index, Mode=OneWay}" />
|
||||||
@@ -345,7 +385,7 @@
|
|||||||
|
|
||||||
<GroupBox
|
<GroupBox
|
||||||
Style="{StaticResource CompactGroupBox}"
|
Style="{StaticResource CompactGroupBox}"
|
||||||
Header="标记参数"
|
Header="检测标记"
|
||||||
Visibility="{Binding SelectedNode.IsInspectionMarker, Converter={StaticResource BoolToVisibilityConverter}}">
|
Visibility="{Binding SelectedNode.IsInspectionMarker, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||||
<StackPanel Margin="8,8,8,6">
|
<StackPanel Margin="8,8,8,6">
|
||||||
<TextBlock Style="{StaticResource LabelStyle}" Text="标记类型" />
|
<TextBlock Style="{StaticResource LabelStyle}" Text="标记类型" />
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Border Grid.Row="0" Background="#F0F0F0" BorderBrush="#DDDDDD" BorderThickness="0,0,0,1">
|
<Border Grid.Row="0" Background="#F0F0F0" BorderBrush="#DDDDDD" BorderThickness="0,0,0,1">
|
||||||
<TextBlock Margin="4,2" HorizontalAlignment="Left" VerticalAlignment="Center"
|
<TextBlock Margin="4,2" HorizontalAlignment="Left" VerticalAlignment="Center"
|
||||||
FontWeight="SemiBold" Foreground="#333333" Text="图像" />
|
FontWeight="SemiBold" Foreground="#333333" Text="图像处理" />
|
||||||
</Border>
|
</Border>
|
||||||
<ContentControl Grid.Row="1" Content="{Binding ImagePanelContent}" />
|
<ContentControl Grid.Row="1" Content="{Binding ImagePanelContent}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
@@ -312,11 +312,11 @@
|
|||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<telerik:RadRibbonButton
|
<telerik:RadRibbonButton
|
||||||
telerik:ScreenTip.Title="标记"
|
telerik:ScreenTip.Title="检测标记"
|
||||||
Size="Medium"
|
Size="Medium"
|
||||||
Command="{Binding InsertInspectionMarkerCommand}"
|
Command="{Binding InsertInspectionMarkerCommand}"
|
||||||
SmallImage="/Assets/Icons/mark.png"
|
SmallImage="/Assets/Icons/mark.png"
|
||||||
Text="标记" />
|
Text="检测标记" />
|
||||||
<telerik:RadRibbonButton
|
<telerik:RadRibbonButton
|
||||||
telerik:ScreenTip.Title="模块"
|
telerik:ScreenTip.Title="模块"
|
||||||
Size="Medium"
|
Size="Medium"
|
||||||
|
|||||||
Reference in New Issue
Block a user