mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-03 00:00:49 +08:00
准备添加流程接口调用
This commit is contained in:
375
NodeFlow/Env/FlowControl.cs
Normal file
375
NodeFlow/Env/FlowControl.cs
Normal file
@@ -0,0 +1,375 @@
|
||||
using Serein.Library;
|
||||
using Serein.Library.Api;
|
||||
using Serein.Library.Utils;
|
||||
using Serein.NodeFlow.Model;
|
||||
using Serein.NodeFlow.Services;
|
||||
using Serein.NodeFlow.Tool;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser;
|
||||
|
||||
namespace Serein.NodeFlow.Env
|
||||
{
|
||||
|
||||
internal class FlowControl : IFlowControl
|
||||
{
|
||||
private readonly IFlowEnvironment flowEnvironment;
|
||||
private readonly IFlowEnvironmentEvent flowEnvironmentEvent;
|
||||
private readonly FlowLibraryService flowLibraryService;
|
||||
private readonly FlowOperationService flowOperationService;
|
||||
private readonly FlowModelService flowModelService;
|
||||
private readonly UIContextOperation UIContextOperation;
|
||||
|
||||
public FlowControl(IFlowEnvironment flowEnvironment,
|
||||
IFlowEnvironmentEvent flowEnvironmentEvent,
|
||||
FlowLibraryService flowLibraryService,
|
||||
FlowOperationService flowOperationService,
|
||||
FlowModelService flowModelService,
|
||||
UIContextOperation UIContextOperation)
|
||||
{
|
||||
this.flowEnvironment = flowEnvironment;
|
||||
this.flowEnvironmentEvent = flowEnvironmentEvent;
|
||||
this.flowLibraryService = flowLibraryService;
|
||||
this.flowOperationService = flowOperationService;
|
||||
this.flowModelService = flowModelService;
|
||||
this.UIContextOperation = UIContextOperation;
|
||||
contexts = new ObjectPool<IDynamicContext>(() => new DynamicContext(flowEnvironment));
|
||||
}
|
||||
|
||||
private ObjectPool<IDynamicContext> contexts;
|
||||
private FlowWorkManagement flowWorkManagement;
|
||||
private ISereinIOC sereinIOC;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 如果全局触发器还在运行,则为 Running 。
|
||||
/// </summary>
|
||||
private RunState FlipFlopState = RunState.NoStart;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 异步运行
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> StartFlowAsync(string[] canvasGuids)
|
||||
{
|
||||
#region 校验参数
|
||||
HashSet<string> guids = new HashSet<string>();
|
||||
bool isBreak = false;
|
||||
foreach (var canvasGuid in canvasGuids)
|
||||
{
|
||||
if (guids.Contains(canvasGuid))
|
||||
{
|
||||
flowEnvironment.WriteLine(InfoType.WARN, $"画布重复,停止运行。{canvasGuid}");
|
||||
isBreak = true;
|
||||
}
|
||||
else if (!flowModelService.ContainsCanvasModel(canvasGuid))
|
||||
{
|
||||
SereinEnv.WriteLine(InfoType.WARN, $"画布不存在,停止运行。{canvasGuid}");
|
||||
isBreak = true;
|
||||
}
|
||||
else if (!flowModelService.IsExsitNodeOnCanvas(canvasGuid))
|
||||
{
|
||||
SereinEnv.WriteLine(InfoType.WARN, $"画布没有节点,停止运行。{canvasGuid}");
|
||||
isBreak = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
guids.Add(canvasGuid);
|
||||
}
|
||||
}
|
||||
if (isBreak)
|
||||
{
|
||||
guids.Clear();
|
||||
return false;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region 初始化每个画布的数据,转换为流程任务
|
||||
Dictionary<string, FlowTask> flowTasks = [];
|
||||
foreach (var guid in guids)
|
||||
{
|
||||
if (!flowModelService.TryGetCanvasModel(guid, out var canvasModel))
|
||||
{
|
||||
SereinEnv.WriteLine(InfoType.WARN, $"画布不存在,停止运行。{guid}");
|
||||
return false;
|
||||
}
|
||||
var ft = new FlowTask();
|
||||
ft.GetNodes = () => flowModelService.GetAllNodeModel(guid);
|
||||
if (canvasModel.StartNode?.Guid is null)
|
||||
{
|
||||
SereinEnv.WriteLine(InfoType.WARN, $"画布不存在起始节点,将停止运行。{guid}");
|
||||
return false;
|
||||
}
|
||||
ft.GetStartNode = () => canvasModel.StartNode;
|
||||
flowTasks.Add(guid, ft);
|
||||
}
|
||||
#endregion
|
||||
|
||||
sereinIOC.Reset();
|
||||
sereinIOC.Register<IFlowEnvironment>(() => flowEnvironment);
|
||||
sereinIOC.Register<IScriptFlowApi, ScriptFlowApi>(); // 注册脚本接口
|
||||
|
||||
var flowTaskOptions = new FlowWorkOptions
|
||||
{
|
||||
Environment = flowEnvironment, // 流程
|
||||
Flows = flowTasks,
|
||||
FlowContextPool = contexts, // 上下文对象池
|
||||
AutoRegisterTypes = flowLibraryService.GetaAutoRegisterType(), // 需要自动实例化的类型
|
||||
InitMds = flowLibraryService.GetMdsOnFlowStart(NodeType.Init),
|
||||
LoadMds = flowLibraryService.GetMdsOnFlowStart(NodeType.Loading),
|
||||
ExitMds = flowLibraryService.GetMdsOnFlowStart(NodeType.Exit),
|
||||
};
|
||||
|
||||
|
||||
|
||||
flowWorkManagement = new FlowWorkManagement(flowTaskOptions);
|
||||
var cts = new CancellationTokenSource();
|
||||
try
|
||||
{
|
||||
var t = await flowWorkManagement.RunAsync(cts.Token);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
SereinEnv.WriteLine(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
SereinEnv.WriteLine(InfoType.INFO, $"流程运行完毕{Environment.NewLine}"); ;
|
||||
}
|
||||
flowTaskOptions = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 从选定节点开始运行
|
||||
/// </summary>
|
||||
/// <param name="startNodeGuid"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> StartFlowFromSelectNodeAsync(string startNodeGuid)
|
||||
{
|
||||
|
||||
var flowTaskOptions = new FlowWorkOptions
|
||||
{
|
||||
Environment = flowEnvironment, // 流程
|
||||
FlowContextPool = contexts, // 上下文对象池
|
||||
};
|
||||
var flowTaskManagement = new FlowWorkManagement(flowTaskOptions);
|
||||
|
||||
if (true || flowEnvironment.FlowState == RunState.Running || FlipFlopState == RunState.Running)
|
||||
{
|
||||
|
||||
if (!flowModelService.TryGetNodeModel(startNodeGuid, out var nodeModel) || nodeModel is SingleFlipflopNode)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
await flowTaskManagement.StartFlowInSelectNodeAsync(nodeModel);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*/// <summary>
|
||||
/// 单独运行一个节点
|
||||
/// </summary>
|
||||
/// <param name="nodeGuid"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<object> InvokeNodeAsync(IDynamicContext context, string nodeGuid)
|
||||
{
|
||||
object result = Unit.Default;
|
||||
if (this.NodeModels.TryGetValue(nodeGuid, out var model))
|
||||
{
|
||||
CancellationTokenSource cts = new CancellationTokenSource();
|
||||
result = await model.ExecutingAsync(context, cts.Token);
|
||||
cts?.Cancel();
|
||||
}
|
||||
return result;
|
||||
}*/
|
||||
|
||||
/// <summary>
|
||||
/// 结束流程
|
||||
/// </summary>
|
||||
public Task<bool> ExitFlowAsync()
|
||||
{
|
||||
flowWorkManagement?.Exit();
|
||||
UIContextOperation?.Invoke(() => flowEnvironmentEvent.OnFlowRunComplete(new FlowEventArgs()));
|
||||
sereinIOC.Reset();
|
||||
flowWorkManagement = null;
|
||||
GC.Collect();
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 激活全局触发器
|
||||
/// </summary>
|
||||
/// <param name="nodeGuid"></param>
|
||||
public void ActivateFlipflopNode(string nodeGuid)
|
||||
{
|
||||
/*if (!TryGetNodeModel(nodeGuid, out var nodeModel))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (nodeModel is null) return;
|
||||
if (flowTaskManagement is not null && nodeModel is SingleFlipflopNode flipflopNode) // 子节点为触发器
|
||||
{
|
||||
if (FlowState != RunState.Completion
|
||||
&& flipflopNode.NotExitPreviousNode()) // 正在运行,且该触发器没有上游节点
|
||||
{
|
||||
_ = flowTaskManagement.RunGlobalFlipflopAsync(this, flipflopNode);// 被父节点移除连接关系的子节点若为触发器,且无上级节点,则当前流程正在运行,则加载到运行环境中
|
||||
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 关闭全局触发器
|
||||
/// </summary>
|
||||
/// <param name="nodeGuid"></param>
|
||||
public void TerminateFlipflopNode(string nodeGuid)
|
||||
{
|
||||
/* if (!TryGetNodeModel(nodeGuid, out var nodeModel))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (nodeModel is null) return;
|
||||
if (flowTaskManagement is not null && nodeModel is SingleFlipflopNode flipflopNode) // 子节点为触发器
|
||||
{
|
||||
flowTaskManagement.TerminateGlobalFlipflopRuning(flipflopNode);
|
||||
}*/
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public void UseExternalIOC(ISereinIOC ioc)
|
||||
{
|
||||
this.sereinIOC = ioc; // 设置IOC容器
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启动器调用,运行到某个节点时触发了监视对象的更新(对象预览视图将会自动更新)
|
||||
/// </summary>
|
||||
/// <param name="nodeGuid"></param>
|
||||
/// <param name="monitorData"></param>
|
||||
/// <param name="sourceType"></param>
|
||||
public void MonitorObjectNotification(string nodeGuid, object monitorData, MonitorObjectEventArgs.ObjSourceType sourceType)
|
||||
{
|
||||
flowEnvironmentEvent.OnMonitorObjectChanged(new MonitorObjectEventArgs(nodeGuid, monitorData, sourceType));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启动器调用,节点触发了中断。
|
||||
/// </summary>
|
||||
/// <param name="nodeGuid">节点</param>
|
||||
/// <param name="expression">表达式</param>
|
||||
/// <param name="type">类型,0用户主动的中断,1表达式中断</param>
|
||||
public void TriggerInterrupt(string nodeGuid, string expression, InterruptTriggerEventArgs.InterruptTriggerType type)
|
||||
{
|
||||
flowEnvironmentEvent.OnInterruptTriggered(new InterruptTriggerEventArgs(nodeGuid, expression, type));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#region 流程接口调用
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 调用流程接口,将返回 FlowResult.Value。如果需要 FlowResult 对象,请使用该方法的泛型版本。
|
||||
/// </summary>
|
||||
/// <param name="apiGuid">流程接口节点Guid</param>
|
||||
/// <param name="param">调用时入参参数</param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
public async Task<object> ApiInvokeAsync(string apiGuid, object[] param)
|
||||
{
|
||||
if (sereinIOC is null)
|
||||
{
|
||||
sereinIOC = flowEnvironment.IOC;
|
||||
}
|
||||
if (!flowModelService.TryGetNodeModel(apiGuid, out var nodeModel))
|
||||
{
|
||||
throw new ArgumentNullException($"不存在流程接口:{apiGuid}");
|
||||
}
|
||||
if (nodeModel is not SingleFlowCallNode flowCallNode)
|
||||
{
|
||||
throw new ArgumentNullException($"目标节点并非流程接口:{apiGuid}");
|
||||
}
|
||||
var context = contexts.Allocate();
|
||||
CancellationTokenSource cts = new CancellationTokenSource();
|
||||
var flowResult = await flowCallNode.StartFlowAsync(context, cts.Token);
|
||||
return flowResult.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 调用流程接口,泛型类型为 FlowResult 时,将返回 FlowResult 对象。
|
||||
/// </summary>
|
||||
/// <typeparam name="TResult"></typeparam>
|
||||
/// <param name="apiGuid">流程接口节点Guid</param>
|
||||
/// <param name="param">调用时入参参数</param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
public async Task<TResult> ApiInvokeAsync<TResult>(string apiGuid, object[] param)
|
||||
{
|
||||
if (sereinIOC is null)
|
||||
{
|
||||
sereinIOC = flowEnvironment.IOC;
|
||||
}
|
||||
if (!flowModelService.TryGetNodeModel(apiGuid, out var nodeModel))
|
||||
{
|
||||
throw new ArgumentNullException($"不存在流程接口:{apiGuid}");
|
||||
}
|
||||
if (nodeModel is not SingleFlowCallNode flowCallNode)
|
||||
{
|
||||
throw new ArgumentNullException($"目标节点并非流程接口:{apiGuid}");
|
||||
}
|
||||
var context = contexts.Allocate();
|
||||
CancellationTokenSource cts = new CancellationTokenSource();
|
||||
var flowResult = await flowCallNode.StartFlowAsync(context, cts.Token);
|
||||
|
||||
if (flowResult.Value is TResult result)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else if (flowResult is FlowResult && flowResult is TResult result2)
|
||||
{
|
||||
return result2;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentNullException($"类型转换失败,流程返回数据与泛型不匹配,当前返回类型为[{flowResult.Value.GetType().FullName}]。");
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsHasSuccessorNodes(IFlowNode nodeModel)
|
||||
{
|
||||
var nextTypes = new[]
|
||||
{
|
||||
ConnectionInvokeType.Upstream,
|
||||
ConnectionInvokeType.IsSucceed,
|
||||
ConnectionInvokeType.IsFail,
|
||||
ConnectionInvokeType.IsError
|
||||
};
|
||||
foreach (var type in nextTypes)
|
||||
{
|
||||
if (nodeModel.SuccessorNodes.TryGetValue(type, out var nextNodes))
|
||||
{
|
||||
if(nextNodes.Count > 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
568
NodeFlow/Env/FlowEdit.cs
Normal file
568
NodeFlow/Env/FlowEdit.cs
Normal file
@@ -0,0 +1,568 @@
|
||||
using Serein.Library;
|
||||
using Serein.Library.Api;
|
||||
using Serein.Library.Utils;
|
||||
using Serein.NodeFlow.Model;
|
||||
using Serein.NodeFlow.Model.Operation;
|
||||
using Serein.NodeFlow.Services;
|
||||
using Serein.NodeFlow.Tool;
|
||||
using static Serein.Library.Api.IFlowEnvironment;
|
||||
|
||||
namespace Serein.NodeFlow.Env
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 流程编辑接口实现
|
||||
/// </summary>
|
||||
internal class FlowEdit : IFlowEdit
|
||||
{
|
||||
public FlowEdit(IFlowEnvironment flowEnvironment,
|
||||
IFlowEnvironmentEvent flowEnvironmentEvent,
|
||||
FlowLibraryService flowLibraryManagement,
|
||||
FlowOperationService flowOperationService,
|
||||
FlowModelService flowModelService,
|
||||
UIContextOperation UIContextOperation,
|
||||
ISereinIOC sereinIOC,
|
||||
NodeMVVMService nodeMVVMService)
|
||||
{
|
||||
this.flowEnvironment = flowEnvironment;
|
||||
this.flowEnvironmentEvent = flowEnvironmentEvent;
|
||||
this.flowLibraryManagement = flowLibraryManagement;
|
||||
this.flowOperationService = flowOperationService;
|
||||
this.flowModelService = flowModelService;
|
||||
this.UIContextOperation = UIContextOperation;
|
||||
NodeMVVMManagement = nodeMVVMService;
|
||||
InitNodeMVVM(nodeMVVMService);
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public NodeMVVMService NodeMVVMManagement { get; }
|
||||
|
||||
private readonly IFlowEnvironment flowEnvironment;
|
||||
private readonly IFlowEnvironmentEvent flowEnvironmentEvent;
|
||||
private readonly FlowLibraryService flowLibraryManagement;
|
||||
private readonly FlowOperationService flowOperationService;
|
||||
private readonly FlowModelService flowModelService;
|
||||
private readonly NodeMVVMService nodeMVVMService;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 注册基本节点类型
|
||||
/// </summary>
|
||||
private void InitNodeMVVM(NodeMVVMService nodeMVVMService)
|
||||
{
|
||||
nodeMVVMService.RegisterModel(NodeControlType.UI, typeof(SingleUINode)); // 动作节点
|
||||
nodeMVVMService.RegisterModel(NodeControlType.Action, typeof(SingleActionNode)); // 动作节点
|
||||
nodeMVVMService.RegisterModel(NodeControlType.Flipflop, typeof(SingleFlipflopNode)); // 触发器节点
|
||||
nodeMVVMService.RegisterModel(NodeControlType.ExpOp, typeof(SingleExpOpNode)); // 表达式节点
|
||||
nodeMVVMService.RegisterModel(NodeControlType.ExpCondition, typeof(SingleConditionNode)); // 条件表达式节点
|
||||
nodeMVVMService.RegisterModel(NodeControlType.GlobalData, typeof(SingleGlobalDataNode)); // 全局数据节点
|
||||
nodeMVVMService.RegisterModel(NodeControlType.Script, typeof(SingleScriptNode)); // 脚本节点
|
||||
nodeMVVMService.RegisterModel(NodeControlType.NetScript, typeof(SingleNetScriptNode)); // 脚本节点
|
||||
nodeMVVMService.RegisterModel(NodeControlType.FlowCall, typeof(SingleFlowCallNode)); // 流程调用节点
|
||||
}
|
||||
|
||||
|
||||
private UIContextOperation UIContextOperation;
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 从Guid获取画布
|
||||
/// </summary>
|
||||
/// <param name="nodeGuid">节点Guid</param>
|
||||
/// <returns>节点Model</returns>
|
||||
/// <exception cref="ArgumentNullException">无法获取节点、Guid/节点为null时报错</exception>
|
||||
public bool TryGetCanvasModel(string nodeGuid, out FlowCanvasDetails canvasDetails)
|
||||
{
|
||||
if (string.IsNullOrEmpty(nodeGuid))
|
||||
{
|
||||
canvasDetails = null;
|
||||
return false;
|
||||
}
|
||||
return flowModelService.TryGetCanvasModel(nodeGuid, out canvasDetails);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从Guid获取节点
|
||||
/// </summary>
|
||||
/// <param name="nodeGuid">节点Guid</param>
|
||||
/// <returns>节点Model</returns>
|
||||
/// <exception cref="ArgumentNullException">无法获取节点、Guid/节点为null时报错</exception>
|
||||
public bool TryGetNodeModel(string nodeGuid, out IFlowNode nodeModel)
|
||||
{
|
||||
if (string.IsNullOrEmpty(nodeGuid))
|
||||
{
|
||||
nodeModel = null;
|
||||
return false;
|
||||
}
|
||||
return flowModelService.TryGetNodeModel(nodeGuid, out nodeModel);
|
||||
|
||||
}
|
||||
|
||||
#region 私有方法
|
||||
|
||||
/// <summary>
|
||||
/// 从节点信息创建节点,并返回状态指示是否创建成功
|
||||
/// </summary>
|
||||
/// <param name="nodeInfo"></param>
|
||||
/// <returns></returns>
|
||||
private bool CreateNodeFromNodeInfo(NodeInfo nodeInfo)
|
||||
{
|
||||
if (!EnumHelper.TryConvertEnum<NodeControlType>(nodeInfo.Type, out var controlType))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#region 获取方法描述
|
||||
MethodDetails? methodDetails;
|
||||
if (controlType == NodeControlType.FlowCall)
|
||||
{
|
||||
if (string.IsNullOrEmpty(nodeInfo.MethodName))
|
||||
{
|
||||
methodDetails = new MethodDetails();
|
||||
methodDetails.ParamsArgIndex = 0;
|
||||
methodDetails.ParameterDetailss = new ParameterDetails[nodeInfo.ParameterData.Length];
|
||||
for (int i = 0; i < methodDetails.ParameterDetailss.Length; i++)
|
||||
{
|
||||
var pdInfo = nodeInfo.ParameterData[i];
|
||||
var t = new ParameterDetailsInfo();
|
||||
var pd = new ParameterDetails(pdInfo, i);
|
||||
methodDetails.ParameterDetailss[i] = pd;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 目标节点可能是方法节点
|
||||
flowLibraryManagement.TryGetMethodDetails(nodeInfo.AssemblyName, nodeInfo.MethodName, out methodDetails); // 加载项目时尝试获取方法信息
|
||||
}
|
||||
}
|
||||
else if (controlType.IsBaseNode())
|
||||
{
|
||||
// 加载基础节点
|
||||
methodDetails = new MethodDetails();
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (string.IsNullOrEmpty(nodeInfo.MethodName)) return false;
|
||||
// 加载方法节点
|
||||
flowLibraryManagement.TryGetMethodDetails(nodeInfo.AssemblyName, nodeInfo.MethodName, out methodDetails); // 加载项目时尝试获取方法信息
|
||||
}
|
||||
#endregion
|
||||
|
||||
var nodeModel = FlowNodeExtension.CreateNode(flowEnvironment, controlType, methodDetails); // 加载项目时创建节点
|
||||
if (nodeModel is null)
|
||||
{
|
||||
nodeInfo.Guid = string.Empty;
|
||||
return false;
|
||||
}
|
||||
if (TryGetCanvasModel(nodeInfo.CanvasGuid, out var canvasModel))
|
||||
{
|
||||
|
||||
// 节点与画布互相绑定
|
||||
// 需要在UI线程上进行添加,否则会报 “不支持从调度程序线程以外的线程对其 SourceCollection 进行的更改”异常
|
||||
nodeModel.CanvasDetails = canvasModel;
|
||||
UIContextOperation?.Invoke(() => canvasModel.Nodes.Add(nodeModel));
|
||||
|
||||
nodeModel.LoadInfo(nodeInfo); // 创建节点model
|
||||
TryAddNode(nodeModel); // 加载项目时将节点加载到环境中
|
||||
}
|
||||
else
|
||||
{
|
||||
SereinEnv.WriteLine(InfoType.ERROR, $"加载节点[{nodeInfo.Guid}]时发生异常,画布[{nodeInfo.CanvasGuid}]不存在");
|
||||
return false;
|
||||
}
|
||||
|
||||
UIContextOperation?.Invoke(() =>
|
||||
flowEnvironmentEvent.OnNodeCreated(new NodeCreateEventArgs(nodeInfo.CanvasGuid, nodeModel, nodeInfo.Position))); // 添加到UI上
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 创建节点
|
||||
/// </summary>
|
||||
/// <param name="nodeBase"></param>
|
||||
private bool TryAddNode(IFlowNode nodeModel)
|
||||
{
|
||||
nodeModel.Guid ??= Guid.NewGuid().ToString();
|
||||
flowModelService.AddNodeModel(nodeModel);
|
||||
|
||||
|
||||
// 如果是触发器,则需要添加到专属集合中
|
||||
/*if (nodeModel is SingleFlipflopNode flipflopNode)
|
||||
{
|
||||
var guid = flipflopNode.Guid;
|
||||
if (!FlipflopNodes.Exists(it => it.Guid.Equals(guid)))
|
||||
{
|
||||
FlipflopNodes.Add(flipflopNode);
|
||||
}
|
||||
}*/
|
||||
return true;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region 流程接口
|
||||
|
||||
private int _add_canvas_count = 1;
|
||||
|
||||
|
||||
|
||||
public void CreateCanvas(string canvasName, int width, int height)
|
||||
{
|
||||
IOperation operation = new CreateCanvasOperation
|
||||
{
|
||||
CanvasInfo = new FlowCanvasDetailsInfo
|
||||
{
|
||||
Name = $"Canvas {_add_canvas_count++}",
|
||||
Width = width,
|
||||
Height = height,
|
||||
Guid = Guid.NewGuid().ToString(),
|
||||
ScaleX = 1.0f,
|
||||
ScaleY = 1.0f,
|
||||
}
|
||||
};
|
||||
|
||||
flowOperationService.Execute(operation);
|
||||
}
|
||||
|
||||
public void RemoveCanvas(string canvasGuid)
|
||||
{
|
||||
IOperation operation = new RemoveCanvasOperation
|
||||
{
|
||||
CanvasGuid = canvasGuid
|
||||
};
|
||||
flowOperationService.Execute(operation);
|
||||
}
|
||||
|
||||
public void ConnectInvokeNode(string canvasGuid, string fromNodeGuid, string toNodeGuid, JunctionType fromNodeJunctionType, JunctionType toNodeJunctionType, ConnectionInvokeType invokeType)
|
||||
{
|
||||
IOperation operation = new ChangeNodeConnectionOperation
|
||||
{
|
||||
CanvasGuid = canvasGuid,
|
||||
FromNodeGuid = fromNodeGuid,
|
||||
ToNodeGuid = toNodeGuid,
|
||||
FromNodeJunctionType = fromNodeJunctionType,
|
||||
ToNodeJunctionType = toNodeJunctionType,
|
||||
ConnectionInvokeType = invokeType,
|
||||
ChangeType = NodeConnectChangeEventArgs.ConnectChangeType.Create,
|
||||
JunctionOfConnectionType = JunctionOfConnectionType.Invoke,
|
||||
};
|
||||
|
||||
flowOperationService.Execute(operation);
|
||||
}
|
||||
|
||||
public void ConnectArgSourceNode(string canvasGuid, string fromNodeGuid, string toNodeGuid, JunctionType fromNodeJunctionType, JunctionType toNodeJunctionType, ConnectionArgSourceType argSourceType, int argIndex)
|
||||
{
|
||||
IOperation operation = new ChangeNodeConnectionOperation
|
||||
{
|
||||
CanvasGuid = canvasGuid,
|
||||
FromNodeGuid = fromNodeGuid,
|
||||
ToNodeGuid = toNodeGuid,
|
||||
FromNodeJunctionType = fromNodeJunctionType,
|
||||
ToNodeJunctionType = toNodeJunctionType,
|
||||
ConnectionArgSourceType = argSourceType,
|
||||
ArgIndex = argIndex,
|
||||
ChangeType = NodeConnectChangeEventArgs.ConnectChangeType.Create,
|
||||
JunctionOfConnectionType = JunctionOfConnectionType.Arg,
|
||||
};
|
||||
flowOperationService.Execute(operation);
|
||||
}
|
||||
|
||||
public void RemoveInvokeConnect(string canvasGuid, string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType)
|
||||
{
|
||||
IOperation operation = new ChangeNodeConnectionOperation
|
||||
{
|
||||
CanvasGuid = canvasGuid,
|
||||
FromNodeGuid = fromNodeGuid,
|
||||
ToNodeGuid = toNodeGuid,
|
||||
ConnectionInvokeType = connectionType,
|
||||
ChangeType = NodeConnectChangeEventArgs.ConnectChangeType.Remove,
|
||||
};
|
||||
flowOperationService.Execute(operation);
|
||||
}
|
||||
|
||||
public void RemoveArgSourceConnect(string canvasGuid, string fromNodeGuid, string toNodeGuid, int argIndex)
|
||||
{
|
||||
IOperation operation = new ChangeNodeConnectionOperation
|
||||
{
|
||||
CanvasGuid = canvasGuid,
|
||||
FromNodeGuid = fromNodeGuid,
|
||||
ToNodeGuid = toNodeGuid,
|
||||
ArgIndex = argIndex,
|
||||
ChangeType = NodeConnectChangeEventArgs.ConnectChangeType.Remove
|
||||
};
|
||||
flowOperationService.Execute(operation);
|
||||
}
|
||||
|
||||
public void CreateNode(string canvasGuid, NodeControlType nodeType, PositionOfUI position, MethodDetailsInfo methodDetailsInfo = null)
|
||||
{
|
||||
IOperation operation = new CreateNodeOperation
|
||||
{
|
||||
CanvasGuid = canvasGuid,
|
||||
NodeControlType = nodeType,
|
||||
Position = position,
|
||||
MethodDetailsInfo = methodDetailsInfo
|
||||
};
|
||||
flowOperationService.Execute(operation);
|
||||
}
|
||||
|
||||
public void RemoveNode(string canvasGuid, string nodeGuid)
|
||||
{
|
||||
IOperation operation = new RemoveNodeOperation
|
||||
{
|
||||
CanvasGuid = canvasGuid,
|
||||
NodeGuid = nodeGuid
|
||||
};
|
||||
flowOperationService.Execute(operation);
|
||||
}
|
||||
|
||||
public void PlaceNodeToContainer(string canvasGuid, string nodeGuid, string containerNodeGuid)
|
||||
{
|
||||
IOperation operation = new ContainerPlaceNodeOperation
|
||||
{
|
||||
CanvasGuid = canvasGuid,
|
||||
NodeGuid = nodeGuid,
|
||||
ContainerNodeGuid = containerNodeGuid
|
||||
};
|
||||
flowOperationService.Execute(operation);
|
||||
}
|
||||
|
||||
public void TakeOutNodeToContainer(string canvasGuid, string nodeGuid)
|
||||
{
|
||||
IOperation operation = new ContainerTakeOutNodeOperation
|
||||
{
|
||||
CanvasGuid = canvasGuid,
|
||||
NodeGuid = nodeGuid,
|
||||
};
|
||||
flowOperationService.Execute(operation);
|
||||
}
|
||||
|
||||
public void SetStartNode(string canvasGuid, string nodeGuid)
|
||||
{
|
||||
if (!TryGetCanvasModel(canvasGuid, out var canvasModel) || !TryGetNodeModel(nodeGuid, out var newStartNodeModel))
|
||||
{
|
||||
return;
|
||||
}
|
||||
var oldNodeGuid = canvasModel.StartNode?.Guid;
|
||||
/*if(TryGetNodeModel(oldNodeGuid, out var newStartNodeModel))
|
||||
{
|
||||
newStartNode.IsStart = false;
|
||||
}*/
|
||||
canvasModel.StartNode = newStartNodeModel;
|
||||
//newStartNode.IsStart = true;
|
||||
UIContextOperation?.Invoke(() => flowEnvironmentEvent.OnStartNodeChanged(new StartNodeChangeEventArgs(canvasGuid, oldNodeGuid, newStartNodeModel.Guid)));
|
||||
return;
|
||||
}
|
||||
|
||||
public void SetConnectPriorityInvoke(string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType)
|
||||
{
|
||||
|
||||
IOperation operation = new ChangeNodeConnectionOperation
|
||||
{
|
||||
CanvasGuid = string.Empty, // 连接优先级不需要画布
|
||||
FromNodeGuid = fromNodeGuid,
|
||||
ToNodeGuid = toNodeGuid,
|
||||
ConnectionInvokeType = connectionType,
|
||||
ChangeType = NodeConnectChangeEventArgs.ConnectChangeType.Create
|
||||
};
|
||||
flowOperationService.Execute(operation);
|
||||
}
|
||||
|
||||
public void ChangeParameter(string nodeGuid, bool isAdd, int paramIndex)
|
||||
{
|
||||
IOperation operation = new ChangeParameterOperation
|
||||
{
|
||||
NodeGuid = nodeGuid,
|
||||
IsAdd = isAdd,
|
||||
ParamIndex = paramIndex
|
||||
};
|
||||
flowOperationService.Execute(operation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从节点信息集合批量加载节点控件
|
||||
/// </summary>
|
||||
/// <param name="List<NodeInfo>">节点信息</param>
|
||||
/// <returns></returns>
|
||||
///
|
||||
public async Task LoadNodeInfosAsync(List<NodeInfo> nodeInfos)
|
||||
{
|
||||
#region 从NodeInfo创建NodeModel
|
||||
// 流程接口节点最后才创建
|
||||
|
||||
List<NodeInfo> flowCallNodeInfos = [];
|
||||
foreach (NodeInfo? nodeInfo in nodeInfos)
|
||||
{
|
||||
if (nodeInfo.Type == nameof(NodeControlType.FlowCall))
|
||||
{
|
||||
flowCallNodeInfos.Add(nodeInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!CreateNodeFromNodeInfo(nodeInfo))
|
||||
{
|
||||
SereinEnv.WriteLine(InfoType.WARN, $"节点创建失败。{Environment.NewLine}{nodeInfo}");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 创建流程接口节点
|
||||
foreach (NodeInfo? nodeInfo in flowCallNodeInfos)
|
||||
{
|
||||
if (!CreateNodeFromNodeInfo(nodeInfo))
|
||||
{
|
||||
SereinEnv.WriteLine(InfoType.WARN, $"节点创建失败。{Environment.NewLine}{nodeInfo}");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 重新放置节点
|
||||
|
||||
List<NodeInfo> needPlaceNodeInfos = [];
|
||||
foreach (NodeInfo? nodeInfo in nodeInfos)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(nodeInfo.ParentNodeGuid) &&
|
||||
TryGetNodeModel(nodeInfo.ParentNodeGuid, out var parentNode))
|
||||
{
|
||||
needPlaceNodeInfos.Add(nodeInfo); // 需要重新放置的节点
|
||||
}
|
||||
}
|
||||
|
||||
foreach (NodeInfo nodeInfo in needPlaceNodeInfos)
|
||||
{
|
||||
if (TryGetNodeModel(nodeInfo.Guid, out var nodeModel) &&
|
||||
TryGetNodeModel(nodeInfo.ParentNodeGuid, out var containerNode)
|
||||
&& containerNode is INodeContainer nodeContainer)
|
||||
{
|
||||
var result = nodeContainer.PlaceNode(nodeModel);
|
||||
if (result)
|
||||
{
|
||||
UIContextOperation?.Invoke(() => flowEnvironmentEvent.OnNodePlace(
|
||||
new NodePlaceEventArgs(nodeInfo.CanvasGuid, nodeModel.Guid, containerNode.Guid)));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
await Task.Delay(100);
|
||||
#region 确定节点之间的方法调用关系
|
||||
foreach (var nodeInfo in nodeInfos)
|
||||
{
|
||||
var canvasGuid = nodeInfo.CanvasGuid;
|
||||
if (!TryGetNodeModel(nodeInfo.Guid, out var fromNodeModel))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (fromNodeModel is null) continue;
|
||||
List<(ConnectionInvokeType connectionType, string[] guids)> allToNodes = [(ConnectionInvokeType.IsSucceed,nodeInfo.TrueNodes),
|
||||
(ConnectionInvokeType.IsFail, nodeInfo.FalseNodes),
|
||||
(ConnectionInvokeType.IsError, nodeInfo.ErrorNodes),
|
||||
(ConnectionInvokeType.Upstream, nodeInfo.UpstreamNodes)];
|
||||
foreach ((ConnectionInvokeType connectionType, string[] toNodeGuids) item in allToNodes)
|
||||
{
|
||||
// 遍历当前类型分支的节点(确认连接关系)
|
||||
foreach (var toNodeGuid in item.toNodeGuids)
|
||||
{
|
||||
if (!TryGetNodeModel(toNodeGuid, out var toNodeModel))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (toNodeModel is null)
|
||||
{
|
||||
// 防御性代码,加载正常保存的项目文件不会进入这里
|
||||
continue;
|
||||
}
|
||||
|
||||
ConnectInvokeNode(canvasGuid, fromNodeModel.Guid, toNodeModel.Guid, JunctionType.NextStep, JunctionType.Execute, item.connectionType);
|
||||
|
||||
//var isSuccessful = ConnectInvokeOfNode(canvasGuid, fromNodeModel, toNodeModel, item.connectionType); // 加载时确定节点间的连接关系
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//List<(ConnectionInvokeType connectionType, string[] guids)> allToNodes = [(ConnectionInvokeType.IsSucceed,nodeInfo.TrueNodes),
|
||||
// (ConnectionInvokeType.IsFail, nodeInfo.FalseNodes),
|
||||
// (ConnectionInvokeType.IsError, nodeInfo.ErrorNodes),
|
||||
// (ConnectionInvokeType.Upstream, nodeInfo.UpstreamNodes)];
|
||||
|
||||
//List<(ConnectionInvokeType, NodeModelBase[])> fromNodes = allToNodes.Where(info => info.guids.Length > 0)
|
||||
// .Select(info => (info.connectionType,
|
||||
// info.guids.Where(guid => NodeModels.ContainsKey(guid)).Select(guid => NodeModels[guid])
|
||||
// .ToArray()))
|
||||
// .ToList();
|
||||
// 遍历每种类型的节点分支(四种)
|
||||
//foreach ((ConnectionInvokeType connectionType, NodeModelBase[] toNodes) item in nodeInfo)
|
||||
//{
|
||||
// // 遍历当前类型分支的节点(确认连接关系)
|
||||
// foreach (var toNode in item.toNodes)
|
||||
// {
|
||||
// _ = ConnectInvokeOfNode(fromNode, toNode, item.connectionType); // 加载时确定节点间的连接关系
|
||||
// }
|
||||
//}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 确定节点之间的参数调用关系
|
||||
var nodeModels = flowModelService.GetAllNodeModel();
|
||||
foreach (var toNode in nodeModels)
|
||||
{
|
||||
var canvasGuid = toNode.CanvasDetails.Guid;
|
||||
if (toNode.MethodDetails.ParameterDetailss == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
for (var i = 0; i < toNode.MethodDetails.ParameterDetailss.Length; i++)
|
||||
{
|
||||
var pd = toNode.MethodDetails.ParameterDetailss[i];
|
||||
if (!string.IsNullOrEmpty(pd.ArgDataSourceNodeGuid)
|
||||
&& TryGetNodeModel(pd.ArgDataSourceNodeGuid, out var fromNode))
|
||||
{
|
||||
|
||||
ConnectArgSourceNode(canvasGuid, fromNode.Guid, toNode.Guid, JunctionType.ReturnData, JunctionType.ArgData, pd.ArgDataSourceType, pd.Index);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
UIContextOperation?.Invoke(() =>
|
||||
{
|
||||
flowEnvironmentEvent.OnProjectLoaded(new ProjectLoadedEventArgs());
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region 视觉效果
|
||||
|
||||
/// <summary>
|
||||
/// 定位节点
|
||||
/// </summary>
|
||||
/// <param name="nodeGuid"></param>
|
||||
public void NodeLocate(string nodeGuid)
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
UIContextOperation?.Invoke(() => flowEnvironmentEvent.OnNodeLocated(new NodeLocatedEventArgs(nodeGuid)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -45,6 +45,9 @@ namespace Serein.NodeFlow.Env
|
||||
/// </summary>
|
||||
public class FlowEnvironment : IFlowEnvironment
|
||||
{
|
||||
/// <summary>
|
||||
/// 流程运行环境构造函数
|
||||
/// </summary>
|
||||
public FlowEnvironment()
|
||||
{
|
||||
ISereinIOC ioc = new SereinIOC();
|
||||
@@ -52,6 +55,8 @@ namespace Serein.NodeFlow.Env
|
||||
.Register<ISereinIOC>(()=> ioc) // 注册IOC
|
||||
.Register<IFlowEnvironment>(() => this)
|
||||
.Register<IFlowEnvironmentEvent, FlowEnvironmentEvent>()
|
||||
.Register<IFlowEdit, FlowEdit>()
|
||||
.Register<IFlowControl, FlowControl>()
|
||||
.Register<LocalFlowEnvironment>()
|
||||
.Register<FlowModelService>()
|
||||
.Register<FlowOperationService>()
|
||||
@@ -63,7 +68,7 @@ namespace Serein.NodeFlow.Env
|
||||
currentFlowEnvironmentEvent = ioc.Get<IFlowEnvironmentEvent>();
|
||||
SereinEnv.SetEnv(currentFlowEnvironment);
|
||||
}
|
||||
|
||||
/*
|
||||
/// <summary>
|
||||
/// 本地环境事件
|
||||
/// </summary>
|
||||
@@ -73,7 +78,7 @@ namespace Serein.NodeFlow.Env
|
||||
/// 远程环境事件
|
||||
/// </summary>
|
||||
private IFlowEnvironmentEvent remoteFlowEnvironmentEvent;
|
||||
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// 管理当前环境
|
||||
@@ -86,9 +91,9 @@ namespace Serein.NodeFlow.Env
|
||||
/// </summary>
|
||||
private IFlowEnvironmentEvent currentFlowEnvironmentEvent;
|
||||
|
||||
|
||||
|
||||
private int _loadingProjectFlag = 0; // 使用原子自增代替锁
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 传入false时,将停止数据通知。传入true时,
|
||||
/// </summary>
|
||||
@@ -110,8 +115,12 @@ namespace Serein.NodeFlow.Env
|
||||
public IFlowEnvironment CurrentEnv => currentFlowEnvironment;
|
||||
/// <inheritdoc/>
|
||||
public UIContextOperation UIContextOperation => currentFlowEnvironment.UIContextOperation;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public NodeMVVMService NodeMVVMManagement => currentFlowEnvironment.NodeMVVMManagement;
|
||||
public IFlowEdit FlowEdit => currentFlowEnvironment.FlowEdit;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IFlowControl FlowControl => currentFlowEnvironment.FlowControl;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ISereinIOC IOC => currentFlowEnvironment.IOC;
|
||||
@@ -138,172 +147,10 @@ namespace Serein.NodeFlow.Env
|
||||
/// <inheritdoc/>
|
||||
public RunState FlowState { get => currentFlowEnvironment.FlowState; set => currentFlowEnvironment.FlowState = value; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event LoadDllHandler DllLoad {
|
||||
add { currentFlowEnvironmentEvent.DllLoad += value; }
|
||||
remove { currentFlowEnvironmentEvent.DllLoad -= value; }
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event ProjectLoadedHandler ProjectLoaded
|
||||
{
|
||||
add { currentFlowEnvironmentEvent.ProjectLoaded += value; }
|
||||
remove { currentFlowEnvironmentEvent.ProjectLoaded -= value; }
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event ProjectSavingHandler? ProjectSaving
|
||||
{
|
||||
add { currentFlowEnvironmentEvent.ProjectSaving += value; }
|
||||
remove { currentFlowEnvironmentEvent.ProjectSaving -= value; }
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event NodeConnectChangeHandler NodeConnectChanged
|
||||
{
|
||||
add { currentFlowEnvironmentEvent.NodeConnectChanged += value; }
|
||||
remove { currentFlowEnvironmentEvent.NodeConnectChanged -= value; }
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event CanvasCreateHandler CanvasCreated
|
||||
{
|
||||
add { currentFlowEnvironmentEvent.CanvasCreated += value; }
|
||||
remove { currentFlowEnvironmentEvent.CanvasCreated -= value; }
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event CanvasRemoveHandler CanvasRemoved
|
||||
{
|
||||
add { currentFlowEnvironmentEvent.CanvasRemoved += value; }
|
||||
remove { currentFlowEnvironmentEvent.CanvasRemoved -= value; }
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event NodeCreateHandler NodeCreated
|
||||
{
|
||||
add { currentFlowEnvironmentEvent.NodeCreated += value; }
|
||||
remove { currentFlowEnvironmentEvent.NodeCreated -= value; }
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event NodeRemoveHandler NodeRemoved
|
||||
{
|
||||
add { currentFlowEnvironmentEvent.NodeRemoved += value; }
|
||||
remove { currentFlowEnvironmentEvent.NodeRemoved -= value; }
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event NodePlaceHandler NodePlace
|
||||
{
|
||||
add { currentFlowEnvironmentEvent.NodePlace += value; }
|
||||
remove { currentFlowEnvironmentEvent.NodePlace -= value; }
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event NodeTakeOutHandler NodeTakeOut
|
||||
{
|
||||
add { currentFlowEnvironmentEvent.NodeTakeOut += value; }
|
||||
remove { currentFlowEnvironmentEvent.NodeTakeOut -= value; }
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event StartNodeChangeHandler StartNodeChanged
|
||||
{
|
||||
add { currentFlowEnvironmentEvent.StartNodeChanged += value; }
|
||||
remove { currentFlowEnvironmentEvent.StartNodeChanged -= value; }
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event FlowRunCompleteHandler FlowRunComplete
|
||||
{
|
||||
add { currentFlowEnvironmentEvent.FlowRunComplete += value; }
|
||||
remove { currentFlowEnvironmentEvent.FlowRunComplete -= value; }
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event MonitorObjectChangeHandler MonitorObjectChanged
|
||||
{
|
||||
add { currentFlowEnvironmentEvent.MonitorObjectChanged += value; }
|
||||
remove { currentFlowEnvironmentEvent.MonitorObjectChanged -= value; }
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event NodeInterruptStateChangeHandler NodeInterruptStateChanged
|
||||
{
|
||||
add { currentFlowEnvironmentEvent.NodeInterruptStateChanged += value; }
|
||||
remove { currentFlowEnvironmentEvent.NodeInterruptStateChanged -= value; }
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event ExpInterruptTriggerHandler InterruptTriggered
|
||||
{
|
||||
add { currentFlowEnvironmentEvent.InterruptTriggered += value; }
|
||||
remove { currentFlowEnvironmentEvent.InterruptTriggered -= value; }
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event IOCMembersChangedHandler IOCMembersChanged
|
||||
{
|
||||
add { currentFlowEnvironmentEvent.IOCMembersChanged += value; }
|
||||
remove { currentFlowEnvironmentEvent.IOCMembersChanged -= value; }
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event NodeLocatedHandler NodeLocated
|
||||
{
|
||||
add { currentFlowEnvironmentEvent.NodeLocated += value; }
|
||||
remove { currentFlowEnvironmentEvent.NodeLocated -= value; }
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event EnvOutHandler EnvOutput
|
||||
{
|
||||
add { currentFlowEnvironmentEvent.EnvOutput += value; }
|
||||
remove { currentFlowEnvironmentEvent.EnvOutput -= value; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void ActivateFlipflopNode(string nodeGuid)
|
||||
{
|
||||
currentFlowEnvironment.ActivateFlipflopNode(nodeGuid);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void CreateCanvas(string canvasName, int width, int height)
|
||||
{
|
||||
currentFlowEnvironment.CreateCanvas(canvasName, width, height);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void RemoveCanvas(string canvasGuid)
|
||||
{
|
||||
currentFlowEnvironment.RemoveCanvas(canvasGuid);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void ConnectInvokeNode(string canvasGuid,
|
||||
string fromNodeGuid,
|
||||
string toNodeGuid,
|
||||
JunctionType fromNodeJunctionType,
|
||||
JunctionType toNodeJunctionType,
|
||||
ConnectionInvokeType invokeType)
|
||||
{
|
||||
currentFlowEnvironment.ConnectInvokeNode(canvasGuid, fromNodeGuid, toNodeGuid, fromNodeJunctionType, toNodeJunctionType, invokeType);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void ConnectArgSourceNode(string canvasGuid,
|
||||
string fromNodeGuid,
|
||||
string toNodeGuid,
|
||||
JunctionType fromNodeJunctionType,
|
||||
JunctionType toNodeJunctionType,
|
||||
ConnectionArgSourceType argSourceType,
|
||||
int argIndex)
|
||||
{
|
||||
currentFlowEnvironment.ConnectArgSourceNode(canvasGuid, fromNodeGuid, toNodeGuid, fromNodeJunctionType, toNodeJunctionType, argSourceType, argIndex);
|
||||
currentFlowEnvironment.FlowControl.ActivateFlipflopNode(nodeGuid);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -320,42 +167,10 @@ namespace Serein.NodeFlow.Env
|
||||
return (isConnect, remoteMsgUtil);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task LoadNodeInfosAsync(List<NodeInfo> nodeInfos)
|
||||
{
|
||||
SetProjectLoadingFlag(false);
|
||||
await currentFlowEnvironment.LoadNodeInfosAsync(nodeInfos); // 装饰器调用
|
||||
SetProjectLoadingFlag(true);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void CreateNode(string canvasGuid, NodeControlType nodeBase, PositionOfUI position, MethodDetailsInfo methodDetailsInfo = null)
|
||||
{
|
||||
SetProjectLoadingFlag(false);
|
||||
currentFlowEnvironment.CreateNode(canvasGuid, nodeBase, position, methodDetailsInfo); // 装饰器调用
|
||||
SetProjectLoadingFlag(true);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void PlaceNodeToContainer(string canvasGuid, string nodeGuid, string containerNodeGuid)
|
||||
{
|
||||
SetProjectLoadingFlag(false);
|
||||
currentFlowEnvironment.PlaceNodeToContainer(canvasGuid, nodeGuid, containerNodeGuid); // 装饰器调用
|
||||
SetProjectLoadingFlag(true);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void TakeOutNodeToContainer(string canvasGuid, string nodeGuid)
|
||||
{
|
||||
SetProjectLoadingFlag(false);
|
||||
currentFlowEnvironment.TakeOutNodeToContainer(canvasGuid,nodeGuid); // 装饰器调用
|
||||
SetProjectLoadingFlag(true);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<bool> ExitFlowAsync()
|
||||
{
|
||||
return await currentFlowEnvironment.ExitFlowAsync();
|
||||
return await currentFlowEnvironment.FlowControl.ExitFlowAsync();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -401,19 +216,7 @@ namespace Serein.NodeFlow.Env
|
||||
/// <inheritdoc/>
|
||||
public void MonitorObjectNotification(string nodeGuid, object monitorData, MonitorObjectEventArgs.ObjSourceType sourceType)
|
||||
{
|
||||
currentFlowEnvironment.MonitorObjectNotification(nodeGuid, monitorData, sourceType);
|
||||
}
|
||||
|
||||
/*/// <inheritdoc/>
|
||||
public void MoveNode(string canvasGuid, string nodeGuid, double x, double y)
|
||||
{
|
||||
currentFlowEnvironment.MoveNode(canvasGuid, nodeGuid, x, y);
|
||||
}
|
||||
*/
|
||||
/// <inheritdoc/>
|
||||
public void NodeLocate(string nodeGuid)
|
||||
{
|
||||
currentFlowEnvironment.NodeLocate(nodeGuid);
|
||||
currentFlowEnvironment.FlowControl.MonitorObjectNotification(nodeGuid, monitorData, sourceType);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -422,31 +225,6 @@ namespace Serein.NodeFlow.Env
|
||||
return currentFlowEnvironment.TryUnloadLibrary(assemblyName);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void SetConnectPriorityInvoke(string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType)
|
||||
{
|
||||
currentFlowEnvironment.SetConnectPriorityInvoke(fromNodeGuid, toNodeGuid, connectionType);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void RemoveInvokeConnect(string canvasGuid, string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType)
|
||||
{
|
||||
currentFlowEnvironment.RemoveInvokeConnect(canvasGuid, fromNodeGuid, toNodeGuid, connectionType);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void RemoveArgSourceConnect(string canvasGuid, string fromNodeGuid, string toNodeGuid, int argIndex)
|
||||
{
|
||||
currentFlowEnvironment.RemoveArgSourceConnect(canvasGuid, fromNodeGuid, toNodeGuid, argIndex);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void RemoveNode(string canvasGuid, string nodeGuid)
|
||||
{
|
||||
currentFlowEnvironment.RemoveNode(canvasGuid, nodeGuid);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 输出信息
|
||||
/// </summary>
|
||||
@@ -489,22 +267,17 @@ namespace Serein.NodeFlow.Env
|
||||
|
||||
#endregion
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void SetStartNode(string canvasGuid, string nodeGuid)
|
||||
{
|
||||
currentFlowEnvironment.SetStartNode(canvasGuid, nodeGuid);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<bool> StartFlowAsync(string[] canvasGuids)
|
||||
{
|
||||
return await currentFlowEnvironment.StartFlowAsync(canvasGuids);
|
||||
return await currentFlowEnvironment.FlowControl.StartFlowAsync(canvasGuids);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<bool> StartFlowFromSelectNodeAsync(string startNodeGuid)
|
||||
{
|
||||
return await currentFlowEnvironment.StartFlowFromSelectNodeAsync(startNodeGuid);
|
||||
return await currentFlowEnvironment.FlowControl.StartFlowFromSelectNodeAsync(startNodeGuid);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -522,13 +295,13 @@ namespace Serein.NodeFlow.Env
|
||||
/// <inheritdoc/>
|
||||
public void TerminateFlipflopNode(string nodeGuid)
|
||||
{
|
||||
currentFlowEnvironment.TerminateFlipflopNode(nodeGuid);
|
||||
currentFlowEnvironment.FlowControl.TerminateFlipflopNode(nodeGuid);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void TriggerInterrupt(string nodeGuid, string expression, InterruptTriggerEventArgs.InterruptTriggerType type)
|
||||
{
|
||||
currentFlowEnvironment.TriggerInterrupt(nodeGuid, expression, type);
|
||||
currentFlowEnvironment.FlowControl.TriggerInterrupt(nodeGuid, expression, type);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -545,7 +318,7 @@ namespace Serein.NodeFlow.Env
|
||||
/// <inheritdoc/>
|
||||
public void UseExternalIOC(ISereinIOC ioc)
|
||||
{
|
||||
currentFlowEnvironment.UseExternalIOC(ioc);
|
||||
currentFlowEnvironment.FlowControl.UseExternalIOC(ioc);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -579,11 +352,6 @@ namespace Serein.NodeFlow.Env
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void ChangeParameter(string nodeGuid, bool isAdd, int paramIndex)
|
||||
{
|
||||
currentFlowEnvironment.ChangeParameter(nodeGuid, isAdd, paramIndex);
|
||||
}
|
||||
|
||||
#region 流程依赖类库的接口
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -43,7 +43,7 @@ namespace Serein.NodeFlow
|
||||
|
||||
// 尝试获取需要创建的节点类型
|
||||
|
||||
if (!env.NodeMVVMManagement.TryGetType(nodeControlType, out var nodeMVVM) || nodeMVVM.ModelType == null)
|
||||
if (!env.FlowEdit.NodeMVVMManagement.TryGetType(nodeControlType, out var nodeMVVM) || nodeMVVM.ModelType == null)
|
||||
{
|
||||
throw new Exception($"无法创建{nodeControlType}节点,节点类型尚未注册。");
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ namespace Serein.NodeFlow.Model
|
||||
// 执行触发检查是否需要中断
|
||||
if (DebugSetting.IsInterrupt)
|
||||
{
|
||||
context.Env.TriggerInterrupt(Guid, "", InterruptTriggerEventArgs.InterruptTriggerType.Monitor); // 通知运行环境该节点中断了
|
||||
context.Env.FlowControl.TriggerInterrupt(Guid, "", InterruptTriggerEventArgs.InterruptTriggerType.Monitor); // 通知运行环境该节点中断了
|
||||
await DebugSetting.GetInterruptTask.Invoke();
|
||||
SereinEnv.WriteLine(InfoType.INFO, $"[{this.MethodDetails?.MethodName}]中断已取消,开始执行后继分支");
|
||||
if (token.IsCancellationRequested) { return null; }
|
||||
|
||||
@@ -38,17 +38,15 @@ namespace Serein.NodeFlow.Model
|
||||
public partial class SingleFlowCallNode : NodeModelBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 接口节点
|
||||
/// 被调用的节点
|
||||
/// </summary>
|
||||
private IFlowNode targetNode;
|
||||
/// <summary>
|
||||
/// 缓存的方法信息
|
||||
/// </summary>
|
||||
public MethodDetails CacheMethodDetails { get; private set; }
|
||||
/// <summary>
|
||||
/// 接口节点Guid
|
||||
/// </summary>
|
||||
//public string? TargetNodeGuid => targetNode?.Guid;
|
||||
|
||||
|
||||
|
||||
|
||||
public SingleFlowCallNode(IFlowEnvironment environment) : base(environment)
|
||||
|
||||
@@ -96,7 +96,7 @@ namespace Serein.NodeFlow.Model
|
||||
{
|
||||
foreach (var nodeModel in ChildrenNode)
|
||||
{
|
||||
nodeModel.Env.TakeOutNodeToContainer(nodeModel.CanvasDetails.Guid, nodeModel.Guid);
|
||||
nodeModel.Env.FlowEdit.TakeOutNodeToContainer(nodeModel.CanvasDetails.Guid, nodeModel.Guid);
|
||||
}
|
||||
DataNode = null;
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ namespace Serein.NodeFlow.Model.Operation
|
||||
if(flowNode is null) return false; // 没有创建过节点
|
||||
var canvasGuid = flowCanvasDetails.Guid;
|
||||
var nodeGuid = flowNode.Guid;
|
||||
flowEnvironment.RemoveNode(canvasGuid, nodeGuid);
|
||||
flowEnvironment.FlowEdit.RemoveNode(canvasGuid, nodeGuid);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser;
|
||||
|
||||
namespace Serein.NodeFlow.Services
|
||||
{
|
||||
@@ -31,32 +30,6 @@ namespace Serein.NodeFlow.Services
|
||||
|
||||
|
||||
|
||||
/* object result = flowApiService.Invoke("", params);
|
||||
TResult result = flowApiService.Invoke<TResult>("", params);
|
||||
object result = await flowApiService.InvokeAsync("", params);
|
||||
TResult result = await flowApiService.InvokeAsync<TResult>("", params);*/
|
||||
|
||||
|
||||
public object Invoke(string apiName, object[] param)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public TResult Invoke<TResult>(string apiName, object[] param)
|
||||
{
|
||||
return default(TResult);
|
||||
}
|
||||
|
||||
public async Task<object> InvokeAsync(string apiName, object[] param)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public async Task<TResult> InvokeAsync<TResult>(string apiName, object[] param)
|
||||
{
|
||||
return default(TResult);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user