diff --git a/Library/Utils/SereinIoc.cs b/Library/Utils/SereinIoc.cs
index 012c6cf..047d391 100644
--- a/Library/Utils/SereinIoc.cs
+++ b/Library/Utils/SereinIoc.cs
@@ -141,7 +141,7 @@ namespace Serein.Library.Utils
}
///
- /// 根据类型生成对应的实例,并注入其中的依赖项(类型信息不登记到IOC容器中)
+ /// 根据类型生成对应的实例,并注入其中的依赖项(类型信息不登记到IOC容器中),类型创建后自动注入其它需要此类型的对象
///
///
///
diff --git a/Library/Web/Router.cs b/Library/Web/Router.cs
index c5531d8..5708ae3 100644
--- a/Library/Web/Router.cs
+++ b/Library/Web/Router.cs
@@ -399,10 +399,18 @@ namespace Serein.Library.Web
catch (Exception ex)
{
// If serialization fails, use the original message's string representation
- resultData = ex.ToString();
- byte[] buffer = Encoding.UTF8.GetBytes(resultData);
- response.ContentLength64 = buffer.Length;
- response.OutputStream.Write(buffer, 0, buffer.Length);
+ try
+ {
+ resultData = ex.ToString();
+ byte[] buffer = Encoding.UTF8.GetBytes(resultData);
+ response.ContentLength64 = buffer.Length;
+ response.OutputStream.Write(buffer, 0, buffer.Length);
+ }
+ catch (Exception ex1)
+ {
+
+ Console.WriteLine(ex1);
+ }
}
diff --git a/NodeFlow/FlowEnvironment.cs b/NodeFlow/FlowEnvironment.cs
index 6f34881..214d327 100644
--- a/NodeFlow/FlowEnvironment.cs
+++ b/NodeFlow/FlowEnvironment.cs
@@ -81,7 +81,7 @@ namespace Serein.NodeFlow
///
public event FlowRunCompleteHandler OnFlowRunComplete;
- private FlowStarter? nodeFlowStarter = null;
+ private FlowStarter? flowStarter = null;
///
/// 一种轻量的IOC容器
@@ -117,6 +117,7 @@ namespace Serein.NodeFlow
/// 私有属性
///
private NodeModelBase _startNode;
+
///
/// 起始节点
///
@@ -143,7 +144,7 @@ namespace Serein.NodeFlow
///
public async Task StartAsync()
{
- nodeFlowStarter = new FlowStarter();
+ flowStarter = new FlowStarter();
List flipflopNodes = Nodes.Values.Where(it => it.MethodDetails?.MethodDynamicType == NodeType.Flipflop && it.IsStart == false)
.Select(it => (SingleFlipflopNode)it)
.Where(node => node is SingleFlipflopNode flipflopNode && flipflopNode.NotExitPreviousNode())
@@ -154,7 +155,7 @@ namespace Serein.NodeFlow
var exitMethods = MethodDetailss.Where(it => it.MethodDynamicType == NodeType.Exit).ToList();
- await nodeFlowStarter.RunAsync(StartNode,
+ await flowStarter.RunAsync(StartNode,
this,
runMethodDetailess,
initMethods,
@@ -162,15 +163,15 @@ namespace Serein.NodeFlow
exitMethods,
flipflopNodes);
- if(nodeFlowStarter?.FlipFlopState == RunState.NoStart)
+ if(flowStarter?.FlipFlopState == RunState.NoStart)
{
this.Exit(); // 未运行触发器时,才会调用结束方法
}
- nodeFlowStarter = null;
+ flowStarter = null;
}
public void Exit()
{
- nodeFlowStarter?.Exit();
+ flowStarter?.Exit();
OnFlowRunComplete?.Invoke(new FlowEventArgs());
}
@@ -341,9 +342,6 @@ namespace Serein.NodeFlow
OnProjectLoaded?.Invoke(new ProjectLoadedEventArgs());
}
-
-
-
///
/// 保存项目为项目文件
///
@@ -381,6 +379,15 @@ namespace Serein.NodeFlow
{
var nodeModel = CreateNode(nodeControlType, methodDetails);
TryAddNode(nodeModel);
+
+ if(flowStarter?.FlowState != RunState.Completion
+ && nodeControlType == NodeControlType.Flipflop
+ && nodeModel is SingleFlipflopNode flipflopNode)
+ {
+ // 当前添加节点属于触发器,且当前正在运行,则加载到运行环境中
+ flowStarter?.AddFlipflopInRuning(flipflopNode, this);
+ }
+
// 通知UI更改
OnNodeCreate?.Invoke(new NodeCreateEventArgs(nodeModel, position));
// 因为需要UI先布置了元素,才能通知UI变更特效
@@ -391,8 +398,6 @@ namespace Serein.NodeFlow
}
}
-
-
///
/// 移除节点
///
@@ -432,15 +437,18 @@ namespace Serein.NodeFlow
// 遍历所有子节点,从那些子节点中的父节点集合移除该节点
foreach (var snc in remoteNode.SuccessorNodes)
{
- var sCType = snc.Key; // 连接类型
+ var connectionType = snc.Key; // 连接类型
for (int i = 0; i < snc.Value.Count; i++)
{
- NodeModelBase? sNode = snc.Value[i];
- remoteNode.SuccessorNodes[sCType].RemoveAt(i);
- OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(remoteNode.Guid,
- sNode.Guid,
- sCType,
- NodeConnectChangeEventArgs.ConnectChangeType.Remote)); // 通知UI
+ NodeModelBase? toNode = snc.Value[i];
+
+ RemoteConnect(remoteNode, toNode, connectionType);
+ //remoteNode.SuccessorNodes[connectionType].RemoveAt(i);
+
+ //OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(remoteNode.Guid,
+ // toNode.Guid,
+ // connectionType,
+ // NodeConnectChangeEventArgs.ConnectChangeType.Remote)); // 通知UI
}
}
@@ -475,9 +483,9 @@ namespace Serein.NodeFlow
///
/// 移除连接关系
///
- ///
- ///
- ///
+ /// 起始节点Guid
+ /// 目标节点Guid
+ /// 连接关系
///
public void RemoteConnect(string fromNodeGuid, string toNodeGuid, ConnectionType connectionType)
{
@@ -490,11 +498,41 @@ namespace Serein.NodeFlow
{
return;
}
+ RemoteConnect(fromNode, toNode, connectionType);
+ //fromNode.SuccessorNodes[connectionType].Remove(toNode);
+ //toNode.PreviousNodes[connectionType].Remove(fromNode);
+ //OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNodeGuid,
+ // toNodeGuid,
+ // connectionType,
+ // NodeConnectChangeEventArgs.ConnectChangeType.Remote));
+ }
+
+
+ ///
+ /// 移除连接关系
+ ///
+ /// 起始节点Model
+ /// 目标节点Model
+ /// 连接关系
+ ///
+ private void RemoteConnect(NodeModelBase fromNode, NodeModelBase toNode, ConnectionType connectionType)
+ {
fromNode.SuccessorNodes[connectionType].Remove(toNode);
toNode.PreviousNodes[connectionType].Remove(fromNode);
- OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNodeGuid,
- toNodeGuid,
+ if(toNode is SingleFlipflopNode flipflopNode)
+ {
+ if (flowStarter?.FlowState != RunState.Completion
+ && flipflopNode.NotExitPreviousNode())
+ {
+ // 被父节点移除连接关系的子节点若为触发器,且无上级节点,则当前流程正在运行,则加载到运行环境中
+ flowStarter?.AddFlipflopInRuning(flipflopNode, this);
+ }
+ }
+
+ // 通知UI
+ OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNode.Guid,
+ toNode.Guid,
connectionType,
NodeConnectChangeEventArgs.ConnectChangeType.Remote));
}
@@ -789,10 +827,6 @@ namespace Serein.NodeFlow
return controlType;
}
-
-
-
-
public static bool NotExitPreviousNode(this SingleFlipflopNode node)
{
ConnectionType[] ct = [ConnectionType.IsSucceed,
diff --git a/NodeFlow/FlowStarter.cs b/NodeFlow/FlowStarter.cs
index d68ad31..5b96a10 100644
--- a/NodeFlow/FlowStarter.cs
+++ b/NodeFlow/FlowStarter.cs
@@ -157,7 +157,7 @@ namespace Serein.NodeFlow
}
#endregion
- #region 执行初始化,绑定IOC容器,再执行加载时,设置流程退出时的回调函数
+ #region 执行初始化,绑定IOC容器,再执行加载时
object?[]? args = [Context];
foreach (var md in initMethods) // 初始化
@@ -172,6 +172,9 @@ namespace Serein.NodeFlow
md.MethodDelegate.DynamicInvoke(data);
}
Context.SereinIoc.Build(); // 预防有人在加载时才注册类型,再绑定一次
+ #endregion
+
+ #region 设置流程退出时的回调函数
ExitAction = () =>
{
SereinIOC.Run(web => {
@@ -193,9 +196,6 @@ namespace Serein.NodeFlow
}
FlowState = RunState.Completion;
FlipFlopState = RunState.Completion;
-
-
-
};
#endregion
@@ -233,6 +233,17 @@ namespace Serein.NodeFlow
#endregion
}
+ public void AddFlipflopInRuning(SingleFlipflopNode singleFlipFlopNode, IFlowEnvironment flowEnvironment)
+ {
+ _ = Task.Run(async () =>
+ {
+ // 设置对象
+ singleFlipFlopNode.MethodDetails.ActingInstance = SereinIOC.GetOrRegisterInstantiate(singleFlipFlopNode.MethodDetails.ActingInstanceType);
+ await FlipflopExecute(singleFlipFlopNode, flowEnvironment); // 启动触发器
+ });
+ }
+
+
///
/// 启动触发器
///
@@ -248,26 +259,39 @@ namespace Serein.NodeFlow
while (!FlipFlopCts.IsCancellationRequested) // 循环中直到栈为空才会退出
{
+ if(singleFlipFlopNode.NotExitPreviousNode() == false)
+ {
+ // 存在上级节点时,退出触发器
+ break;
+ }
object?[]? parameters = singleFlipFlopNode.GetParameters(context, md);
// 调用委托并获取结果
-
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[connection].Select(nextNode =>
+ var upstreamNodeTasks = singleFlipFlopNode.SuccessorNodes[ConnectionType.Upstream].Select(nextNode =>
+ {
+ var context = new DynamicContext(SereinIOC, flowEnvironment);
+ nextNode.PreviousNode = singleFlipFlopNode;
+ return nextNode.StartExecution(context);
+ }).ToArray();
+
+ var tmpTasks = singleFlipFlopNode.SuccessorNodes[connection].Select(nextNode =>
{
var context = new DynamicContext(SereinIOC,flowEnvironment);
nextNode.PreviousNode = singleFlipFlopNode;
return nextNode.StartExecution(context);
}).ToArray();
+ Task[] tasks = [..upstreamNodeTasks, .. tmpTasks];
Task.WaitAll(tasks);
}
else
diff --git a/README.md b/README.md
index 80bc230..5844280 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,8 @@
不定期在Bilibili个人空间上更新相关的视频。
https://space.bilibili.com/33526379
-# 当前任务 2024年9月15日22:04:40
+# 计划任务 2024年9月17日更新
+* (重要+优先)实现断点功能,查看运行中节点的数据、ioc容器对象
* 计划新增基础节点“属性包装器”,用来收集各个节点的数据,包装成匿名对象/Json类型
* 计划编写网络方面的通讯,方便传出、传入数据
* 包装数据类型, 优化传递效率(尽可能避免拆箱、装箱)
diff --git a/WorkBench/App.xaml.cs b/WorkBench/App.xaml.cs
index 5b27782..6ee511f 100644
--- a/WorkBench/App.xaml.cs
+++ b/WorkBench/App.xaml.cs
@@ -150,14 +150,14 @@ namespace Serein.WorkBench
Shutdown(); // 关闭应用程序
}
}
- //else if (1 == 1)
- //{
- // string filePath = @"F:\临时\project\new project.dnf";
- // //string filePath = @"D:\Project\C#\DynamicControl\SereinFlow\.Output\Debug\net8.0-windows7.0\U9 project.dnf";
- // string content = System.IO.File.ReadAllText(filePath); // 读取整个文件内容
- // App.FData = JsonConvert.DeserializeObject(content);
- // App.FileDataPath = filePath;//System.IO.Path.GetDirectoryName(filePath)!;
- //}
+ else if (1 == 1)
+ {
+ string filePath = @"F:\临时\project\new project.dnf";
+ //string filePath = @"D:\Project\C#\DynamicControl\SereinFlow\.Output\Debug\net8.0-windows7.0\U9 project.dnf";
+ string content = System.IO.File.ReadAllText(filePath); // 读取整个文件内容
+ App.FData = JsonConvert.DeserializeObject(content);
+ App.FileDataPath = filePath;//System.IO.Path.GetDirectoryName(filePath)!;
+ }
}
}