在现有的 位置节点属性中新增一个 checkbox 按钮,来确认是否保存图片
This commit is contained in:
@@ -747,5 +747,54 @@ internal sealed class SynchronousProgress<T> : IProgress<T>
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task SavePosition_WithSaveImage_RefreshesInputImageForFollowingInspectionModule()
|
||||||
|
{
|
||||||
|
var (service, mockStore, _, mockMainViewport, _) = CreateService();
|
||||||
|
var initialImage = CreateBitmapSource(1, 1);
|
||||||
|
var refreshedImage = CreateBitmapSource(2, 3);
|
||||||
|
|
||||||
|
mockMainViewport.SetupGet(m => m.LatestManualImage).Returns((ImageSource)null);
|
||||||
|
mockMainViewport.SetupSequence(m => m.CurrentDisplayImage)
|
||||||
|
.Returns(initialImage)
|
||||||
|
.Returns(refreshedImage);
|
||||||
|
|
||||||
|
List<InspectionAssetWriteRequest> capturedAssets = null;
|
||||||
|
mockStore.Setup(s => s.AppendNodeResultAsync(
|
||||||
|
It.IsAny<InspectionNodeResult>(),
|
||||||
|
It.IsAny<IEnumerable<InspectionMetricResult>>(),
|
||||||
|
It.IsAny<PipelineExecutionSnapshot>(),
|
||||||
|
It.IsAny<IEnumerable<InspectionAssetWriteRequest>>()))
|
||||||
|
.Callback<InspectionNodeResult, IEnumerable<InspectionMetricResult>, PipelineExecutionSnapshot, IEnumerable<InspectionAssetWriteRequest>>(
|
||||||
|
(_, __, ___, assets) => capturedAssets = assets?.ToList())
|
||||||
|
.Returns(Task.CompletedTask);
|
||||||
|
|
||||||
|
var program = new CncProgram(
|
||||||
|
Guid.NewGuid(),
|
||||||
|
"Program",
|
||||||
|
DateTime.UtcNow,
|
||||||
|
DateTime.UtcNow,
|
||||||
|
new List<CncNode>
|
||||||
|
{
|
||||||
|
new SavePositionNode(Guid.NewGuid(), 0, "Pos_0", MotionState.Default, SaveImage: true),
|
||||||
|
new InspectionModuleNode(Guid.NewGuid(), 1, "Inspect_0", new PipelineModel { Name = "Pipeline" })
|
||||||
|
}.AsReadOnly());
|
||||||
|
|
||||||
|
await service.ExecuteAsync(program, null, CancellationToken.None);
|
||||||
|
|
||||||
|
var inputAsset = Assert.Single(capturedAssets.Where(a => a.AssetType == InspectionAssetType.NodeInputImage));
|
||||||
|
Assert.Equal(2, inputAsset.Width);
|
||||||
|
Assert.Equal(3, inputAsset.Height);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BitmapSource CreateBitmapSource(int width, int height)
|
||||||
|
{
|
||||||
|
var stride = width * 4;
|
||||||
|
var pixels = new byte[stride * height];
|
||||||
|
var bitmap = BitmapSource.Create(width, height, 96, 96, PixelFormats.Bgra32, null, pixels, stride);
|
||||||
|
bitmap.Freeze();
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,15 +7,25 @@ using FsCheck.Fluent;
|
|||||||
using FsCheck.Xunit;
|
using FsCheck.Xunit;
|
||||||
using XplorePlane.Models;
|
using XplorePlane.Models;
|
||||||
using XplorePlane.ViewModels.Cnc;
|
using XplorePlane.ViewModels.Cnc;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
namespace XplorePlane.Tests.ViewModels
|
namespace XplorePlane.Tests.ViewModels
|
||||||
{
|
{
|
||||||
public class CncNodeViewModelTests
|
public class CncNodeViewModelTests
|
||||||
{
|
{
|
||||||
// ── Property 11: 节点执行状态转换正确性 ──────────────────────────────
|
[Fact]
|
||||||
|
public void SavePosition_SaveImage_CanBeUpdated()
|
||||||
|
{
|
||||||
|
var node = new SavePositionNode(Guid.NewGuid(), 0, "Pos_0", MotionState.Default, SaveImage: false);
|
||||||
|
var vm = new CncNodeViewModel(node, (_, __) => { });
|
||||||
|
|
||||||
|
vm.SaveImage = true;
|
||||||
|
|
||||||
|
var updatedNode = Assert.IsType<SavePositionNode>(vm.Model);
|
||||||
|
Assert.True(vm.SaveImage);
|
||||||
|
Assert.True(updatedNode.SaveImage);
|
||||||
|
}
|
||||||
|
|
||||||
// Feature: cnc-run-execution, Property 11: 节点执行状态转换正确性
|
|
||||||
// Validates: Requirements 6.1, 6.2
|
|
||||||
[Property(MaxTest = 100)]
|
[Property(MaxTest = 100)]
|
||||||
public Property ExecutionState_TransitionsProduceCorrectBoolProperties()
|
public Property ExecutionState_TransitionsProduceCorrectBoolProperties()
|
||||||
{
|
{
|
||||||
@@ -30,31 +40,27 @@ namespace XplorePlane.Tests.ViewModels
|
|||||||
gen.ToArbitrary(),
|
gen.ToArbitrary(),
|
||||||
node =>
|
node =>
|
||||||
{
|
{
|
||||||
var vm = new CncNodeViewModel(node, (vm2, n) => { });
|
var vm = new CncNodeViewModel(node, (_, __) => { });
|
||||||
|
|
||||||
// Running
|
|
||||||
vm.ExecutionState = NodeExecutionState.Running;
|
vm.ExecutionState = NodeExecutionState.Running;
|
||||||
bool runningOk = vm.IsRunningNode == true
|
bool runningOk = vm.IsRunningNode
|
||||||
&& vm.IsSucceededNode == false
|
&& !vm.IsSucceededNode
|
||||||
&& vm.IsFailedNode == false;
|
&& !vm.IsFailedNode;
|
||||||
|
|
||||||
// Succeeded
|
|
||||||
vm.ExecutionState = NodeExecutionState.Succeeded;
|
vm.ExecutionState = NodeExecutionState.Succeeded;
|
||||||
bool succeededOk = vm.IsRunningNode == false
|
bool succeededOk = !vm.IsRunningNode
|
||||||
&& vm.IsSucceededNode == true
|
&& vm.IsSucceededNode
|
||||||
&& vm.IsFailedNode == false;
|
&& !vm.IsFailedNode;
|
||||||
|
|
||||||
// Failed
|
|
||||||
vm.ExecutionState = NodeExecutionState.Failed;
|
vm.ExecutionState = NodeExecutionState.Failed;
|
||||||
bool failedOk = vm.IsRunningNode == false
|
bool failedOk = !vm.IsRunningNode
|
||||||
&& vm.IsSucceededNode == false
|
&& !vm.IsSucceededNode
|
||||||
&& vm.IsFailedNode == true;
|
&& vm.IsFailedNode;
|
||||||
|
|
||||||
// Idle
|
|
||||||
vm.ExecutionState = NodeExecutionState.Idle;
|
vm.ExecutionState = NodeExecutionState.Idle;
|
||||||
bool idleOk = vm.IsRunningNode == false
|
bool idleOk = !vm.IsRunningNode
|
||||||
&& vm.IsSucceededNode == false
|
&& !vm.IsSucceededNode
|
||||||
&& vm.IsFailedNode == false;
|
&& !vm.IsFailedNode;
|
||||||
|
|
||||||
return runningOk && succeededOk && failedOk && idleOk;
|
return runningOk && succeededOk && failedOk && idleOk;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -85,7 +85,8 @@ namespace XplorePlane.Models
|
|||||||
Guid Id,
|
Guid Id,
|
||||||
int Index,
|
int Index,
|
||||||
string Name,
|
string Name,
|
||||||
MotionState MotionState) : CncNode(Id, Index, CncNodeType.SavePosition, Name);
|
MotionState MotionState,
|
||||||
|
bool SaveImage = false) : CncNode(Id, Index, CncNodeType.SavePosition, Name);
|
||||||
|
|
||||||
/// <summary>检测模块节点 | Inspection module node</summary>
|
/// <summary>检测模块节点 | Inspection module node</summary>
|
||||||
public record InspectionModuleNode(
|
public record InspectionModuleNode(
|
||||||
|
|||||||
@@ -82,7 +82,8 @@ namespace XplorePlane.Services.Cnc
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
int inspectionNodeCount = program.Nodes.OfType<InspectionModuleNode>().Count();
|
int inspectionNodeCount = program.Nodes.OfType<InspectionModuleNode>().Count();
|
||||||
var sourceImage = TryGetSourceImage();
|
var runSourceImage = TryGetSourceImage();
|
||||||
|
var currentSourceImage = runSourceImage;
|
||||||
|
|
||||||
Guid runId;
|
Guid runId;
|
||||||
try
|
try
|
||||||
@@ -95,15 +96,15 @@ namespace XplorePlane.Services.Cnc
|
|||||||
};
|
};
|
||||||
|
|
||||||
InspectionAssetWriteRequest sourceAsset = null;
|
InspectionAssetWriteRequest sourceAsset = null;
|
||||||
if (sourceImage != null)
|
if (runSourceImage != null)
|
||||||
{
|
{
|
||||||
sourceAsset = new InspectionAssetWriteRequest
|
sourceAsset = new InspectionAssetWriteRequest
|
||||||
{
|
{
|
||||||
AssetType = InspectionAssetType.RunSourceImage,
|
AssetType = InspectionAssetType.RunSourceImage,
|
||||||
Content = EncodeBitmapToBmp(sourceImage),
|
Content = EncodeBitmapToBmp(runSourceImage),
|
||||||
FileFormat = "bmp",
|
FileFormat = "bmp",
|
||||||
Width = sourceImage.PixelWidth,
|
Width = runSourceImage.PixelWidth,
|
||||||
Height = sourceImage.PixelHeight
|
Height = runSourceImage.PixelHeight
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,13 +156,29 @@ namespace XplorePlane.Services.Cnc
|
|||||||
"Executing save-position node [{Index}] {Name} | " +
|
"Executing save-position node [{Index}] {Name} | " +
|
||||||
"StageX={StageX} StageY={StageY} SourceZ={SourceZ} DetectorZ={DetectorZ} " +
|
"StageX={StageX} StageY={StageY} SourceZ={SourceZ} DetectorZ={DetectorZ} " +
|
||||||
"DetectorSwing={DetectorSwing} FDD={FDD} FOD={FOD} Magnification={Magnification} " +
|
"DetectorSwing={DetectorSwing} FDD={FDD} FOD={FOD} Magnification={Magnification} " +
|
||||||
"StageRotation={StageRotation} FixtureRotation={FixtureRotation}",
|
"StageRotation={StageRotation} FixtureRotation={FixtureRotation} SaveImage={SaveImage}",
|
||||||
sp.Index, sp.Name,
|
sp.Index, sp.Name,
|
||||||
sp.MotionState.StageX, sp.MotionState.StageY,
|
sp.MotionState.StageX, sp.MotionState.StageY,
|
||||||
sp.MotionState.SourceZ, sp.MotionState.DetectorZ,
|
sp.MotionState.SourceZ, sp.MotionState.DetectorZ,
|
||||||
sp.MotionState.DetectorSwing, sp.MotionState.FDD,
|
sp.MotionState.DetectorSwing, sp.MotionState.FDD,
|
||||||
sp.MotionState.FOD, sp.MotionState.Magnification,
|
sp.MotionState.FOD, sp.MotionState.Magnification,
|
||||||
sp.MotionState.StageRotation, sp.MotionState.FixtureRotation);
|
sp.MotionState.StageRotation, sp.MotionState.FixtureRotation,
|
||||||
|
sp.SaveImage);
|
||||||
|
|
||||||
|
if (sp.SaveImage)
|
||||||
|
{
|
||||||
|
var capturedImage = TryGetSourceImage();
|
||||||
|
if (capturedImage != null)
|
||||||
|
{
|
||||||
|
currentSourceImage = capturedImage;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.ForModule<CncExecutionService>().Warn(
|
||||||
|
"Save-position node '{0}' requested image capture, but no current image was available.",
|
||||||
|
sp.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SaveNodeNode sn:
|
case SaveNodeNode sn:
|
||||||
@@ -214,7 +231,7 @@ namespace XplorePlane.Services.Cnc
|
|||||||
case InspectionModuleNode inspectionNode:
|
case InspectionModuleNode inspectionNode:
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var img = await ExecuteInspectionNodeAsync(runId, inspectionNode, sourceImage, linkedCts.Token);
|
var img = await ExecuteInspectionNodeAsync(runId, inspectionNode, currentSourceImage, linkedCts.Token);
|
||||||
if (img != null) lastResultImage = img;
|
if (img != null) lastResultImage = img;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|||||||
@@ -430,7 +430,8 @@ namespace XplorePlane.Services.Cnc
|
|||||||
{
|
{
|
||||||
return new SavePositionNode(
|
return new SavePositionNode(
|
||||||
id, index, $"检测位置_{index}",
|
id, index, $"检测位置_{index}",
|
||||||
MotionState: _appStateService.MotionState);
|
MotionState: _appStateService.MotionState,
|
||||||
|
SaveImage: false);
|
||||||
}
|
}
|
||||||
private double TryReadCurrent()
|
private double TryReadCurrent()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -930,9 +930,7 @@ WHERE run_id = @run_id";
|
|||||||
{
|
{
|
||||||
return Path.Combine(
|
return Path.Combine(
|
||||||
"Results",
|
"Results",
|
||||||
startedAt.Value.ToString("yyyy"),
|
startedAt.Value.ToString("yyyy-MM-dd"),
|
||||||
startedAt.Value.ToString("MM"),
|
|
||||||
startedAt.Value.ToString("dd"),
|
|
||||||
runId.ToString("D"));
|
runId.ToString("D"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -420,7 +420,7 @@ namespace XplorePlane.ViewModels.Cnc
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
sb.AppendLine("Index,NodeType,Name,SourceZ,DetectorZ,StageX,StageY,DetectorSwing,StageRotation,FixtureRotation,FOD,FDD,Magnification,Voltage_kV,Current_uA,Power_W,RayOn,DetectorConnected,FrameRate,Resolution,ImageFile,MarkerType,MarkerX,MarkerY,DialogTitle,DialogMessage,DelayMs,Pipeline");
|
sb.AppendLine("Index,NodeType,Name,SourceZ,DetectorZ,StageX,StageY,DetectorSwing,StageRotation,FixtureRotation,FOD,FDD,Magnification,Voltage_kV,Current_uA,Power_W,RayOn,DetectorConnected,FrameRate,Resolution,ImageFile,SaveImage,MarkerType,MarkerX,MarkerY,DialogTitle,DialogMessage,DelayMs,Pipeline");
|
||||||
|
|
||||||
var inv = CultureInfo.InvariantCulture;
|
var inv = CultureInfo.InvariantCulture;
|
||||||
|
|
||||||
@@ -431,13 +431,13 @@ namespace XplorePlane.ViewModels.Cnc
|
|||||||
ReferencePointNode rp => $"{rp.Index},{rp.NodeType},{Esc(rp.Name)},{rp.SourceZ.ToString(inv)},{rp.DetectorZ.ToString(inv)},{rp.StageX.ToString(inv)},{rp.StageY.ToString(inv)},{rp.DetectorSwing.ToString(inv)},{rp.StageRotation.ToString(inv)},{rp.FixtureRotation.ToString(inv)},{rp.FOD.ToString(inv)},{rp.FDD.ToString(inv)},{rp.Magnification.ToString(inv)},{rp.Voltage.ToString(inv)},{rp.Current.ToString(inv)},,{rp.IsRayOn},,,,,,,,,,",
|
ReferencePointNode rp => $"{rp.Index},{rp.NodeType},{Esc(rp.Name)},{rp.SourceZ.ToString(inv)},{rp.DetectorZ.ToString(inv)},{rp.StageX.ToString(inv)},{rp.StageY.ToString(inv)},{rp.DetectorSwing.ToString(inv)},{rp.StageRotation.ToString(inv)},{rp.FixtureRotation.ToString(inv)},{rp.FOD.ToString(inv)},{rp.FDD.ToString(inv)},{rp.Magnification.ToString(inv)},{rp.Voltage.ToString(inv)},{rp.Current.ToString(inv)},,{rp.IsRayOn},,,,,,,,,,",
|
||||||
SaveNodeWithImageNode sni => $"{sni.Index},{sni.NodeType},{Esc(sni.Name)},{sni.MotionState.SourceZ.ToString(inv)},{sni.MotionState.DetectorZ.ToString(inv)},{sni.MotionState.StageX.ToString(inv)},{sni.MotionState.StageY.ToString(inv)},{sni.MotionState.DetectorSwing.ToString(inv)},{sni.MotionState.StageRotation.ToString(inv)},{sni.MotionState.FixtureRotation.ToString(inv)},{sni.MotionState.FOD.ToString(inv)},{sni.MotionState.FDD.ToString(inv)},{sni.MotionState.Magnification.ToString(inv)},{sni.RaySourceState.Voltage.ToString(inv)},,{sni.RaySourceState.Power.ToString(inv)},{sni.RaySourceState.IsOn},{sni.DetectorState.IsConnected},{sni.DetectorState.FrameRate.ToString(inv)},{Esc(sni.DetectorState.Resolution)},{Esc(sni.ImageFileName)},,,,,,",
|
SaveNodeWithImageNode sni => $"{sni.Index},{sni.NodeType},{Esc(sni.Name)},{sni.MotionState.SourceZ.ToString(inv)},{sni.MotionState.DetectorZ.ToString(inv)},{sni.MotionState.StageX.ToString(inv)},{sni.MotionState.StageY.ToString(inv)},{sni.MotionState.DetectorSwing.ToString(inv)},{sni.MotionState.StageRotation.ToString(inv)},{sni.MotionState.FixtureRotation.ToString(inv)},{sni.MotionState.FOD.ToString(inv)},{sni.MotionState.FDD.ToString(inv)},{sni.MotionState.Magnification.ToString(inv)},{sni.RaySourceState.Voltage.ToString(inv)},,{sni.RaySourceState.Power.ToString(inv)},{sni.RaySourceState.IsOn},{sni.DetectorState.IsConnected},{sni.DetectorState.FrameRate.ToString(inv)},{Esc(sni.DetectorState.Resolution)},{Esc(sni.ImageFileName)},,,,,,",
|
||||||
SaveNodeNode sn => $"{sn.Index},{sn.NodeType},{Esc(sn.Name)},{sn.MotionState.SourceZ.ToString(inv)},{sn.MotionState.DetectorZ.ToString(inv)},{sn.MotionState.StageX.ToString(inv)},{sn.MotionState.StageY.ToString(inv)},{sn.MotionState.DetectorSwing.ToString(inv)},{sn.MotionState.StageRotation.ToString(inv)},{sn.MotionState.FixtureRotation.ToString(inv)},{sn.MotionState.FOD.ToString(inv)},{sn.MotionState.FDD.ToString(inv)},{sn.MotionState.Magnification.ToString(inv)},{sn.RaySourceState.Voltage.ToString(inv)},,{sn.RaySourceState.Power.ToString(inv)},{sn.RaySourceState.IsOn},{sn.DetectorState.IsConnected},{sn.DetectorState.FrameRate.ToString(inv)},{Esc(sn.DetectorState.Resolution)},,,,,,,",
|
SaveNodeNode sn => $"{sn.Index},{sn.NodeType},{Esc(sn.Name)},{sn.MotionState.SourceZ.ToString(inv)},{sn.MotionState.DetectorZ.ToString(inv)},{sn.MotionState.StageX.ToString(inv)},{sn.MotionState.StageY.ToString(inv)},{sn.MotionState.DetectorSwing.ToString(inv)},{sn.MotionState.StageRotation.ToString(inv)},{sn.MotionState.FixtureRotation.ToString(inv)},{sn.MotionState.FOD.ToString(inv)},{sn.MotionState.FDD.ToString(inv)},{sn.MotionState.Magnification.ToString(inv)},{sn.RaySourceState.Voltage.ToString(inv)},,{sn.RaySourceState.Power.ToString(inv)},{sn.RaySourceState.IsOn},{sn.DetectorState.IsConnected},{sn.DetectorState.FrameRate.ToString(inv)},{Esc(sn.DetectorState.Resolution)},,,,,,,",
|
||||||
SavePositionNode sp => $"{sp.Index},{sp.NodeType},{Esc(sp.Name)},{sp.MotionState.SourceZ.ToString(inv)},{sp.MotionState.DetectorZ.ToString(inv)},{sp.MotionState.StageX.ToString(inv)},{sp.MotionState.StageY.ToString(inv)},{sp.MotionState.DetectorSwing.ToString(inv)},{sp.MotionState.StageRotation.ToString(inv)},{sp.MotionState.FixtureRotation.ToString(inv)},{sp.MotionState.FOD.ToString(inv)},{sp.MotionState.FDD.ToString(inv)},{sp.MotionState.Magnification.ToString(inv)},,,,,,,,,,,,,,",
|
SavePositionNode sp => $"{sp.Index},{sp.NodeType},{Esc(sp.Name)},{sp.MotionState.SourceZ.ToString(inv)},{sp.MotionState.DetectorZ.ToString(inv)},{sp.MotionState.StageX.ToString(inv)},{sp.MotionState.StageY.ToString(inv)},{sp.MotionState.DetectorSwing.ToString(inv)},{sp.MotionState.StageRotation.ToString(inv)},{sp.MotionState.FixtureRotation.ToString(inv)},{sp.MotionState.FOD.ToString(inv)},{sp.MotionState.FDD.ToString(inv)},{sp.MotionState.Magnification.ToString(inv)},,,,,,,,{sp.SaveImage},,,,,,,",
|
||||||
InspectionModuleNode im => $"{im.Index},{im.NodeType},{Esc(im.Name)},,,,,,,,,,,,,,,,,,,,,,{Esc(im.Pipeline?.Name ?? string.Empty)}",
|
InspectionModuleNode im => $"{im.Index},{im.NodeType},{Esc(im.Name)},,,,,,,,,,,,,,,,,,,,,,,{Esc(im.Pipeline?.Name ?? string.Empty)}",
|
||||||
InspectionMarkerNode mk => $"{mk.Index},{mk.NodeType},{Esc(mk.Name)},,,,,,,,,,,,,,,,,{Esc(mk.MarkerType)},{mk.MarkerX.ToString(inv)},{mk.MarkerY.ToString(inv)},,,",
|
InspectionMarkerNode mk => $"{mk.Index},{mk.NodeType},{Esc(mk.Name)},,,,,,,,,,,,,,,,,,{Esc(mk.MarkerType)},{mk.MarkerX.ToString(inv)},{mk.MarkerY.ToString(inv)},,,",
|
||||||
PauseDialogNode pd => $"{pd.Index},{pd.NodeType},{Esc(pd.Name)},,,,,,,,,,,,,,,,,,,{Esc(pd.DialogTitle)},{Esc(pd.DialogMessage)},,",
|
PauseDialogNode pd => $"{pd.Index},{pd.NodeType},{Esc(pd.Name)},,,,,,,,,,,,,,,,,,,,{Esc(pd.DialogTitle)},{Esc(pd.DialogMessage)},,",
|
||||||
WaitDelayNode wd => $"{wd.Index},{wd.NodeType},{Esc(wd.Name)},,,,,,,,,,,,,,,,,,,,,{wd.DelayMilliseconds},",
|
WaitDelayNode wd => $"{wd.Index},{wd.NodeType},{Esc(wd.Name)},,,,,,,,,,,,,,,,,,,,,,{wd.DelayMilliseconds},",
|
||||||
CompleteProgramNode cp => $"{cp.Index},{cp.NodeType},{Esc(cp.Name)},,,,,,,,,,,,,,,,,,,,,,",
|
CompleteProgramNode cp => $"{cp.Index},{cp.NodeType},{Esc(cp.Name)},,,,,,,,,,,,,,,,,,,,,,,",
|
||||||
_ => $"{node.Index},{node.NodeType},{Esc(node.Name)},,,,,,,,,,,,,,,,,,,,,,"
|
_ => $"{node.Index},{node.NodeType},{Esc(node.Name)},,,,,,,,,,,,,,,,,,,,,,,"
|
||||||
};
|
};
|
||||||
|
|
||||||
sb.AppendLine(row);
|
sb.AppendLine(row);
|
||||||
|
|||||||
@@ -349,6 +349,18 @@ namespace XplorePlane.ViewModels.Cnc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool SaveImage
|
||||||
|
{
|
||||||
|
get => _model is SavePositionNode sp && sp.SaveImage;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_model is SavePositionNode sp)
|
||||||
|
{
|
||||||
|
UpdateModel(sp with { SaveImage = value });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public string PipelineName
|
public string PipelineName
|
||||||
{
|
{
|
||||||
get => _model is InspectionModuleNode im ? im.Pipeline?.Name ?? string.Empty : string.Empty;
|
get => _model is InspectionModuleNode im ? im.Pipeline?.Name ?? string.Empty : string.Empty;
|
||||||
@@ -636,6 +648,7 @@ namespace XplorePlane.ViewModels.Cnc
|
|||||||
RaisePropertyChanged(nameof(FrameRate));
|
RaisePropertyChanged(nameof(FrameRate));
|
||||||
RaisePropertyChanged(nameof(Resolution));
|
RaisePropertyChanged(nameof(Resolution));
|
||||||
RaisePropertyChanged(nameof(ImageFileName));
|
RaisePropertyChanged(nameof(ImageFileName));
|
||||||
|
RaisePropertyChanged(nameof(SaveImage));
|
||||||
RaisePropertyChanged(nameof(Pipeline));
|
RaisePropertyChanged(nameof(Pipeline));
|
||||||
RaisePropertyChanged(nameof(PipelineName));
|
RaisePropertyChanged(nameof(PipelineName));
|
||||||
RaisePropertyChanged(nameof(MarkerType));
|
RaisePropertyChanged(nameof(MarkerType));
|
||||||
|
|||||||
@@ -584,6 +584,15 @@
|
|||||||
</StackPanel>
|
</StackPanel>
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
|
|
||||||
|
<GroupBox
|
||||||
|
Style="{StaticResource CompactGroupBox}"
|
||||||
|
Header="位置参数"
|
||||||
|
Visibility="{Binding SelectedNode.IsSavePosition, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||||
|
<StackPanel Margin="8,8,8,6">
|
||||||
|
<CheckBox Style="{StaticResource EditorCheck}" Content="保存图像" IsChecked="{Binding SelectedNode.SaveImage}" />
|
||||||
|
</StackPanel>
|
||||||
|
</GroupBox>
|
||||||
|
|
||||||
<GroupBox
|
<GroupBox
|
||||||
Style="{StaticResource CompactGroupBox}"
|
Style="{StaticResource CompactGroupBox}"
|
||||||
Header="检测标记"
|
Header="检测标记"
|
||||||
|
|||||||
@@ -232,9 +232,12 @@ namespace XplorePlane.Views.Cnc
|
|||||||
}
|
}
|
||||||
|
|
||||||
var label = EnsureCheckDisplayLabel(checkBox, bindingPath);
|
var label = EnsureCheckDisplayLabel(checkBox, bindingPath);
|
||||||
checkBox.IsEnabled = !isReadOnlyNode;
|
bool allowEditWhenReadOnly = bindingPath == "SelectedNode.SaveImage";
|
||||||
checkBox.Visibility = isReadOnlyNode ? Visibility.Collapsed : Visibility.Visible;
|
bool showReadOnlyLabel = isReadOnlyNode && !allowEditWhenReadOnly;
|
||||||
label.Visibility = isReadOnlyNode ? Visibility.Visible : Visibility.Collapsed;
|
|
||||||
|
checkBox.IsEnabled = !isReadOnlyNode || allowEditWhenReadOnly;
|
||||||
|
checkBox.Visibility = showReadOnlyLabel ? Visibility.Collapsed : Visibility.Visible;
|
||||||
|
label.Visibility = showReadOnlyLabel ? Visibility.Visible : Visibility.Collapsed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user