添加项目文件。
This commit is contained in:
85
UIShare/GlobalVariable/ConfigService.cs
Normal file
85
UIShare/GlobalVariable/ConfigService.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Newtonsoft.Json;
|
||||
using Logger;
|
||||
|
||||
namespace UIShare.GlobalVariable
|
||||
{
|
||||
public static class ConfigService
|
||||
{
|
||||
private static readonly object _fileLock = new();
|
||||
|
||||
/// <summary>
|
||||
/// 根据标题(格子标识)加载独立的配置文件
|
||||
/// </summary>
|
||||
public static SystemConfig Load(string title)
|
||||
{
|
||||
if (string.IsNullOrEmpty(title))
|
||||
{
|
||||
throw new ArgumentException("配置标题不能为空", nameof(title));
|
||||
}
|
||||
|
||||
// 临时实例化一个对象以获取默认的 SystemPath
|
||||
var dummy = new SystemConfig();
|
||||
string configPath = Path.Combine(dummy.SystemPath, $"{title}.json");
|
||||
|
||||
if (!File.Exists(configPath))
|
||||
{
|
||||
// 如果不存在,创建一个带 Title 的默认配置并保存
|
||||
var defaultConfig = new SystemConfig { Title = title };
|
||||
Save(defaultConfig);
|
||||
return defaultConfig;
|
||||
}
|
||||
|
||||
lock (_fileLock)
|
||||
{
|
||||
try
|
||||
{
|
||||
string json = File.ReadAllText(configPath);
|
||||
var config = JsonConvert.DeserializeObject<SystemConfig>(json, new JsonSerializerSettings
|
||||
{
|
||||
TypeNameHandling = TypeNameHandling.All
|
||||
});
|
||||
|
||||
return config ?? new SystemConfig { Title = title };
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify($"格子 [{title}] 配置加载失败: {ex.Message}");
|
||||
return new SystemConfig { Title = title };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存指定的配置实例
|
||||
/// </summary>
|
||||
public static void Save(SystemConfig config)
|
||||
{
|
||||
if (config == null || string.IsNullOrEmpty(config.Title)) return;
|
||||
|
||||
lock (_fileLock)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!Directory.Exists(config.SystemPath))
|
||||
Directory.CreateDirectory(config.SystemPath);
|
||||
|
||||
string configPath = Path.Combine(config.SystemPath, $"{config.Title}.json");
|
||||
|
||||
string json = JsonConvert.SerializeObject(config, Formatting.Indented, new JsonSerializerSettings
|
||||
{
|
||||
TypeNameHandling = TypeNameHandling.All
|
||||
});
|
||||
|
||||
File.WriteAllText(configPath, json);
|
||||
LoggerHelper.InfoWithNotify($"配置 [{config.Title}] 已保存。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify($"配置 [{config.Title}] 保存失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
37
UIShare/GlobalVariable/GlobalInfo.cs
Normal file
37
UIShare/GlobalVariable/GlobalInfo.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace UIShare.GlobalVariable
|
||||
{
|
||||
public class GlobalInfo:BindableBase
|
||||
{
|
||||
public event EventHandler? ScopeChanged;
|
||||
public Dictionary<string,ScopedContext> ContextDic { get; set; }
|
||||
public Dictionary<string,StepRunning> StepRunningDic { get; set; }
|
||||
public String UserName { get; set; } = "Not Logged in";
|
||||
public bool IsAdmin { get; set; } = true;
|
||||
private string _currentScope = "default";
|
||||
public string CurrentScope
|
||||
{
|
||||
get => _currentScope;
|
||||
set
|
||||
{
|
||||
if (_currentScope != value)
|
||||
{
|
||||
_currentScope = value;
|
||||
ScopeChanged?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
public GlobalInfo()
|
||||
{
|
||||
ContextDic = new();
|
||||
StepRunningDic = new();
|
||||
CurrentScope = "default";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
42
UIShare/GlobalVariable/ScopedContext.cs
Normal file
42
UIShare/GlobalVariable/ScopedContext.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using MaterialDesignThemes.Wpf;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UIShare.UIViewModel;
|
||||
|
||||
namespace UIShare.GlobalVariable
|
||||
{
|
||||
public class ScopedContext
|
||||
{
|
||||
private static readonly Random _randomSeed = new Random();
|
||||
public ProgramModel Program { get; set; } = new();
|
||||
public String SelectedStepList { get; set; } = "主程序";
|
||||
public string CurrentFilePath { get; set; }
|
||||
public bool? IsStop { get; set; }
|
||||
public bool SingleStep { get; set; }
|
||||
public string RunState { get; set; } = "运行";
|
||||
public TimeSpan RunningTime { get; set; } = TimeSpan.Zero;
|
||||
public Stopwatch SW { get; set; } = new();
|
||||
public bool IsTerminate { get; set; } = false;
|
||||
public ObservableCollection<Assembly> Assemblies { get; set; } = new();
|
||||
public PackIconKind RunIcon { get; set; } = PackIconKind.Play;
|
||||
public StepModel SelectedStep { get; set; }
|
||||
public ParameterModel SelectedParameter { get; set; }
|
||||
// 【新增测试属性】:每个实例被 new 出来时独一无二的随机身份
|
||||
// 证 ID
|
||||
public int DebugRandomId { get; private set; }
|
||||
public ScopedContext()
|
||||
{
|
||||
lock (_randomSeed)
|
||||
{
|
||||
// 每次诞生一个新上下文,就在 10000 到 99999 之间随机摇一个数
|
||||
DebugRandomId = _randomSeed.Next(10000, 100000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
730
UIShare/GlobalVariable/StepRunning.cs
Normal file
730
UIShare/GlobalVariable/StepRunning.cs
Normal file
@@ -0,0 +1,730 @@
|
||||
using UIShare.UIViewModel;
|
||||
using UIShare.PubEvent;
|
||||
using Common.Tools;
|
||||
using Logger;
|
||||
using MaterialDesignThemes.Wpf;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UIShare.GlobalVariable;
|
||||
using static UIShare.UIViewModel.ParameterModel;
|
||||
|
||||
|
||||
namespace UIShare
|
||||
{
|
||||
public class StepRunning
|
||||
{
|
||||
private ScopedContext _scopedContext;
|
||||
private SystemConfig _systemConfig;
|
||||
//private Devices _devices;
|
||||
private IContainerProvider containerProvider;
|
||||
private IEventAggregator _eventAggregator;
|
||||
|
||||
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();
|
||||
public CancellationTokenSource errorStepCTS = new();
|
||||
private bool SubSingleStep = false;
|
||||
|
||||
private Guid TestRoundID;
|
||||
public StepRunning(ScopedContext ScopedContext, SystemConfig systemConfig,IEventAggregator eventAggregator,IContainerProvider containerProvider)
|
||||
{
|
||||
_scopedContext = ScopedContext;
|
||||
_systemConfig = systemConfig;
|
||||
_eventAggregator = eventAggregator;
|
||||
//_devices = containerProvider.Resolve<Devices>();
|
||||
}
|
||||
public async Task<bool> ExecuteErrorSteps(ProgramModel program, int depth = 0, CancellationToken cancellationToken = default)
|
||||
{
|
||||
int index = 0;
|
||||
bool stepSuccess = false;
|
||||
if (depth == 0)
|
||||
{
|
||||
loopStack.Clear();
|
||||
loopStopwatchStack.Clear();
|
||||
ResetAllStepStatus(program.ErrorStepCollection);
|
||||
tmpParameters.Clear();
|
||||
TestRoundID = Guid.NewGuid();
|
||||
}
|
||||
foreach (var item in program.Parameters)
|
||||
{
|
||||
tmpParameters.TryAdd(item.ID, item);
|
||||
}
|
||||
|
||||
while (index < program.ErrorStepCollection.Count)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
break;
|
||||
}
|
||||
var step = program.ErrorStepCollection[index];
|
||||
if (!step.IsUsed)
|
||||
{
|
||||
index++;
|
||||
continue;
|
||||
}
|
||||
|
||||
step.Result = 0;
|
||||
if (step.StepType == "循环开始")
|
||||
{
|
||||
var endStep = program.ErrorStepCollection.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: 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.ErrorStepCollection.First(x => x.ID == step.LoopStartStepId).Result = 1;
|
||||
loopStopwatchStack.Pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理普通步骤
|
||||
else
|
||||
{
|
||||
if (depth == 0)
|
||||
{
|
||||
stepStopwatch.Restart();
|
||||
}
|
||||
|
||||
if (step.SubProgram != null)
|
||||
{
|
||||
if (_scopedContext.SingleStep)//子程序的单步执行将执行完保存下的所有Method
|
||||
{
|
||||
SubSingleStep = true;
|
||||
_scopedContext.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;
|
||||
_scopedContext.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.ErrorStepCollection.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.ErrorStepCollection.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return loopStack.Count == 0 && stepSuccess;
|
||||
}
|
||||
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.StepCollection);
|
||||
tmpParameters.Clear();
|
||||
TestRoundID = Guid.NewGuid();
|
||||
}
|
||||
foreach (var item in program.Parameters)
|
||||
{
|
||||
tmpParameters.TryAdd(item.ID, item);
|
||||
}
|
||||
|
||||
while (index < program.StepCollection.Count)
|
||||
{
|
||||
while (_scopedContext.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($"循环开始({step.Name}),共{context.LoopCount}次", depth);
|
||||
index++;
|
||||
}
|
||||
|
||||
// 处理循环结束
|
||||
else if (step.StepType == "循环结束")
|
||||
{
|
||||
if (loopStack.Count == 0)
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify("未匹配的循环结束指令", depth: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 (_scopedContext.SingleStep)//子程序的单步执行将执行完保存下的所有Method
|
||||
{
|
||||
SubSingleStep = true;
|
||||
_scopedContext.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;
|
||||
_scopedContext.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 (_scopedContext.SingleStep)
|
||||
{
|
||||
_scopedContext.IsStop = true;
|
||||
_scopedContext.RunState = "运行";
|
||||
_scopedContext.SingleStep = false;
|
||||
_eventAggregator.GetEvent<RunSingalCompletedEvent>().Publish("Play");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return loopStack.Count == 0 && stepSuccess;
|
||||
}
|
||||
|
||||
public async Task ExecuteMethodStep(StepModel step, Dictionary<Guid, ParameterModel> parameters, int depth, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(_scopedContext.Program.StepCollection.Count>1)
|
||||
_scopedContext.SelectedStep = null;
|
||||
await Task.Delay(_systemConfig.PerformanceLevel);
|
||||
|
||||
|
||||
// 1. 查找类型
|
||||
Type? targetType = null;
|
||||
foreach (var assembly in _scopedContext.Assemblies)
|
||||
{
|
||||
targetType = assembly.GetType(step.Method!.FullName!);
|
||||
if (targetType != null) break;
|
||||
}
|
||||
if (targetType == null)
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify($"指令 [ {step.Index} ] 执行错误:未找到类型 {step.Method!.FullName}", depth: 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
|
||||
{
|
||||
if (stringArray[i] is string s && s.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// 先转成整数
|
||||
var intValue = Convert.ToInt64(s, 16);
|
||||
|
||||
// 再转成目标类型
|
||||
array.SetValue(Convert.ChangeType(intValue, elementType), 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
|
||||
{
|
||||
if (actualValue is string s && s.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// 先转成整数
|
||||
var intValue = Convert.ToInt64(s, 16);
|
||||
|
||||
// 再转成目标类型
|
||||
actualValue = Convert.ChangeType(intValue, param.Type);
|
||||
}
|
||||
else
|
||||
{
|
||||
actualValue = Convert.ChangeType(actualValue, param.Type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.WarnWithNotify($"指令 [ {step.Index} ] 执行错误:参数 {param.Name} 类型转换失败: {ex.Message}", depth: 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: depth);
|
||||
step.Result = 2;
|
||||
}
|
||||
|
||||
// 检查是否是静态方法
|
||||
bool isStaticMethod = method!.IsStatic;
|
||||
|
||||
// 如果是实例方法,需要创建实例
|
||||
if (!isStaticMethod)
|
||||
{
|
||||
try
|
||||
{
|
||||
//instance = _devices.DeviceDic[targetType.Name];
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.ErrorWithNotify($"指令 [ {step.Index} ] 执行错误:创建实例失败 - {ex.Message}", depth: 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: 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 && _scopedContext.Program.Parameters.FirstOrDefault(x => x.ID == currentPara.ID) != null)
|
||||
//{
|
||||
// _ = SaveDataToDatabase(_scopedContext.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: depth);
|
||||
step.Result = 2;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public void ResetAllStepStatus(ObservableCollection<StepModel> StepCollection)
|
||||
{
|
||||
foreach (var step in 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: depth);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!paraResult)
|
||||
{
|
||||
LoggerHelper.WarnWithNotify("参数限值校验失败", depth: depth);
|
||||
}
|
||||
step.Result = 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#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
|
||||
|
||||
}
|
||||
}
|
||||
41
UIShare/GlobalVariable/SystemConfig.cs
Normal file
41
UIShare/GlobalVariable/SystemConfig.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using Logger;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UIShare.UIViewModel;
|
||||
|
||||
namespace UIShare.GlobalVariable
|
||||
{
|
||||
public class SystemConfig
|
||||
{
|
||||
[JsonIgnore]
|
||||
public string SystemPath { get; set; } = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "UIShare");
|
||||
public string Title { get; set; } = string.Empty;
|
||||
public int PerformanceLevel { get; set; } = 50;
|
||||
public string DLLFilePath { get; set; } = @"D:\ADP\指令\";
|
||||
public string SubProgramFilePath { get; set; } = @"D:\ADP\子程序\";
|
||||
public string DefaultProgramFilePath { get; set; } = "";
|
||||
public string DefaultBLFFilePath { get; set; } = "";
|
||||
public string DefaultDBCFilePath { get; set; } = "";
|
||||
public string TSMasterName { get; set; } = "ADP测试上位机";
|
||||
|
||||
/// <summary>
|
||||
/// 设备列表:每个工位独立一份(SystemConfig 已注册为 Scoped)。
|
||||
/// 当前阶段预置几条模拟设备,便于设置界面直接展示左侧列表。
|
||||
/// </summary>
|
||||
public ObservableCollection<DeviceInfoModel> DeviceList { get; set; } = new()
|
||||
{
|
||||
new DeviceInfoModel { DeviceName = "DAQ_001", DeviceType = "数据采集卡", Remark = "8 通道电压采集", IsEnabled = true, IsConnected = false },
|
||||
new DeviceInfoModel { DeviceName = "PSU_002", DeviceType = "可编程电源", Remark = "0-30V / 0-5A", IsEnabled = true, IsConnected = false },
|
||||
new DeviceInfoModel { DeviceName = "CAN_003", DeviceType = "CAN 通讯卡", Remark = "双通道 CAN-FD", IsEnabled = false, IsConnected = false },
|
||||
new DeviceInfoModel { DeviceName = "IO_004", DeviceType = "数字 I/O", Remark = "16 进 16 出", IsEnabled = true, IsConnected = false },
|
||||
new DeviceInfoModel { DeviceName = "Serial_005", DeviceType = "串口", Remark = "RS232 / RS485", IsEnabled = true, IsConnected = false },
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user