Compare commits
2 Commits
2a64d48b54
...
2969ada965
| Author | SHA1 | Date | |
|---|---|---|---|
| 2969ada965 | |||
| 06714f819f |
@@ -3,6 +3,7 @@ using System.Linq;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
using XP.Common.GeneralForm.Views;
|
||||||
using XP.Common.Logging.Interfaces;
|
using XP.Common.Logging.Interfaces;
|
||||||
using XplorePlane.Models;
|
using XplorePlane.Models;
|
||||||
using XplorePlane.Services.InspectionResults;
|
using XplorePlane.Services.InspectionResults;
|
||||||
@@ -71,7 +72,7 @@ namespace XplorePlane.Services.Cnc
|
|||||||
case WaitDelayNode waitNode:
|
case WaitDelayNode waitNode:
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await Task.Delay(waitNode.DelayMilliseconds, cancellationToken);
|
await ExecuteWaitDelayWithProgressAsync(waitNode, cancellationToken);
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
{
|
{
|
||||||
@@ -160,5 +161,49 @@ namespace XplorePlane.Services.Cnc
|
|||||||
"Failed to complete inspection run '{0}'", runId);
|
"Failed to complete inspection run '{0}'", runId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static async Task ExecuteWaitDelayWithProgressAsync(WaitDelayNode waitNode, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
int totalMs = waitNode.DelayMilliseconds;
|
||||||
|
if (totalMs <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const int tickMs = 50;
|
||||||
|
ProgressWindow progressWindow = null;
|
||||||
|
|
||||||
|
await Application.Current.Dispatcher.InvokeAsync(() =>
|
||||||
|
{
|
||||||
|
progressWindow = new ProgressWindow(
|
||||||
|
title: "延时等待",
|
||||||
|
message: $"节点:{waitNode.Name} 等待 {totalMs / 1000.0:F1} 秒",
|
||||||
|
isCancelable: false);
|
||||||
|
progressWindow.Owner = Application.Current.MainWindow;
|
||||||
|
progressWindow.Show();
|
||||||
|
});
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int elapsed = 0;
|
||||||
|
while (elapsed < totalMs)
|
||||||
|
{
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
int remaining = totalMs - elapsed;
|
||||||
|
int delay = Math.Min(tickMs, remaining);
|
||||||
|
await Task.Delay(delay, cancellationToken);
|
||||||
|
elapsed += delay;
|
||||||
|
|
||||||
|
double pct = Math.Min(100.0 * elapsed / totalMs, 100.0);
|
||||||
|
double remainSec = Math.Max(0, (totalMs - elapsed) / 1000.0);
|
||||||
|
string msg = $"节点:{waitNode.Name} 剩余 {remainSec:F1} 秒";
|
||||||
|
|
||||||
|
progressWindow?.UpdateProgress(msg, pct);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
progressWindow?.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,9 @@ namespace XplorePlane.ViewModels.Cnc
|
|||||||
private bool _pendingInsertAfterAnchor;
|
private bool _pendingInsertAfterAnchor;
|
||||||
private CancellationTokenSource _cts;
|
private CancellationTokenSource _cts;
|
||||||
private bool _isRunning;
|
private bool _isRunning;
|
||||||
|
private string _statusMessage = "就绪";
|
||||||
|
private string _executionError;
|
||||||
|
private bool _hasExecutionError;
|
||||||
|
|
||||||
public CncEditorViewModel(
|
public CncEditorViewModel(
|
||||||
ICncProgramService cncProgramService,
|
ICncProgramService cncProgramService,
|
||||||
@@ -159,6 +162,24 @@ namespace XplorePlane.ViewModels.Cnc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string StatusMessage
|
||||||
|
{
|
||||||
|
get => _statusMessage;
|
||||||
|
private set => SetProperty(ref _statusMessage, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ExecutionError
|
||||||
|
{
|
||||||
|
get => _executionError;
|
||||||
|
private set => SetProperty(ref _executionError, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool HasExecutionError
|
||||||
|
{
|
||||||
|
get => _hasExecutionError;
|
||||||
|
private set => SetProperty(ref _hasExecutionError, value);
|
||||||
|
}
|
||||||
|
|
||||||
public DelegateCommand InsertReferencePointCommand { get; }
|
public DelegateCommand InsertReferencePointCommand { get; }
|
||||||
public DelegateCommand InsertSaveNodeWithImageCommand { get; }
|
public DelegateCommand InsertSaveNodeWithImageCommand { get; }
|
||||||
public DelegateCommand InsertSaveNodeCommand { get; }
|
public DelegateCommand InsertSaveNodeCommand { get; }
|
||||||
@@ -435,14 +456,28 @@ namespace XplorePlane.ViewModels.Cnc
|
|||||||
{
|
{
|
||||||
_cts = new CancellationTokenSource();
|
_cts = new CancellationTokenSource();
|
||||||
IsRunning = true;
|
IsRunning = true;
|
||||||
|
HasExecutionError = false;
|
||||||
|
ExecutionError = null;
|
||||||
|
StatusMessage = $"正在执行:{_currentProgram?.Name ?? "程序"}(共 {_currentProgram?.Nodes?.Count ?? 0} 个节点)";
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var progress = new Progress<CncNodeExecutionProgress>(OnExecutionProgress);
|
var progress = new Progress<CncNodeExecutionProgress>(OnExecutionProgress);
|
||||||
await _cncExecutionService.ExecuteAsync(_currentProgram, progress, _cts.Token);
|
await _cncExecutionService.ExecuteAsync(_currentProgram, progress, _cts.Token);
|
||||||
|
if (_cts.IsCancellationRequested)
|
||||||
|
StatusMessage = "执行已停止";
|
||||||
|
else
|
||||||
|
StatusMessage = $"执行完成:{_currentProgram?.Name}";
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
StatusMessage = "执行已取消";
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.Error(ex, "CNC execution failed");
|
_logger.Error(ex, "CNC execution failed");
|
||||||
|
ExecutionError = ex.Message;
|
||||||
|
HasExecutionError = true;
|
||||||
|
StatusMessage = $"执行失败:{ex.Message}";
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -462,7 +497,17 @@ namespace XplorePlane.ViewModels.Cnc
|
|||||||
{
|
{
|
||||||
var nodeVm = Nodes.FirstOrDefault(n => n.Id == progress.NodeId);
|
var nodeVm = Nodes.FirstOrDefault(n => n.Id == progress.NodeId);
|
||||||
if (nodeVm != null)
|
if (nodeVm != null)
|
||||||
|
{
|
||||||
nodeVm.ExecutionState = progress.State;
|
nodeVm.ExecutionState = progress.State;
|
||||||
|
if (progress.State == NodeExecutionState.Running)
|
||||||
|
StatusMessage = $"正在执行节点:{nodeVm.Name}({nodeVm.Index + 1}/{_currentProgram?.Nodes?.Count ?? 0})";
|
||||||
|
else if (progress.State == NodeExecutionState.Failed)
|
||||||
|
{
|
||||||
|
HasExecutionError = true;
|
||||||
|
ExecutionError = $"节点 [{nodeVm.Name}] 执行失败";
|
||||||
|
StatusMessage = $"错误:节点 [{nodeVm.Name}] 执行失败";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ResetAllNodeStates()
|
private void ResetAllNodeStates()
|
||||||
@@ -485,6 +530,8 @@ namespace XplorePlane.ViewModels.Cnc
|
|||||||
DeleteNodeCommand.RaiseCanExecuteChanged();
|
DeleteNodeCommand.RaiseCanExecuteChanged();
|
||||||
MoveNodeUpCommand.RaiseCanExecuteChanged();
|
MoveNodeUpCommand.RaiseCanExecuteChanged();
|
||||||
MoveNodeDownCommand.RaiseCanExecuteChanged();
|
MoveNodeDownCommand.RaiseCanExecuteChanged();
|
||||||
|
RunCncCommand.RaiseCanExecuteChanged();
|
||||||
|
StopCncCommand.RaiseCanExecuteChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnProgramEdited()
|
private void OnProgramEdited()
|
||||||
@@ -557,6 +604,7 @@ namespace XplorePlane.ViewModels.Cnc
|
|||||||
: Nodes.LastOrDefault();
|
: Nodes.LastOrDefault();
|
||||||
|
|
||||||
_preferredSelectedNodeId = null;
|
_preferredSelectedNodeId = null;
|
||||||
|
RaiseEditCommandsCanExecuteChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void NormalizeDefaultNodeNamesInCurrentProgram()
|
private void NormalizeDefaultNodeNamesInCurrentProgram()
|
||||||
|
|||||||
@@ -57,6 +57,20 @@ namespace XplorePlane.ViewModels
|
|||||||
_cncPageView = new CncPageView { DataContext = _cncEditorViewModel };
|
_cncPageView = new CncPageView { DataContext = _cncEditorViewModel };
|
||||||
|
|
||||||
_mainViewportService.StateChanged += OnMainViewportStateChanged;
|
_mainViewportService.StateChanged += OnMainViewportStateChanged;
|
||||||
|
_cncEditorViewModel.PropertyChanged += (s, e) =>
|
||||||
|
{
|
||||||
|
if (e.PropertyName == nameof(CncEditorViewModel.StatusMessage))
|
||||||
|
RaisePropertyChanged(nameof(CncStatusMessage));
|
||||||
|
else if (e.PropertyName == nameof(CncEditorViewModel.HasExecutionError))
|
||||||
|
RaisePropertyChanged(nameof(CncHasExecutionError));
|
||||||
|
else if (e.PropertyName == nameof(CncEditorViewModel.IsRunning))
|
||||||
|
{
|
||||||
|
RunCncCommand.RaiseCanExecuteChanged();
|
||||||
|
StopCncCommand.RaiseCanExecuteChanged();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
_cncEditorViewModel.RunCncCommand.CanExecuteChanged += (s, e) => RunCncCommand.RaiseCanExecuteChanged();
|
||||||
|
_cncEditorViewModel.StopCncCommand.CanExecuteChanged += (s, e) => StopCncCommand.RaiseCanExecuteChanged();
|
||||||
|
|
||||||
NavigationTree = new ObservableCollection<object>();
|
NavigationTree = new ObservableCollection<object>();
|
||||||
|
|
||||||
@@ -87,8 +101,12 @@ namespace XplorePlane.ViewModels
|
|||||||
InsertSaveNodeCommand = new DelegateCommand(() => ExecuteCncEditorAction(vm => vm.InsertSaveNodeCommand.Execute()));
|
InsertSaveNodeCommand = new DelegateCommand(() => ExecuteCncEditorAction(vm => vm.InsertSaveNodeCommand.Execute()));
|
||||||
InsertPauseDialogCommand = new DelegateCommand(() => ExecuteCncEditorAction(vm => vm.InsertPauseDialogCommand.Execute()));
|
InsertPauseDialogCommand = new DelegateCommand(() => ExecuteCncEditorAction(vm => vm.InsertPauseDialogCommand.Execute()));
|
||||||
InsertWaitDelayCommand = new DelegateCommand(() => ExecuteCncEditorAction(vm => vm.InsertWaitDelayCommand.Execute()));
|
InsertWaitDelayCommand = new DelegateCommand(() => ExecuteCncEditorAction(vm => vm.InsertWaitDelayCommand.Execute()));
|
||||||
RunCncCommand = new DelegateCommand(() => ExecuteCncEditorAction(vm => vm.RunCncCommand.Execute()));
|
RunCncCommand = new DelegateCommand(
|
||||||
StopCncCommand = new DelegateCommand(() => ExecuteCncEditorAction(vm => vm.StopCncCommand.Execute()));
|
() => ExecuteCncEditorAction(vm => vm.RunCncCommand.Execute()),
|
||||||
|
() => _cncEditorViewModel.RunCncCommand.CanExecute());
|
||||||
|
StopCncCommand = new DelegateCommand(
|
||||||
|
() => ExecuteCncEditorAction(vm => vm.StopCncCommand.Execute()),
|
||||||
|
() => _cncEditorViewModel.StopCncCommand.CanExecute());
|
||||||
|
|
||||||
PointDistanceMeasureCommand = new DelegateCommand(ExecutePointDistanceMeasure);
|
PointDistanceMeasureCommand = new DelegateCommand(ExecutePointDistanceMeasure);
|
||||||
PointLineDistanceMeasureCommand = new DelegateCommand(ExecutePointLineDistanceMeasure);
|
PointLineDistanceMeasureCommand = new DelegateCommand(ExecutePointLineDistanceMeasure);
|
||||||
@@ -121,6 +139,9 @@ namespace XplorePlane.ViewModels
|
|||||||
set => SetProperty(ref _licenseInfo, value);
|
set => SetProperty(ref _licenseInfo, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string CncStatusMessage => _cncEditorViewModel.StatusMessage;
|
||||||
|
public bool CncHasExecutionError => _cncEditorViewModel.HasExecutionError;
|
||||||
|
|
||||||
public ObservableCollection<object> NavigationTree { get; set; }
|
public ObservableCollection<object> NavigationTree { get; set; }
|
||||||
|
|
||||||
public DelegateCommand NavigateHomeCommand { get; set; }
|
public DelegateCommand NavigateHomeCommand { get; set; }
|
||||||
|
|||||||
@@ -106,6 +106,7 @@
|
|||||||
<StackPanel>
|
<StackPanel>
|
||||||
<telerik:RadRibbonButton
|
<telerik:RadRibbonButton
|
||||||
telerik:ScreenTip.Title="运行"
|
telerik:ScreenTip.Title="运行"
|
||||||
|
Command="{Binding RunCncCommand}"
|
||||||
Size="Large"
|
Size="Large"
|
||||||
SmallImage="/Assets/Icons/run.png"
|
SmallImage="/Assets/Icons/run.png"
|
||||||
Text="运行" />
|
Text="运行" />
|
||||||
@@ -114,6 +115,7 @@
|
|||||||
<telerik:RadRibbonButton
|
<telerik:RadRibbonButton
|
||||||
telerik:ScreenTip.Description="停止"
|
telerik:ScreenTip.Description="停止"
|
||||||
telerik:ScreenTip.Title="停止"
|
telerik:ScreenTip.Title="停止"
|
||||||
|
Command="{Binding StopCncCommand}"
|
||||||
Size="Large"
|
Size="Large"
|
||||||
SmallImage="/Assets/Icons/stop.png"
|
SmallImage="/Assets/Icons/stop.png"
|
||||||
Text="停止" />
|
Text="停止" />
|
||||||
@@ -554,7 +556,19 @@
|
|||||||
FontFamily="Microsoft YaHei UI"
|
FontFamily="Microsoft YaHei UI"
|
||||||
FontSize="11"
|
FontSize="11"
|
||||||
Foreground="White"
|
Foreground="White"
|
||||||
Text="就绪" />
|
Text="{Binding CncStatusMessage}">
|
||||||
|
<TextBlock.Style>
|
||||||
|
<Style TargetType="TextBlock">
|
||||||
|
<Setter Property="Foreground" Value="White" />
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding CncHasExecutionError}" Value="True">
|
||||||
|
<Setter Property="Foreground" Value="#FF9090" />
|
||||||
|
<Setter Property="FontWeight" Value="SemiBold" />
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</TextBlock.Style>
|
||||||
|
</TextBlock>
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
@@ -563,7 +577,7 @@
|
|||||||
FontFamily="Consolas"
|
FontFamily="Consolas"
|
||||||
FontSize="11"
|
FontSize="11"
|
||||||
Foreground="White"
|
Foreground="White"
|
||||||
Text="x: 0 y: 0 RGB: 0 0 0" />
|
Text="x: 0 y: 0" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
Reference in New Issue
Block a user