完善执行逻辑
This commit is contained in:
parent
45ebf1f2b6
commit
b69a469c89
@ -1,4 +1,5 @@
|
|||||||
using BOB.Models;
|
using BOB.Converters;
|
||||||
|
using BOB.Models;
|
||||||
using BOB.ViewModels;
|
using BOB.ViewModels;
|
||||||
using BOB.ViewModels.Dialogs;
|
using BOB.ViewModels.Dialogs;
|
||||||
using BOB.Views;
|
using BOB.Views;
|
||||||
@ -38,7 +39,7 @@ namespace BOB
|
|||||||
containerRegistry.RegisterDialog<DeviceSetting, DeviceSettingViewModel>("DeviceSetting");
|
containerRegistry.RegisterDialog<DeviceSetting, DeviceSettingViewModel>("DeviceSetting");
|
||||||
//注册全局变量
|
//注册全局变量
|
||||||
containerRegistry.RegisterSingleton<GlobalVariables>();
|
containerRegistry.RegisterSingleton<GlobalVariables>();
|
||||||
|
containerRegistry.RegisterSingleton<StepRunning>();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
123
BOB/Converters/ParameterToGotoSettingStringConverter.cs
Normal file
123
BOB/Converters/ParameterToGotoSettingStringConverter.cs
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Data;
|
||||||
|
|
||||||
|
namespace BOB.Converters
|
||||||
|
{
|
||||||
|
public class ParameterToGotoSettingStringConverter : IValueConverter
|
||||||
|
{
|
||||||
|
private GlobalVariables _globalVariables;
|
||||||
|
public ParameterToGotoSettingStringConverter(GlobalVariables globalVariables)
|
||||||
|
{
|
||||||
|
_globalVariables= globalVariables;
|
||||||
|
}
|
||||||
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
if (value is Guid stepID && stepID == _globalVariables.SelectedStep!.ID)
|
||||||
|
{
|
||||||
|
if (_globalVariables.SelectedStep == null)
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
if (_globalVariables.SelectedStep!.OKGotoStepID == null && _globalVariables.SelectedStep!.NGGotoStepID == null)
|
||||||
|
{
|
||||||
|
return "0/0";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string gotoString = "";
|
||||||
|
if (_globalVariables.SelectedStep!.OKGotoStepID != null)
|
||||||
|
{
|
||||||
|
var OKGotoStep = _globalVariables.Program.StepCollection.FirstOrDefault(x => x.ID == _globalVariables.SelectedStep!.OKGotoStepID);
|
||||||
|
if (OKGotoStep != null)
|
||||||
|
{
|
||||||
|
gotoString = OKGotoStep.Index.ToString() + "/";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gotoString = "0/";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gotoString = "0/";
|
||||||
|
}
|
||||||
|
if (_globalVariables.SelectedStep!.NGGotoStepID != null)
|
||||||
|
{
|
||||||
|
var NGGotoStep = _globalVariables.Program.StepCollection.FirstOrDefault(x => x.ID == _globalVariables.SelectedStep!.NGGotoStepID);
|
||||||
|
if (NGGotoStep != null)
|
||||||
|
{
|
||||||
|
gotoString += NGGotoStep.Index.ToString();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gotoString += "0";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gotoString += "0";
|
||||||
|
}
|
||||||
|
return gotoString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
if (value is string gotoSettingstring)
|
||||||
|
{
|
||||||
|
gotoSettingstring = gotoSettingstring.Replace(" ", "").Replace("/n", "").Replace("/r", "");
|
||||||
|
if (gotoSettingstring == "0/0")
|
||||||
|
{
|
||||||
|
_globalVariables.SelectedStep!.OKGotoStepID = null;
|
||||||
|
_globalVariables.SelectedStep!.NGGotoStepID = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var list = gotoSettingstring.Split("/");
|
||||||
|
var okindex = System.Convert.ToInt32(list[0]);
|
||||||
|
var ngindex = System.Convert.ToInt32(list[1]);
|
||||||
|
if (okindex == 0)
|
||||||
|
{
|
||||||
|
_globalVariables.SelectedStep!.OKGotoStepID = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (okindex > _globalVariables.Program.StepCollection.Count)
|
||||||
|
{
|
||||||
|
throw new Exception("步骤序号超出最大值");
|
||||||
|
}
|
||||||
|
_globalVariables.SelectedStep!.OKGotoStepID = _globalVariables.Program.StepCollection.FirstOrDefault(x => x.Index == okindex)?.ID;
|
||||||
|
}
|
||||||
|
if (ngindex == 0)
|
||||||
|
{
|
||||||
|
_globalVariables.SelectedStep!.NGGotoStepID = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (ngindex > _globalVariables.Program.StepCollection.Count)
|
||||||
|
{
|
||||||
|
throw new Exception("步骤序号超出最大值");
|
||||||
|
}
|
||||||
|
_globalVariables.SelectedStep!.NGGotoStepID = _globalVariables.Program.StepCollection.FirstOrDefault(x => x.Index == ngindex)?.ID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
MessageBox.Show($"跳转表达式错误:{ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _globalVariables.SelectedStep!.ID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,7 +1,10 @@
|
|||||||
using BOB.Models;
|
using BOB.Models;
|
||||||
|
using MaterialDesignThemes.Wpf;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -14,6 +17,11 @@ namespace BOB
|
|||||||
public String UserName { get; set; } = "hsc";
|
public String UserName { get; set; } = "hsc";
|
||||||
public String Title { get; set; } = "主程序";
|
public String Title { get; set; } = "主程序";
|
||||||
public string CurrentFilePath { get; set; }
|
public string CurrentFilePath { get; set; }
|
||||||
|
public bool? IsStop { get; set; }
|
||||||
|
public bool SingleStep { get; set; }
|
||||||
|
public string RunState { get; set; } = "运行";
|
||||||
|
public ObservableCollection<Assembly> Assemblies { get; set; } = new();
|
||||||
|
public PackIconKind RunIcon { get; set; } = PackIconKind.Play;
|
||||||
public StepModel SelectedStep { get; set; }
|
public StepModel SelectedStep { get; set; }
|
||||||
public ParameterModel SelectedParameter { get; set; }
|
public ParameterModel SelectedParameter { get; set; }
|
||||||
public DeviceModel SelectedDevice { get; set; }
|
public DeviceModel SelectedDevice { get; set; }
|
||||||
|
|||||||
@ -22,6 +22,7 @@ namespace BOB.Models
|
|||||||
LoopStartStepId = source.LoopStartStepId;
|
LoopStartStepId = source.LoopStartStepId;
|
||||||
OKExpression = source.OKExpression;
|
OKExpression = source.OKExpression;
|
||||||
OKGotoStepID = source.OKGotoStepID;
|
OKGotoStepID = source.OKGotoStepID;
|
||||||
|
GotoSettingString = source.GotoSettingString;
|
||||||
NGGotoStepID = source.NGGotoStepID;
|
NGGotoStepID = source.NGGotoStepID;
|
||||||
Description = source.Description;
|
Description = source.Description;
|
||||||
IsUsed = source.IsUsed;
|
IsUsed = source.IsUsed;
|
||||||
|
|||||||
531
BOB/StepRunning.cs
Normal file
531
BOB/StepRunning.cs
Normal file
@ -0,0 +1,531 @@
|
|||||||
|
using BOB.Models;
|
||||||
|
using Common.Tools;
|
||||||
|
using Logger;
|
||||||
|
using MaterialDesignThemes.Wpf;
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using static BOB.Models.ParameterModel;
|
||||||
|
|
||||||
|
|
||||||
|
namespace BOB
|
||||||
|
{
|
||||||
|
public class StepRunning
|
||||||
|
{
|
||||||
|
private GlobalVariables _globalVariables;
|
||||||
|
|
||||||
|
private readonly Dictionary<Guid, ParameterModel> tmpParameters = [];
|
||||||
|
|
||||||
|
private readonly Stopwatch stepStopwatch = new();
|
||||||
|
|
||||||
|
private readonly Stack<Stopwatch> loopStopwatchStack = new();
|
||||||
|
|
||||||
|
private readonly Stack<LoopContext> loopStack = new();
|
||||||
|
|
||||||
|
public CancellationTokenSource stepCTS = new();
|
||||||
|
private bool SubSingleStep = false;
|
||||||
|
|
||||||
|
private Guid TestRoundID;
|
||||||
|
public StepRunning(GlobalVariables globalVariables)
|
||||||
|
{
|
||||||
|
_globalVariables = globalVariables;
|
||||||
|
}
|
||||||
|
public async Task<bool> ExecuteSteps(ProgramModel program, int depth = 0, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
int index = 0;
|
||||||
|
bool stepSuccess = false;
|
||||||
|
if (depth == 0)
|
||||||
|
{
|
||||||
|
loopStack.Clear();
|
||||||
|
loopStopwatchStack.Clear();
|
||||||
|
ResetAllStepStatus(program);
|
||||||
|
tmpParameters.Clear();
|
||||||
|
TestRoundID = Guid.NewGuid();
|
||||||
|
}
|
||||||
|
foreach (var item in program.Parameters)
|
||||||
|
{
|
||||||
|
tmpParameters.TryAdd(item.ID, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (index < program.StepCollection.Count)
|
||||||
|
{
|
||||||
|
while (_globalVariables.IsStop == true)
|
||||||
|
{
|
||||||
|
await Task.Delay(50);
|
||||||
|
}
|
||||||
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
var step = program.StepCollection[index];
|
||||||
|
if (!step.IsUsed)
|
||||||
|
{
|
||||||
|
index++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
step.Result = 0;
|
||||||
|
if (step.StepType == "循环开始")
|
||||||
|
{
|
||||||
|
var endStep = program.StepCollection.FirstOrDefault(x => x.LoopStartStepId == step.ID);
|
||||||
|
if (endStep != null)
|
||||||
|
{
|
||||||
|
endStep.Result = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LoggerHelper.ErrorWithNotify("程序循环指令未闭合,请检查后重试");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理循环开始
|
||||||
|
if (step.StepType == "循环开始")
|
||||||
|
{
|
||||||
|
Stopwatch loopStopwatch = new();
|
||||||
|
loopStopwatch.Start();
|
||||||
|
loopStopwatchStack.Push(loopStopwatch);
|
||||||
|
var context = new LoopContext
|
||||||
|
{
|
||||||
|
LoopCount = step.LoopCount ?? 1,
|
||||||
|
CurrentLoop = 0,
|
||||||
|
StartIndex = index,
|
||||||
|
LoopStartStep = step
|
||||||
|
};
|
||||||
|
loopStack.Push(context);
|
||||||
|
step.CurrentLoopCount = context.LoopCount;
|
||||||
|
LoggerHelper.InfoWithNotify($"循环开始,共{context.LoopCount}次", depth);
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理循环结束
|
||||||
|
else if (step.StepType == "循环结束")
|
||||||
|
{
|
||||||
|
if (loopStack.Count == 0)
|
||||||
|
{
|
||||||
|
LoggerHelper.ErrorWithNotify("未匹配的循环结束指令", depth);
|
||||||
|
step.Result = 2;
|
||||||
|
index++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var context = loopStack.Peek();
|
||||||
|
context.CurrentLoop++;
|
||||||
|
|
||||||
|
// 更新循环开始步骤的显示
|
||||||
|
context.LoopStartStep!.CurrentLoopCount = context.LoopCount - context.CurrentLoop;
|
||||||
|
|
||||||
|
if (context.CurrentLoop < context.LoopCount)
|
||||||
|
{
|
||||||
|
// 继续循环:跳转到循环开始后的第一条指令
|
||||||
|
index = context.StartIndex + 1;
|
||||||
|
LoggerHelper.InfoWithNotify($"循环第{context.CurrentLoop}次结束,跳回开始,剩余{context.LoopCount - context.CurrentLoop}次", depth);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 循环结束
|
||||||
|
loopStack.Pop();
|
||||||
|
var loopStopwatch = loopStopwatchStack.Peek();
|
||||||
|
index++;
|
||||||
|
LoggerHelper.InfoWithNotify($"循环结束,共执行{context.LoopCount}次", depth);
|
||||||
|
if (depth == 0 && loopStopwatch.IsRunning)
|
||||||
|
{
|
||||||
|
loopStopwatch.Stop();
|
||||||
|
step.RunTime = (int)loopStopwatch.ElapsedMilliseconds;
|
||||||
|
step.Result = 1;
|
||||||
|
program.StepCollection.First(x => x.ID == step.LoopStartStepId).Result = 1;
|
||||||
|
loopStopwatchStack.Pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理普通步骤
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (depth == 0)
|
||||||
|
{
|
||||||
|
stepStopwatch.Restart();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (step.SubProgram != null)
|
||||||
|
{
|
||||||
|
if (_globalVariables.SingleStep)//子程序的单步执行将执行完保存下的所有Method
|
||||||
|
{
|
||||||
|
SubSingleStep = true;
|
||||||
|
_globalVariables.SingleStep = false;
|
||||||
|
}
|
||||||
|
LoggerHelper.InfoWithNotify($"开始执行子程序 [ {step.Index} ] [ {step.Name} ] ", depth);
|
||||||
|
stepSuccess = await ExecuteSteps(step.SubProgram, depth + 1, cancellationToken);
|
||||||
|
UpdateCurrentStepResult(step, true, stepSuccess, depth);
|
||||||
|
if (SubSingleStep)
|
||||||
|
{
|
||||||
|
SubSingleStep = false;
|
||||||
|
_globalVariables.SingleStep = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (step.Method != null)
|
||||||
|
{
|
||||||
|
LoggerHelper.InfoWithNotify($"开始执行指令 [ {step.Index} ] [ {step.Method!.FullName}.{step.Method.Name} ] ", depth);
|
||||||
|
await ExecuteMethodStep(step, tmpParameters, depth, cancellationToken);
|
||||||
|
stepSuccess = step.Result == 1;
|
||||||
|
if (step.NGGotoStepID != null && !stepSuccess)
|
||||||
|
{
|
||||||
|
var tmp = program.StepCollection.FirstOrDefault(x => x.ID == step.NGGotoStepID);
|
||||||
|
if (tmp != null)
|
||||||
|
{
|
||||||
|
index = tmp.Index - 2;
|
||||||
|
LoggerHelper.InfoWithNotify($"指令跳转 [ {tmp.Index} ] [ {tmp.Name} ]", depth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (step.OKGotoStepID != null && stepSuccess)
|
||||||
|
{
|
||||||
|
var tmp = program.StepCollection.FirstOrDefault(x => x.ID == step.OKGotoStepID);
|
||||||
|
if (tmp != null)
|
||||||
|
{
|
||||||
|
index = tmp.Index - 2;
|
||||||
|
LoggerHelper.InfoWithNotify($"指令跳转 [ {tmp.Index} ] [ {tmp.Name} ]", depth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
|
||||||
|
if (depth == 0 && stepStopwatch.IsRunning)
|
||||||
|
{
|
||||||
|
stepStopwatch.Stop();
|
||||||
|
step.RunTime = (int)stepStopwatch.ElapsedMilliseconds;
|
||||||
|
}
|
||||||
|
if (_globalVariables.SingleStep)
|
||||||
|
{
|
||||||
|
_globalVariables.IsStop = true;
|
||||||
|
_globalVariables.RunState = "运行";
|
||||||
|
_globalVariables.RunIcon = PackIconKind.Play;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return loopStack.Count == 0 && stepSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task ExecuteMethodStep(StepModel step, Dictionary<Guid, ParameterModel> parameters, int depth, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_globalVariables.SelectedStep = null;
|
||||||
|
await Task.Delay(SystemConfig.Instance.PerformanceLevel);
|
||||||
|
|
||||||
|
// 1. 查找类型
|
||||||
|
Type? targetType = null;
|
||||||
|
foreach (var assembly in _globalVariables.Assemblies)
|
||||||
|
{
|
||||||
|
targetType = assembly.GetType(step.Method!.FullName!);
|
||||||
|
if (targetType != null) break;
|
||||||
|
}
|
||||||
|
if (targetType == null)
|
||||||
|
{
|
||||||
|
LoggerHelper.ErrorWithNotify($"指令 [ {step.Index} ] 执行错误:未找到类型 {step.Method!.FullName}", depth);
|
||||||
|
step.Result = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 创建实例(仅当方法不是静态时才需要)
|
||||||
|
object? instance = null;
|
||||||
|
bool isMethod = false;
|
||||||
|
|
||||||
|
// 3. 准备参数
|
||||||
|
var inputParams = new List<object?>();
|
||||||
|
var paramTypes = new List<Type>();
|
||||||
|
ParameterModel? outputParam = null;
|
||||||
|
foreach (var param in step.Method!.Parameters)
|
||||||
|
{
|
||||||
|
if (param.Category == ParameterCategory.Input)
|
||||||
|
{
|
||||||
|
if (param.Type == typeof(CancellationToken))
|
||||||
|
{
|
||||||
|
inputParams.Add(stepCTS.Token);
|
||||||
|
paramTypes.Add(param.Type!);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var actualValue = param.GetActualValue(tmpParameters);
|
||||||
|
// 类型转换处理
|
||||||
|
if (actualValue != null)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(actualValue.ToString()))
|
||||||
|
{
|
||||||
|
actualValue = null;
|
||||||
|
}
|
||||||
|
if (actualValue != null && param.Type != null && actualValue.GetType() != param.Type)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (param.Type.IsArray)
|
||||||
|
{
|
||||||
|
// 获取数组元素类型
|
||||||
|
Type elementType = param.Type.GetElementType()!;
|
||||||
|
|
||||||
|
// 解析字符串为字符串数组
|
||||||
|
string[] stringArray = actualValue.ToString()!
|
||||||
|
.Trim('[', ']')
|
||||||
|
.Split(',', StringSplitOptions.RemoveEmptyEntries)
|
||||||
|
.Select(s => s.Trim())
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
// 创建目标类型数组
|
||||||
|
Array array = Array.CreateInstance(elementType, stringArray.Length);
|
||||||
|
|
||||||
|
// 转换每个元素
|
||||||
|
for (int i = 0; i < stringArray.Length; i++)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 特殊处理字符串类型
|
||||||
|
if (elementType == typeof(string))
|
||||||
|
{
|
||||||
|
array.SetValue(stringArray[i], i);
|
||||||
|
}
|
||||||
|
// 特殊处理枚举类型
|
||||||
|
else if (elementType.IsEnum)
|
||||||
|
{
|
||||||
|
array.SetValue(Enum.Parse(elementType, stringArray[i]), i);
|
||||||
|
}
|
||||||
|
// 常规类型转换
|
||||||
|
else
|
||||||
|
{
|
||||||
|
array.SetValue(Convert.ChangeType(stringArray[i], elementType), i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
throw new InvalidCastException($"指令 [ {step.Index} ] 执行错误:元素 '{stringArray[i]}' 无法转换为 {elementType.Name}[]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
actualValue = array;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (param.Type.BaseType == typeof(Enum))
|
||||||
|
{
|
||||||
|
actualValue = Enum.Parse(param.Type, param.Value!.ToString()!);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
actualValue = Convert.ChangeType(actualValue, param.Type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LoggerHelper.WarnWithNotify($"指令 [ {step.Index} ] 执行错误:参数 {param.Name} 类型转换失败: {ex.Message}", depth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inputParams.Add(actualValue);
|
||||||
|
paramTypes.Add(param.Type!);
|
||||||
|
}
|
||||||
|
else if (param.Category == ParameterCategory.Output)
|
||||||
|
{
|
||||||
|
outputParam = param;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 获取方法
|
||||||
|
var method = targetType!.GetMethod(
|
||||||
|
step.Method.Name!,
|
||||||
|
BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance,
|
||||||
|
null,
|
||||||
|
paramTypes.ToArray(),
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
|
if (method == null)
|
||||||
|
{
|
||||||
|
LoggerHelper.ErrorWithNotify($"指令 [ {step.Index} ] 执行错误:未找到方法{step.Method.Name}", depth);
|
||||||
|
step.Result = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否是静态方法
|
||||||
|
bool isStaticMethod = method!.IsStatic;
|
||||||
|
|
||||||
|
// 如果是实例方法,需要创建实例
|
||||||
|
if (!isMethod)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
instance = Activator.CreateInstance(targetType);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LoggerHelper.ErrorWithNotify($"指令 [ {step.Index} ] 执行错误:创建实例失败 - {ex.Message}", depth);
|
||||||
|
step.Result = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 执行方法
|
||||||
|
|
||||||
|
object? returnValue = method.Invoke(instance, inputParams.ToArray());
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 处理异步方法
|
||||||
|
if (returnValue is Task task)
|
||||||
|
{
|
||||||
|
await task.ConfigureAwait(false);
|
||||||
|
// 获取结果(如果是Task<T>)
|
||||||
|
if (task.GetType().IsGenericType)
|
||||||
|
{
|
||||||
|
var returnValueProperty = task.GetType().GetProperty("Result");
|
||||||
|
returnValue = returnValueProperty?.GetValue(task);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
returnValue = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理VoidTaskreturnValue类型
|
||||||
|
if (returnValue != null && returnValue.GetType().FullName == "System.Threading.Tasks.VoidTaskreturnValue")
|
||||||
|
{
|
||||||
|
returnValue = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LoggerHelper.ErrorWithNotify($"指令 [ {step.Index} ] 执行错误: {ex.InnerException?.Message ?? ex.Message}", depth);
|
||||||
|
step.Result = 2;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. 处理输出
|
||||||
|
bool paraResult = true; //记录参数上下限是否NG
|
||||||
|
if (outputParam != null)
|
||||||
|
{
|
||||||
|
outputParam.Value = returnValue;
|
||||||
|
var currentPara = outputParam.GetCurrentParameter(tmpParameters);
|
||||||
|
if (currentPara != null)
|
||||||
|
{
|
||||||
|
currentPara.Value = returnValue;
|
||||||
|
var tmp = currentPara.GetResult();
|
||||||
|
currentPara.Result = tmp.Item1;
|
||||||
|
paraResult = tmp.Item1;
|
||||||
|
if (tmp.Item2 != null)
|
||||||
|
{
|
||||||
|
LoggerHelper.WarnWithNotify(tmp.Item2);
|
||||||
|
}
|
||||||
|
if (currentPara.IsSave && _globalVariables.Program.Parameters.FirstOrDefault(x => x.ID == currentPara.ID) != null)
|
||||||
|
{
|
||||||
|
_ = SaveDataToDatabase(_globalVariables.Program.ID, currentPara);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var returnType = returnValue?.GetType();
|
||||||
|
if (returnType != null)
|
||||||
|
{
|
||||||
|
if (!returnType.IsArray)
|
||||||
|
{
|
||||||
|
LoggerHelper.SuccessWithNotify($"输出 [ {outputParam.Name} ] = {returnValue} ({returnType.Name})", depth);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (returnValue is IEnumerable enumerable)
|
||||||
|
{
|
||||||
|
var elements = enumerable.Cast<object>().Select(item => item?.ToString() ?? "null");
|
||||||
|
LoggerHelper.SuccessWithNotify($"输出 [ {outputParam.Name} ] = [ {string.Join(", ", elements)} ] ({returnType.Name})", depth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LoggerHelper.SuccessWithNotify($"指令 [ {step.Index} ] 执行成功", depth);
|
||||||
|
UpdateCurrentStepResult(step, paraResult: paraResult, depth: depth);
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LoggerHelper.ErrorWithNotify($"指令 [ {step.Index} ] 执行错误: {ex.InnerException?.Message ?? ex.Message}", depth);
|
||||||
|
step.Result = 2;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResetAllStepStatus(ProgramModel program)
|
||||||
|
{
|
||||||
|
foreach (var step in program.StepCollection)
|
||||||
|
{
|
||||||
|
step.Result = -1;
|
||||||
|
step.RunTime = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateCurrentStepResult(StepModel step, bool paraResult = true, bool stepResult = true, int depth = 0)
|
||||||
|
{
|
||||||
|
if (stepResult && paraResult)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(step.OKExpression))
|
||||||
|
{
|
||||||
|
step.Result = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Dictionary<string, object> paraDic = [];
|
||||||
|
foreach (var item in tmpParameters)
|
||||||
|
{
|
||||||
|
paraDic.TryAdd(item.Value.Name, item.Value.Value!);
|
||||||
|
}
|
||||||
|
if (step.SubProgram != null)
|
||||||
|
{
|
||||||
|
foreach (var item in step.SubProgram.Parameters.Where(x => x.Category == ParameterCategory.Output))
|
||||||
|
{
|
||||||
|
paraDic.TryAdd(item.Name, item.Value!);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (step.Method != null)
|
||||||
|
{
|
||||||
|
foreach (var item in step.Method.Parameters.Where(x => x.Category == ParameterCategory.Output))
|
||||||
|
{
|
||||||
|
paraDic.TryAdd(item.Name, item.Value!);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool re = ExpressionEvaluator.EvaluateExpression(step.OKExpression, paraDic);
|
||||||
|
step.Result = re ? 1 : 2;
|
||||||
|
if (step.Result == 2)
|
||||||
|
{
|
||||||
|
LoggerHelper.WarnWithNotify($"指令 [ {step.Index} ] NG:条件表达式验证失败", depth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!paraResult)
|
||||||
|
{
|
||||||
|
LoggerHelper.WarnWithNotify("参数限值校验失败", depth);
|
||||||
|
}
|
||||||
|
step.Result = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SaveDataToDatabase(Guid programID, ParameterModel currentPara)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#region 私有类
|
||||||
|
|
||||||
|
private class LoopContext
|
||||||
|
{
|
||||||
|
public int LoopCount { get; set; }
|
||||||
|
public int CurrentLoop { get; set; }
|
||||||
|
public int StartIndex { get; set; }
|
||||||
|
public StepModel? LoopStartStep { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -37,18 +37,30 @@ namespace BOB.ViewModels
|
|||||||
set => SetProperty(ref _instructionTree, value);
|
set => SetProperty(ref _instructionTree, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ProgramModel _program;
|
|
||||||
public ProgramModel Program
|
public ProgramModel Program
|
||||||
{
|
{
|
||||||
get => _program;
|
get => _globalVariables.Program;
|
||||||
set => SetProperty(ref _program, value);
|
set
|
||||||
|
{
|
||||||
|
if (_globalVariables.Program != value)
|
||||||
|
{
|
||||||
|
_globalVariables.Program = value;
|
||||||
|
RaisePropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ObservableCollection<Assembly> _assemblies = new();
|
|
||||||
public ObservableCollection<Assembly> Assemblies
|
public ObservableCollection<Assembly> Assemblies
|
||||||
{
|
{
|
||||||
get => _assemblies;
|
get => _globalVariables.Assemblies;
|
||||||
set => SetProperty(ref _assemblies, value);
|
set
|
||||||
|
{
|
||||||
|
if (_globalVariables.Assemblies != value)
|
||||||
|
{
|
||||||
|
_globalVariables.Assemblies = value;
|
||||||
|
RaisePropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ObservableCollection<SubProgramItem> _subPrograms = new();
|
private ObservableCollection<SubProgramItem> _subPrograms = new();
|
||||||
@ -71,7 +83,7 @@ namespace BOB.ViewModels
|
|||||||
get => _xmlDocumentCache;
|
get => _xmlDocumentCache;
|
||||||
set => SetProperty(ref _xmlDocumentCache, value);
|
set => SetProperty(ref _xmlDocumentCache, value);
|
||||||
}
|
}
|
||||||
GlobalVariables GlobalVariables { get; set; }
|
GlobalVariables _globalVariables { get; set; }
|
||||||
#endregion
|
#endregion
|
||||||
public ICommand LoadedCommand { get; set; }
|
public ICommand LoadedCommand { get; set; }
|
||||||
public ICommand SearchEnterCommand { get; set; }
|
public ICommand SearchEnterCommand { get; set; }
|
||||||
@ -79,8 +91,7 @@ namespace BOB.ViewModels
|
|||||||
public ICommand ReloadCommand { get; set; }
|
public ICommand ReloadCommand { get; set; }
|
||||||
public CommandTreeViewModel(GlobalVariables _GlobalVariables)
|
public CommandTreeViewModel(GlobalVariables _GlobalVariables)
|
||||||
{
|
{
|
||||||
GlobalVariables= _GlobalVariables;
|
_globalVariables= _GlobalVariables;
|
||||||
Program = GlobalVariables.Program;
|
|
||||||
LoadedCommand = new DelegateCommand(Loaded);
|
LoadedCommand = new DelegateCommand(Loaded);
|
||||||
SearchEnterCommand = new DelegateCommand(Search);
|
SearchEnterCommand = new DelegateCommand(Search);
|
||||||
TreeDoubleClickCommand = new DelegateCommand<object>(TreeDoubleClick);
|
TreeDoubleClickCommand = new DelegateCommand<object>(TreeDoubleClick);
|
||||||
@ -101,7 +112,7 @@ namespace BOB.ViewModels
|
|||||||
{
|
{
|
||||||
if(Node.Children.Count == 0)
|
if(Node.Children.Count == 0)
|
||||||
{
|
{
|
||||||
int index = GlobalVariables.SelectedStep?.Index >= 0 ? GlobalVariables.SelectedStep.Index : -1;
|
int index = _globalVariables.SelectedStep?.Index >= 0 ? _globalVariables.SelectedStep.Index : -1;
|
||||||
if (Node.Tag is MethodInfo method)
|
if (Node.Tag is MethodInfo method)
|
||||||
{
|
{
|
||||||
AddMethodToProgram(method, index);
|
AddMethodToProgram(method, index);
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
using Logger;
|
using Logger;
|
||||||
using Prism.Mvvm;
|
using Prism.Mvvm;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Windows;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Threading;
|
||||||
|
|
||||||
namespace BOB.ViewModels
|
namespace BOB.ViewModels
|
||||||
{
|
{
|
||||||
@ -24,7 +26,8 @@ namespace BOB.ViewModels
|
|||||||
public void OnLogAdded(string message, string color)
|
public void OnLogAdded(string message, string color)
|
||||||
{
|
{
|
||||||
var brush = (Brush)new BrushConverter().ConvertFromString(color);
|
var brush = (Brush)new BrushConverter().ConvertFromString(color);
|
||||||
Logs.Add(new LogItem { Message = message, Color = brush });
|
Application.Current.Dispatcher.Invoke(() => Logs.Add(new LogItem { Message = message, Color = brush }));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -16,11 +16,17 @@ namespace BOB.ViewModels
|
|||||||
public class ParametersManagerViewModel:BindableBase
|
public class ParametersManagerViewModel:BindableBase
|
||||||
{
|
{
|
||||||
#region 属性
|
#region 属性
|
||||||
private ProgramModel _program;
|
|
||||||
public ProgramModel Program
|
public ProgramModel Program
|
||||||
{
|
{
|
||||||
get => _program;
|
get => _globalVariables.Program;
|
||||||
set => SetProperty(ref _program, value);
|
set
|
||||||
|
{
|
||||||
|
if (_globalVariables.Program != value)
|
||||||
|
{
|
||||||
|
_globalVariables.Program = value;
|
||||||
|
RaisePropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
private ParameterModel _SelectedParameter;
|
private ParameterModel _SelectedParameter;
|
||||||
public ParameterModel SelectedParameter
|
public ParameterModel SelectedParameter
|
||||||
|
|||||||
@ -29,6 +29,45 @@ namespace BOB.ViewModels
|
|||||||
set => SetProperty(ref _IsLeftDrawerOpen, value);
|
set => SetProperty(ref _IsLeftDrawerOpen, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String RunState
|
||||||
|
{
|
||||||
|
get => _globalVariables.RunState;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_globalVariables.RunState != value)
|
||||||
|
{
|
||||||
|
_globalVariables.RunState = value;
|
||||||
|
RaisePropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SingleStep
|
||||||
|
{
|
||||||
|
get => _globalVariables.SingleStep;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_globalVariables.SingleStep != value)
|
||||||
|
{
|
||||||
|
_globalVariables.SingleStep = value;
|
||||||
|
RaisePropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public PackIconKind RunIcon
|
||||||
|
{
|
||||||
|
get => _globalVariables.RunIcon;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_globalVariables.RunIcon != value)
|
||||||
|
{
|
||||||
|
_globalVariables.RunIcon = value;
|
||||||
|
RaisePropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
#region 命令
|
#region 命令
|
||||||
public ICommand LeftDrawerOpenCommand { get; set; }
|
public ICommand LeftDrawerOpenCommand { get; set; }
|
||||||
@ -44,14 +83,18 @@ namespace BOB.ViewModels
|
|||||||
public ICommand OpenCommand { get; set; }
|
public ICommand OpenCommand { get; set; }
|
||||||
public ICommand NewCommand { get; set; }
|
public ICommand NewCommand { get; set; }
|
||||||
public ICommand SetDefaultCommand { get; set; }
|
public ICommand SetDefaultCommand { get; set; }
|
||||||
|
public ICommand LoadCommand { get; set; }
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
private IEventAggregator _eventAggregator;
|
private IEventAggregator _eventAggregator;
|
||||||
private GlobalVariables _globalVariables;
|
private GlobalVariables _globalVariables;
|
||||||
public ShellViewModel(IEventAggregator eventAggregator, IContainerProvider containerProvider,GlobalVariables globalVariables)
|
private StepRunning _stepRunning;
|
||||||
|
private Task? currentExecutionTask;
|
||||||
|
public ShellViewModel(IEventAggregator eventAggregator, IContainerProvider containerProvider,GlobalVariables globalVariables, StepRunning stepRunning)
|
||||||
{
|
{
|
||||||
_eventAggregator= eventAggregator;
|
_eventAggregator = eventAggregator;
|
||||||
_globalVariables= globalVariables;
|
_globalVariables = globalVariables;
|
||||||
|
_stepRunning=stepRunning;
|
||||||
LeftDrawerOpenCommand = new DelegateCommand(LeftDrawerOpen);
|
LeftDrawerOpenCommand = new DelegateCommand(LeftDrawerOpen);
|
||||||
MinimizeCommand = new DelegateCommand<Window>(MinimizeWindow);
|
MinimizeCommand = new DelegateCommand<Window>(MinimizeWindow);
|
||||||
MaximizeCommand = new DelegateCommand<Window>(MaximizeWindow);
|
MaximizeCommand = new DelegateCommand<Window>(MaximizeWindow);
|
||||||
@ -61,28 +104,45 @@ namespace BOB.ViewModels
|
|||||||
ResotrationCommand = new DelegateCommand(Resotration);
|
ResotrationCommand = new DelegateCommand(Resotration);
|
||||||
StopCommand = new DelegateCommand(Stop);
|
StopCommand = new DelegateCommand(Stop);
|
||||||
NewCommand = new DelegateCommand(New);
|
NewCommand = new DelegateCommand(New);
|
||||||
OpenCommand = new DelegateCommand(Open);
|
OpenCommand = new DelegateCommand<string>(Open);
|
||||||
SaveAsCommand = new DelegateCommand(SaveAs);
|
SaveAsCommand = new DelegateCommand(SaveAs);
|
||||||
SaveCommand = new DelegateCommand(Save);
|
SaveCommand = new DelegateCommand(Save);
|
||||||
SetDefaultCommand = new DelegateCommand(SetDefault);
|
SetDefaultCommand = new DelegateCommand(SetDefault);
|
||||||
|
LoadCommand = new DelegateCommand(Load);
|
||||||
}
|
}
|
||||||
#region ToolBar命令
|
#region ToolBar命令
|
||||||
|
private void Load()
|
||||||
|
{
|
||||||
|
if (SystemConfig.Instance.DefaultSubProgramFilePath != null)
|
||||||
|
{
|
||||||
|
if (File.Exists(SystemConfig.Instance.DefaultSubProgramFilePath))
|
||||||
|
{
|
||||||
|
Open(SystemConfig.Instance.DefaultSubProgramFilePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
private void SetDefault()
|
private void SetDefault()
|
||||||
{
|
{
|
||||||
if(_globalVariables.CurrentFilePath!=null)
|
if(_globalVariables.CurrentFilePath!=null)
|
||||||
{
|
{
|
||||||
SystemConfig.Instance.DefaultSubProgramFilePath = _globalVariables.CurrentFilePath;
|
SystemConfig.Instance.DefaultSubProgramFilePath = _globalVariables.CurrentFilePath;
|
||||||
|
SystemConfig.Instance.SaveToFile();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private void New()
|
private void New()
|
||||||
{
|
{
|
||||||
_globalVariables.CurrentFilePath = null;
|
_globalVariables.CurrentFilePath = null;
|
||||||
_globalVariables.Program = new();
|
_globalVariables.Program.Parameters.Clear();
|
||||||
|
_globalVariables.Program.Devices.Clear();
|
||||||
|
_globalVariables.Program.StepCollection.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Open()
|
private void Open(string filePath = null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
{
|
||||||
|
// 如果没有传路径,弹出文件选择对话框
|
||||||
|
if (string.IsNullOrEmpty(filePath))
|
||||||
{
|
{
|
||||||
var openFileDialog = new OpenFileDialog
|
var openFileDialog = new OpenFileDialog
|
||||||
{
|
{
|
||||||
@ -91,36 +151,42 @@ namespace BOB.ViewModels
|
|||||||
InitialDirectory = @"D:\BOB\子程序"
|
InitialDirectory = @"D:\BOB\子程序"
|
||||||
};
|
};
|
||||||
|
|
||||||
if (openFileDialog.ShowDialog() == true)
|
if (openFileDialog.ShowDialog() != true)
|
||||||
{
|
return; // 用户取消选择
|
||||||
string filePath = openFileDialog.FileName;
|
|
||||||
|
|
||||||
// 读取 JSON 文件内容
|
filePath = openFileDialog.FileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确认文件存在
|
||||||
|
if (!File.Exists(filePath))
|
||||||
|
{
|
||||||
|
LoggerHelper.ErrorWithNotify($"文件不存在: {filePath}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取 JSON 文件
|
||||||
string json = File.ReadAllText(filePath);
|
string json = File.ReadAllText(filePath);
|
||||||
|
|
||||||
// 反序列化为 ProgramModel
|
// 反序列化为 ProgramModel
|
||||||
var program = JsonConvert.DeserializeObject<ProgramModel>(json);
|
var program = JsonConvert.DeserializeObject<ProgramModel>(json);
|
||||||
|
|
||||||
if (program != null)
|
if (program == null)
|
||||||
{
|
{
|
||||||
_globalVariables.Program = program;
|
LoggerHelper.WarnWithNotify($"文件格式不正确或为空: {filePath}");
|
||||||
_globalVariables.CurrentFilePath = filePath;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_globalVariables.Program.Parameters = program.Parameters;
|
||||||
|
_globalVariables.Program.Devices = program.Devices;
|
||||||
|
_globalVariables.Program.StepCollection = program.StepCollection;
|
||||||
|
_globalVariables.CurrentFilePath = filePath;
|
||||||
LoggerHelper.SuccessWithNotify($"成功打开文件: {filePath}");
|
LoggerHelper.SuccessWithNotify($"成功打开文件: {filePath}");
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
LoggerHelper.WarnWithNotify($"文件内容格式不正确: {filePath}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
LoggerHelper.ErrorWithNotify($"打开文件失败: {ex.Message}");
|
LoggerHelper.ErrorWithNotify($"打开文件失败: {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void SaveAs()
|
private void SaveAs()
|
||||||
{
|
{
|
||||||
string defaultPath = @"D:\BOB\子程序";
|
string defaultPath = @"D:\BOB\子程序";
|
||||||
@ -197,14 +263,60 @@ namespace BOB.ViewModels
|
|||||||
LoggerHelper.InfoWithNotify(_globalVariables.UserName + "执行复位命令");
|
LoggerHelper.InfoWithNotify(_globalVariables.UserName + "执行复位命令");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RunSingle()
|
private async void RunSingle()
|
||||||
{
|
{
|
||||||
|
if (RunState == "运行")
|
||||||
|
{
|
||||||
|
SingleStep = true;
|
||||||
LoggerHelper.InfoWithNotify(_globalVariables.UserName + "执行单步执行命令");
|
LoggerHelper.InfoWithNotify(_globalVariables.UserName + "执行单步执行命令");
|
||||||
|
RunState = "暂停";
|
||||||
|
RunIcon = PackIconKind.Pause;
|
||||||
|
if (_globalVariables.IsStop == null)
|
||||||
|
{
|
||||||
|
_globalVariables.IsStop = false;
|
||||||
|
currentExecutionTask = _stepRunning.ExecuteSteps(_globalVariables.Program, cancellationToken: _stepRunning.stepCTS.Token);
|
||||||
|
await currentExecutionTask;
|
||||||
|
RunState = "运行";
|
||||||
|
RunIcon = PackIconKind.Play;
|
||||||
|
_globalVariables.IsStop = null;
|
||||||
|
}
|
||||||
|
else if (_globalVariables.IsStop == true)
|
||||||
|
{
|
||||||
|
_globalVariables.IsStop = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Running()
|
private async void Running()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
if (RunState == "运行")
|
||||||
|
{
|
||||||
|
SingleStep = false;
|
||||||
LoggerHelper.InfoWithNotify(_globalVariables.UserName + "执行运行命令");
|
LoggerHelper.InfoWithNotify(_globalVariables.UserName + "执行运行命令");
|
||||||
|
RunState = "暂停";
|
||||||
|
RunIcon = PackIconKind.Pause;
|
||||||
|
if (_globalVariables.IsStop == null)
|
||||||
|
{
|
||||||
|
_globalVariables.IsStop = false;
|
||||||
|
currentExecutionTask = _stepRunning.ExecuteSteps(_globalVariables.Program, cancellationToken: _stepRunning.stepCTS.Token);
|
||||||
|
await currentExecutionTask;
|
||||||
|
RunState = "运行";
|
||||||
|
RunIcon = PackIconKind.Play;
|
||||||
|
_globalVariables.IsStop = null;
|
||||||
|
}
|
||||||
|
else if (_globalVariables.IsStop == true)
|
||||||
|
{
|
||||||
|
_globalVariables.IsStop = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LoggerHelper.InfoWithNotify(_globalVariables.UserName + "点击暂停命令");
|
||||||
|
_globalVariables.IsStop = true;
|
||||||
|
RunState = "运行";
|
||||||
|
RunIcon = PackIconKind.Play;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LeftDrawerOpen()
|
private void LeftDrawerOpen()
|
||||||
|
|||||||
@ -12,17 +12,29 @@ namespace BOB.ViewModels
|
|||||||
public class SingleStepEditViewModel:BindableBase
|
public class SingleStepEditViewModel:BindableBase
|
||||||
{
|
{
|
||||||
#region 属性
|
#region 属性
|
||||||
|
private Guid _ID;
|
||||||
|
public Guid ID
|
||||||
|
{
|
||||||
|
get => _ID;
|
||||||
|
set => SetProperty(ref _ID, value);
|
||||||
|
}
|
||||||
private StepModel _SelectedStep;
|
private StepModel _SelectedStep;
|
||||||
public StepModel SelectedStep
|
public StepModel SelectedStep
|
||||||
{
|
{
|
||||||
get => _SelectedStep;
|
get => _SelectedStep;
|
||||||
set => SetProperty(ref _SelectedStep, value);
|
set => SetProperty(ref _SelectedStep, value);
|
||||||
}
|
}
|
||||||
private ProgramModel _Program;
|
|
||||||
public ProgramModel Program
|
public ProgramModel Program
|
||||||
{
|
{
|
||||||
get => _Program;
|
get => _globalVariables.Program;
|
||||||
set => SetProperty(ref _Program, value);
|
set
|
||||||
|
{
|
||||||
|
if (_globalVariables.Program != value)
|
||||||
|
{
|
||||||
|
_globalVariables.Program = value;
|
||||||
|
RaisePropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
private GlobalVariables _globalVariables;
|
private GlobalVariables _globalVariables;
|
||||||
@ -37,7 +49,6 @@ namespace BOB.ViewModels
|
|||||||
CancelEditCommand = new DelegateCommand(CancelEdit);
|
CancelEditCommand = new DelegateCommand(CancelEdit);
|
||||||
SaveStepCommand = new DelegateCommand(SaveStep);
|
SaveStepCommand = new DelegateCommand(SaveStep);
|
||||||
_eventAggregator.GetEvent<DeletedStepEvent>().Subscribe(DisposeSelectedStep);
|
_eventAggregator.GetEvent<DeletedStepEvent>().Subscribe(DisposeSelectedStep);
|
||||||
Program = _globalVariables.Program;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DisposeSelectedStep(Guid id)
|
private void DisposeSelectedStep(Guid id)
|
||||||
@ -58,11 +69,18 @@ namespace BOB.ViewModels
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
var steps = _globalVariables.Program.StepCollection;
|
||||||
|
int index = steps.ToList().FindIndex(x => x.ID == ID);
|
||||||
|
if (index >= 0)
|
||||||
|
{
|
||||||
|
steps[index] = SelectedStep;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EditSingleSetp()
|
private void EditSingleSetp()
|
||||||
{
|
{
|
||||||
|
ID = _globalVariables.SelectedStep.ID;
|
||||||
SelectedStep = new StepModel(_globalVariables.SelectedStep);
|
SelectedStep = new StepModel(_globalVariables.SelectedStep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,11 +34,17 @@ namespace BOB.ViewModels
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private ProgramModel _Program;
|
|
||||||
public ProgramModel Program
|
public ProgramModel Program
|
||||||
{
|
{
|
||||||
get => _Program;
|
get => _globalVariables.Program;
|
||||||
set => SetProperty(ref _Program, value);
|
set
|
||||||
|
{
|
||||||
|
if (_globalVariables.Program != value)
|
||||||
|
{
|
||||||
|
_globalVariables.Program = value;
|
||||||
|
RaisePropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
private bool _IsAdmin;
|
private bool _IsAdmin;
|
||||||
public bool IsAdmin
|
public bool IsAdmin
|
||||||
@ -60,7 +66,6 @@ namespace BOB.ViewModels
|
|||||||
_eventAggregator = eventAggregator;
|
_eventAggregator = eventAggregator;
|
||||||
_globalVariables = _GlobalVariables;
|
_globalVariables = _GlobalVariables;
|
||||||
IsAdmin = _globalVariables.IsAdmin;
|
IsAdmin = _globalVariables.IsAdmin;
|
||||||
Program = _globalVariables.Program;
|
|
||||||
EditStepCommand = new DelegateCommand(EditStep);
|
EditStepCommand = new DelegateCommand(EditStep);
|
||||||
CopyStepCommand = new DelegateCommand(CopyStep);
|
CopyStepCommand = new DelegateCommand(CopyStep);
|
||||||
PasteStepCommand = new DelegateCommand(PasteStep);
|
PasteStepCommand = new DelegateCommand(PasteStep);
|
||||||
|
|||||||
@ -18,6 +18,12 @@
|
|||||||
<WindowChrome GlassFrameThickness="-1" />
|
<WindowChrome GlassFrameThickness="-1" />
|
||||||
</WindowChrome.WindowChrome>
|
</WindowChrome.WindowChrome>
|
||||||
|
|
||||||
|
<i:Interaction.Triggers>
|
||||||
|
<i:EventTrigger EventName="Loaded">
|
||||||
|
<i:InvokeCommandAction Command="{Binding LoadCommand}" />
|
||||||
|
</i:EventTrigger>
|
||||||
|
</i:Interaction.Triggers>
|
||||||
|
|
||||||
<materialDesign:DrawerHost x:Name="MainDrawerHost"
|
<materialDesign:DrawerHost x:Name="MainDrawerHost"
|
||||||
IsLeftDrawerOpen="{Binding IsLeftDrawerOpen, Mode=TwoWay}">
|
IsLeftDrawerOpen="{Binding IsLeftDrawerOpen, Mode=TwoWay}">
|
||||||
|
|
||||||
@ -143,7 +149,7 @@
|
|||||||
Command="{Binding RunningCommand}"
|
Command="{Binding RunningCommand}"
|
||||||
Foreground="White">
|
Foreground="White">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<materialDesign:PackIcon Kind="Play"
|
<materialDesign:PackIcon Kind="{Binding RunIcon}"
|
||||||
Foreground="White" />
|
Foreground="White" />
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
|||||||
@ -21,6 +21,7 @@
|
|||||||
<converters:EnumValueConverter x:Key="EnumValueConverter" />
|
<converters:EnumValueConverter x:Key="EnumValueConverter" />
|
||||||
<converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
|
<converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
|
||||||
<converters:FilteredParametersConverter x:Key="FilteredParametersConverter" />
|
<converters:FilteredParametersConverter x:Key="FilteredParametersConverter" />
|
||||||
|
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
<Grid>
|
<Grid>
|
||||||
<GroupBox Header="单步编辑">
|
<GroupBox Header="单步编辑">
|
||||||
@ -66,7 +67,8 @@
|
|||||||
Content="跳转"
|
Content="跳转"
|
||||||
ToolTip="格式:OK跳转序号/NG跳转序号(默认为0/0)" />
|
ToolTip="格式:OK跳转序号/NG跳转序号(默认为0/0)" />
|
||||||
<TextBox MinWidth="120"
|
<TextBox MinWidth="120"
|
||||||
materialDesign:HintAssist.Hint="" />
|
Text="{Binding SelectedStep.GotoSettingString}"
|
||||||
|
materialDesign:HintAssist.Hint="格式:OK跳转序号/NG跳转序号(默认为0/0)" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<!-- 备注 -->
|
<!-- 备注 -->
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="ncalc" Version="1.3.8" />
|
||||||
<PackageReference Include="Prism.Unity" Version="9.0.537" />
|
<PackageReference Include="Prism.Unity" Version="9.0.537" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
104
Common/Tool/ExpressionEvaluator.cs
Normal file
104
Common/Tool/ExpressionEvaluator.cs
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using NCalc;
|
||||||
|
|
||||||
|
namespace Common.Tools
|
||||||
|
{
|
||||||
|
public class ExpressionEvaluator
|
||||||
|
{
|
||||||
|
public static bool EvaluateExpression(string expression, Dictionary<string, object>? variables = null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 预处理:替换中文变量名为英文别名
|
||||||
|
var (processedExpression, processedVariables) = PreprocessExpression(expression, variables);
|
||||||
|
|
||||||
|
var expr = new Expression(processedExpression, EvaluateOptions.IgnoreCase);
|
||||||
|
|
||||||
|
if (processedVariables != null)
|
||||||
|
{
|
||||||
|
foreach (var kvp in processedVariables)
|
||||||
|
{
|
||||||
|
expr.Parameters[kvp.Key] = kvp.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expr.HasErrors())
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"条件表达式格式错误: {expr.Error}");
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = expr.Evaluate();
|
||||||
|
return Convert.ToBoolean(result);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"条件表达式异常: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static (string, Dictionary<string, object>) PreprocessExpression(
|
||||||
|
string expression,
|
||||||
|
Dictionary<string, object>? variables)
|
||||||
|
{
|
||||||
|
if (variables == null || variables.Count == 0)
|
||||||
|
return (expression, variables ?? new Dictionary<string, object>());
|
||||||
|
|
||||||
|
// 生成变量名映射 (中文 -> 英文别名)
|
||||||
|
var chineseToAlias = new Dictionary<string, string>();
|
||||||
|
var aliasToValue = new Dictionary<string, object>();
|
||||||
|
int counter = 1;
|
||||||
|
|
||||||
|
foreach (var key in variables.Keys)
|
||||||
|
{
|
||||||
|
if (ContainsChinese(key))
|
||||||
|
{
|
||||||
|
string alias = $"var_{counter}";
|
||||||
|
counter++;
|
||||||
|
chineseToAlias[key] = alias;
|
||||||
|
aliasToValue[alias] = variables[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果没有中文变量名,直接返回原始数据
|
||||||
|
if (chineseToAlias.Count == 0)
|
||||||
|
return (expression, variables);
|
||||||
|
|
||||||
|
// 替换表达式中的中文变量名
|
||||||
|
string processedExpression = expression;
|
||||||
|
foreach (var pair in chineseToAlias)
|
||||||
|
{
|
||||||
|
// 使用正则确保完整匹配变量名
|
||||||
|
string pattern = $@"\b{Regex.Escape(pair.Key)}\b";
|
||||||
|
processedExpression = Regex.Replace(
|
||||||
|
processedExpression,
|
||||||
|
pattern,
|
||||||
|
pair.Value,
|
||||||
|
RegexOptions.Compiled
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建新变量字典(英文别名 + 原始英文变量)
|
||||||
|
var newVariables = new Dictionary<string, object>(aliasToValue);
|
||||||
|
foreach (var key in variables.Keys)
|
||||||
|
{
|
||||||
|
if (!ContainsChinese(key))
|
||||||
|
{
|
||||||
|
newVariables[key] = variables[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (processedExpression, newVariables);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查字符串是否包含中文字符
|
||||||
|
private static bool ContainsChinese(string text)
|
||||||
|
{
|
||||||
|
return text.Any(c => c >= 0x4E00 && c <= 0x9FFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -14,6 +14,7 @@ namespace Logger
|
|||||||
public static readonly ILogger Logger = LogManager.GetLogger("InfoLogger");
|
public static readonly ILogger Logger = LogManager.GetLogger("InfoLogger");
|
||||||
public static readonly ILogger sqlLogger = LogManager.GetLogger("SqlLogger");
|
public static readonly ILogger sqlLogger = LogManager.GetLogger("SqlLogger");
|
||||||
// 日志事件,UI可以订阅
|
// 日志事件,UI可以订阅
|
||||||
|
|
||||||
public static event Action<string, string>? LogAdded;
|
public static event Action<string, string>? LogAdded;
|
||||||
|
|
||||||
public static void InfoWithNotify(string message)
|
public static void InfoWithNotify(string message)
|
||||||
@ -50,7 +51,32 @@ namespace Logger
|
|||||||
Logger.Error(message);
|
Logger.Error(message);
|
||||||
NotifyUI(message, "red");
|
NotifyUI(message, "red");
|
||||||
}
|
}
|
||||||
|
public static void InfoWithNotify(string message,int depth)
|
||||||
|
{
|
||||||
|
Logger.Info(message); // 写入 NLog
|
||||||
|
NotifyUI(message, "lightblue"); // 触发UI显示
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SuccessWithNotify(string message, int depth )
|
||||||
|
{
|
||||||
|
Logger.Info(message);
|
||||||
|
NotifyUI(message, "lightgreen");
|
||||||
|
}
|
||||||
|
public static void WarnWithNotify(string message, int depth )
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
Logger.Warn(message);
|
||||||
|
NotifyUI(message, "orange");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ErrorWithNotify(string message, int depth )
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
Logger.Error(message);
|
||||||
|
NotifyUI(message, "red");
|
||||||
|
}
|
||||||
private static void NotifyUI(string message, string color)
|
private static void NotifyUI(string message, string color)
|
||||||
{
|
{
|
||||||
LogAdded?.Invoke(message,color);
|
LogAdded?.Invoke(message,color);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user