使用异步重构了节点执行方法,将触发器节点与其他节点统一。使用Channel代替Tcs更改了信号触发,使其符合异步编程的习惯。增加了节点是否启用勾选框、参数遮罩勾选框,节点右键面板增加中断功能(试验)。增加了选择后被选择的节点的视觉效果。更改平移缩放逻辑,使其更加符合一般的使用习惯。

This commit is contained in:
fengjiayi
2024-09-20 10:50:32 +08:00
parent 8335094656
commit f5924aa31e
30 changed files with 1298 additions and 539 deletions

View File

@@ -7,6 +7,7 @@ using Serein.Library.Web;
using Serein.NodeFlow.Base;
using Serein.NodeFlow.Model;
using System.ComponentModel.Design;
using static Serein.Library.Utils.ChannelFlowInterrupt;
namespace Serein.NodeFlow
{
@@ -22,6 +23,7 @@ namespace Serein.NodeFlow
{
SereinIOC = new SereinIOC();
}
/// <summary>
/// 流程运行状态
/// </summary>
@@ -60,13 +62,12 @@ namespace Serein.NodeFlow
/// 结束运行时需要执行的方法
/// </summary>
private Action ExitAction { get; set; } = null;
/// <summary>
/// 运行的上下文
/// </summary>
private IDynamicContext Context { get; set; } = null;
/// <summary>
/// 开始运行
/// </summary>
@@ -106,7 +107,7 @@ namespace Serein.NodeFlow
#endregion
#region Ioc容器
// 清除节点使用的对象
// 清除节点使用的对象,筛选出需要初始化的方法描述
var thisRuningMds = new List<MethodDetails>();
thisRuningMds.AddRange(runNodeMd.Where(md => md is not null));
thisRuningMds.AddRange(initMethods.Where(md => md is not null));
@@ -213,11 +214,11 @@ namespace Serein.NodeFlow
// 使用 TaskCompletionSource 创建未启动的触发器任务
var tasks = flipflopNodes.Select(async node =>
{
await FlipflopExecute(node, env);
await FlipflopExecute(env,node);
}).ToArray();
_ = Task.WhenAll(tasks);
}
await startNode.StartExecution(Context); // 从起始节点开始运行
await startNode.StartExecute(Context); // 开始运行时从起始节点开始运行
// 等待结束
if (FlipFlopCts != null)
{
@@ -240,15 +241,17 @@ namespace Serein.NodeFlow
{
// 设置对象
singleFlipFlopNode.MethodDetails.ActingInstance = SereinIOC.GetOrRegisterInstantiate(singleFlipFlopNode.MethodDetails.ActingInstanceType);
await FlipflopExecute(singleFlipFlopNode, flowEnvironment); // 启动触发器
await FlipflopExecute(flowEnvironment,singleFlipFlopNode); // 启动触发器
});
}
/// <summary>
/// 启动全局触发器
/// </summary>
private async Task FlipflopExecute(SingleFlipflopNode singleFlipFlopNode, IFlowEnvironment flowEnvironment)
/// <param name="flowEnvironment">流程运行全局环境</param>
/// <param name="singleFlipFlopNode">需要全局监听信号的触发器</param>
/// <returns></returns>
private async Task FlipflopExecute(IFlowEnvironment flowEnvironment,SingleFlipflopNode singleFlipFlopNode)
{
var context = new DynamicContext(SereinIOC, flowEnvironment);
MethodDetails md = singleFlipFlopNode.MethodDetails;
@@ -259,6 +262,7 @@ namespace Serein.NodeFlow
{
md.ActingInstance ??= context.SereinIoc.GetOrRegisterInstantiate(md.ActingInstanceType);
}
object?[]? parameters = singleFlipFlopNode.GetParameters(context, singleFlipFlopNode.MethodDetails); // 启动全局触发器时获取入参参数
// 设置委托对象
var func = md.ExplicitDatas.Length == 0 ?
(Func<object, object, Task<IFlipflopContext>>)del :
@@ -267,49 +271,13 @@ namespace Serein.NodeFlow
{
while (!FlipFlopCts.IsCancellationRequested)
{
object?[]? parameters = singleFlipFlopNode.GetParameters(context, singleFlipFlopNode.MethodDetails); // 启动全局触发器时获取入参参数
IFlipflopContext flipflopContext = await func.Invoke(md.ActingInstance, parameters);// 首先开始等待触发器
_ = GlobalFlipflopExecute(singleFlipFlopNode, context);
IFlipflopContext flipflopContext = await func.Invoke(md.ActingInstance, parameters);// 开始等待全局触发器的触发
var connectionType = flipflopContext.State.ToContentType();
if (connectionType != ConnectionType.None)
{
await GlobalFlipflopExecute(context, singleFlipFlopNode, connectionType);
}
}
//while (!FlipFlopCts.IsCancellationRequested)
//{
// if (singleFlipFlopNode.NotExitPreviousNode() == false)
// {
// break;
// }
// object?[]? parameters = singleFlipFlopNode.GetParameters(context, md);
// if (md.ActingInstance == null)
// {
// md.ActingInstance = context.SereinIoc.GetOrRegisterInstantiate(md.ActingInstanceType);
// }
// IFlipflopContext flipflopContext = await func.Invoke(md.ActingInstance, parameters);
// ConnectionType connection = flipflopContext.State.ToContentType();
// if (connection != ConnectionType.None)
// {
// singleFlipFlopNode.NextOrientation = connection;
// singleFlipFlopNode.FlowData = flipflopContext.Data;
// var tasks = singleFlipFlopNode.SuccessorNodes.Values
// .SelectMany(nodeList => nodeList)
// .Select(nextNode =>
// {
// var nextContext = new DynamicContext(SereinIOC, flowEnvironment);
// nextNode.PreviousNode = singleFlipFlopNode;
// return nextNode.StartExecution(nextContext); // 全局触发器收到信号,开始执行
// }).ToArray();
// await Task.WhenAll(tasks);
// }
// else
// {
// break;
// }
//}
}
catch (Exception ex)
{
@@ -317,18 +285,25 @@ namespace Serein.NodeFlow
}
}
public async Task GlobalFlipflopExecute(SingleFlipflopNode singleFlipFlopNode, IDynamicContext context)
/// <summary>
/// 全局触发器开始执行相关分支
/// </summary>
/// <param name="context">上下文</param>
/// <param name="singleFlipFlopNode">被触发的全局触发器</param>
/// <param name="connectionType">分支类型</param>
/// <returns></returns>
public async Task GlobalFlipflopExecute(IDynamicContext context, SingleFlipflopNode singleFlipFlopNode, ConnectionType connectionType)
{
if (FlipFlopCts.IsCancellationRequested)
if (FlipFlopCts.IsCancellationRequested )
{
return;
}
bool skip = true;
var cts = context.SereinIoc.GetOrRegisterInstantiate<CancellationTokenSource>();
Stack<NodeModelBase> stack = new Stack<NodeModelBase>();
stack.Push(singleFlipFlopNode);
ConnectionType connectionType = ConnectionType.IsSucceed;
while (stack.Count > 0 && !cts.IsCancellationRequested) // 循环中直到栈为空才会退出循环
{
@@ -346,7 +321,7 @@ namespace Serein.NodeFlow
for (int i = upstreamNodes.Count - 1; i >= 0; i--)
{
upstreamNodes[i].PreviousNode = currentNode;
await upstreamNodes[i].StartExecution(context); // 执行上游分支
await upstreamNodes[i].StartExecute(context); // 执行全局触发器的上游分支
}
// 当前节点是已经触发了的全局触发器,所以跳过,难道每次都要判断一次?
@@ -356,15 +331,8 @@ namespace Serein.NodeFlow
}
else
{
// 判断是否为触发器节点,如果是,则开始等待。
if (currentNode.MethodDetails != null && currentNode.MethodDetails.MethodDynamicType == NodeType.Flipflop)
{
currentNode.FlowData = await currentNode.ExecuteAsync(context); // 流程中遇到了触发器
}
else
{
currentNode.FlowData = currentNode.Execute(context); // 流程中正常执行
}
currentNode.FlowData = await currentNode.ExecutingAsync(context);
if (currentNode.NextOrientation == ConnectionType.None)
{
break; // 不再执行