从节点Model解耦出容器接口,重新设计了节点的保存、加载。

This commit is contained in:
fengjiayi
2024-12-24 22:23:53 +08:00
parent 949ac973bc
commit 5b0ba84fd6
30 changed files with 979 additions and 760 deletions

View File

@@ -88,5 +88,10 @@
/// </summary>
public const string SetMonitor = nameof(SetMonitor);
/// <summary>
/// 增加/减少方法可选类型的参数个数
/// </summary>
public const string ChangeParameter = nameof(ChangeParameter);
}
}

View File

@@ -9,6 +9,7 @@ using Serein.Library.Utils;
using Serein.Library.Utils.SereinExpression;
using Serein.NodeFlow.Model;
using Serein.NodeFlow.Tool;
using Serein.Script.Node;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
@@ -150,6 +151,11 @@ namespace Serein.NodeFlow.Env
/// </summary>
public event NodeRemoveHandler? OnNodeRemove;
/// <summary>
/// 节点父子关系发生改变事件
/// </summary>
public event NodeContainerChildChangeHandler OnNodeParentChildChange;
/// <summary>
/// 起始节点变化事件
/// </summary>
@@ -575,147 +581,7 @@ namespace Serein.NodeFlow.Env
LoadLibrary(dllFilePath); // 加载项目文件时加载对应的程序集
}
#if false
List<(NodeModelBase, string[])> regionChildNodes = new List<(NodeModelBase, string[])>();
List<(NodeModelBase, PositionOfUI)> ordinaryNodes = new List<(NodeModelBase, PositionOfUI)>();
// 加载节点
foreach (NodeInfo? nodeInfo in projectData.Nodes)
{
NodeControlType controlType = FlowFunc.GetNodeControlType(nodeInfo);
if (controlType == NodeControlType.None)
{
continue;
}
MethodDetails? methodDetails = null;
if (controlType.IsBaseNode())
{
// 加载基础节点
methodDetails = new MethodDetails();
}
else
{
// 加载方法节点
if (string.IsNullOrEmpty(nodeInfo.AssemblyName) && string.IsNullOrEmpty(nodeInfo.MethodName))
{
continue;
}
FlowLibraryManagement.TryGetMethodDetails(nodeInfo.AssemblyName, nodeInfo.MethodName, out methodDetails); // 加载项目时尝试获取方法信息
}
var nodeModel = FlowFunc.CreateNode(this, controlType, methodDetails); // 加载项目时创建节点
nodeModel.LoadInfo(nodeInfo); // 创建节点model
if (nodeModel is null)
{
nodeInfo.Guid = string.Empty;
continue;
}
TryAddNode(nodeModel); // 加载项目时将节点加载到环境中
if (nodeInfo.ChildNodeGuids?.Length > 0)
{
regionChildNodes.Add((nodeModel, nodeInfo.ChildNodeGuids));
UIContextOperation?.Invoke(() => OnNodeCreate?.Invoke(new NodeCreateEventArgs(nodeModel, nodeInfo.Position)));
}
else
{
ordinaryNodes.Add((nodeModel, nodeInfo.Position));
}
}
// 加载区域子项
foreach ((NodeModelBase region, string[] childNodeGuids) item in regionChildNodes)
{
foreach (var childNodeGuid in item.childNodeGuids)
{
NodeModels.TryGetValue(childNodeGuid, out NodeModelBase? childNode);
if (childNode is null)
{
// 节点尚未加载
continue;
}
UIContextOperation?.Invoke(() => OnNodeCreate?.Invoke(new NodeCreateEventArgs(childNode, true, item.region.Guid)));
// 存在节点
}
}
// 加载节点
foreach ((NodeModelBase nodeModel, PositionOfUI position) item in ordinaryNodes)
{
bool IsContinue = false;
foreach ((NodeModelBase region, string[] childNodeGuids) item2 in regionChildNodes)
{
foreach (var childNodeGuid in item2.childNodeGuids)
{
if (item.nodeModel.Guid.Equals(childNodeGuid))
{
IsContinue = true;
}
}
}
if (IsContinue) continue;
UIContextOperation?.Invoke(() => OnNodeCreate?.Invoke(new NodeCreateEventArgs(item.nodeModel, item.position)));
}
// 确定节点之间的连接关系
Task.Run(async () =>
{
await Task.Delay(777);
#region
foreach (var nodeInfo in projectData.Nodes)
{
if (!NodeModels.TryGetValue(nodeInfo.Guid, out NodeModelBase? fromNode))
{
// 不存在对应的起始节点
continue;
}
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 fromNodes)
{
// 遍历当前类型分支的节点(确认连接关系)
foreach (var toNode in item.toNodes)
{
_ = ConnectInvokeOfNode(fromNode, toNode, item.connectionType); // 加载时确定节点间的连接关系
}
}
}
#endregion
#region
foreach (var toNode in NodeModels.Values)
{
for (var i = 0; i < toNode.MethodDetails.ParameterDetailss.Length; i++)
{
var pd = toNode.MethodDetails.ParameterDetailss[i];
if (!string.IsNullOrEmpty(pd.ArgDataSourceNodeGuid)
&& NodeModels.TryGetValue(pd.ArgDataSourceNodeGuid, out var fromNode))
{
await ConnectArgSourceOfNodeAsync(fromNode, toNode, pd.ArgDataSourceType, pd.Index);
}
}
}
#endregion
});
UIContextOperation?.Invoke(() => OnProjectLoaded?.Invoke(new ProjectLoadedEventArgs()));
#endif
LoadNodeInfosAsync(projectData.Nodes.ToList());
_ = LoadNodeInfosAsync(projectData.Nodes.ToList());
SetStartNode(projectData.StartNode);
}
@@ -899,6 +765,7 @@ namespace Serein.NodeFlow.Env
//}
}
/// <summary>
/// 从节点信息集合批量加载节点控件
/// </summary>
@@ -906,18 +773,17 @@ namespace Serein.NodeFlow.Env
/// <returns></returns>
public Task LoadNodeInfosAsync(List<NodeInfo> nodeInfos)
{
List<(NodeModelBase, string[])> regionChildNodes = new List<(NodeModelBase, string[])>();
List<(NodeModelBase, PositionOfUI)> ordinaryNodes = new List<(NodeModelBase, PositionOfUI)>();
// 加载节点
List<NodeInfo> needPlaceNodeInfos = [];
#region NodeInfo创建NodeModel
foreach (NodeInfo? nodeInfo in nodeInfos)
{
NodeControlType controlType = FlowFunc.GetNodeControlType(nodeInfo);
if (controlType == NodeControlType.None)
if (!EnumHelper.TryConvertEnum<NodeControlType>(nodeInfo.Type, out var controlType))
{
continue;
}
MethodDetails? methodDetails = null;
#region
MethodDetails? methodDetails;
if (controlType.IsBaseNode())
{
// 加载基础节点
@@ -925,77 +791,50 @@ namespace Serein.NodeFlow.Env
}
else
{
if (string.IsNullOrEmpty(nodeInfo.MethodName)) continue;
// 加载方法节点
if (string.IsNullOrEmpty(nodeInfo.MethodName))
{
continue;
}
FlowLibraryManagement.TryGetMethodDetails(nodeInfo.AssemblyName, nodeInfo.MethodName, out methodDetails); // 加载项目时尝试获取方法信息
}
}
#endregion
var nodeModel = FlowFunc.CreateNode(this, controlType, methodDetails); // 加载项目时创建节点
nodeModel.LoadInfo(nodeInfo); // 创建节点model
if (nodeModel is null)
{
nodeInfo.Guid = string.Empty;
continue;
}
nodeModel.LoadInfo(nodeInfo); // 创建节点model
TryAddNode(nodeModel); // 加载项目时将节点加载到环境中
if (nodeInfo.ChildNodeGuids?.Length > 0)
if (!string.IsNullOrEmpty(nodeInfo.ParentNodeGuid) &&
NodeModels.TryGetValue(nodeInfo.ParentNodeGuid, out var parentNode))
{
regionChildNodes.Add((nodeModel, nodeInfo.ChildNodeGuids));
UIContextOperation?.Invoke(() => OnNodeCreate?.Invoke(new NodeCreateEventArgs(nodeModel, nodeInfo.Position)));
}
else
{
ordinaryNodes.Add((nodeModel, nodeInfo.Position));
needPlaceNodeInfos.Add(nodeInfo); // 需要重新放置的节点
}
UIContextOperation?.Invoke(() =>
OnNodeCreate?.Invoke(new NodeCreateEventArgs(nodeModel, nodeInfo.Position))); // 添加到UI上
}
#endregion
// 加载区域子项
foreach ((NodeModelBase region, string[] childNodeGuids) item in regionChildNodes)
#region
foreach (NodeInfo nodeInfo in needPlaceNodeInfos)
{
foreach (var childNodeGuid in item.childNodeGuids)
if (NodeModels.TryGetValue(nodeInfo.Guid, out var childNode) &&
NodeModels.TryGetValue(nodeInfo.ParentNodeGuid, out var parentNode))
{
NodeModels.TryGetValue(childNodeGuid, out NodeModelBase? childNode);
if (childNode is null)
{
// 节点尚未加载
continue;
}
UIContextOperation?.Invoke(() => OnNodeCreate?.Invoke(new NodeCreateEventArgs(childNode, true, item.region.Guid)));
// 存在节点
childNode.ParentNode = parentNode;
parentNode.ChildrenNode.Add(childNode);
UIContextOperation?.Invoke(() => OnNodeParentChildChange?.Invoke(
new NodeContainerChildChangeEventArgs(childNode.Guid, parentNode.Guid,
NodeContainerChildChangeEventArgs.Type.Place)));
}
}
// 加载节点
foreach ((NodeModelBase nodeModel, PositionOfUI position) item in ordinaryNodes)
{
bool IsContinue = false;
foreach ((NodeModelBase region, string[] childNodeGuids) item2 in regionChildNodes)
{
foreach (var childNodeGuid in item2.childNodeGuids)
{
if (item.nodeModel.Guid.Equals(childNodeGuid))
{
IsContinue = true;
}
}
}
if (IsContinue) continue;
UIContextOperation?.Invoke(() => OnNodeCreate?.Invoke(new NodeCreateEventArgs(item.nodeModel, item.position)));
#endregion
}
// 确定节点之间的连接关系
Task.Run(async () =>
_ = Task.Run(async () =>
{
await Task.Delay(400);
#region
await Task.Delay(100);
#region
foreach (var nodeInfo in nodeInfos)
{
if (!NodeModels.TryGetValue(nodeInfo.Guid, out NodeModelBase? fromNode))
@@ -1024,10 +863,11 @@ namespace Serein.NodeFlow.Env
}
}
#endregion
#region
#region
foreach (var toNode in NodeModels.Values)
{
if(toNode.MethodDetails.ParameterDetailss == null)
if (toNode.MethodDetails.ParameterDetailss == null)
{
continue;
}
@@ -1038,13 +878,12 @@ namespace Serein.NodeFlow.Env
&& NodeModels.TryGetValue(pd.ArgDataSourceNodeGuid, out var fromNode))
{
await ConnectArgSourceOfNodeAsync(fromNode, toNode, pd.ArgDataSourceType, pd.Index);
_ = ConnectArgSourceOfNodeAsync(fromNode, toNode, pd.ArgDataSourceType, pd.Index);
}
}
}
#endregion
});
UIContextOperation?.Invoke(() => OnProjectLoaded?.Invoke(new ProjectLoadedEventArgs()));
return Task.CompletedTask;
@@ -1056,7 +895,9 @@ namespace Serein.NodeFlow.Env
/// <param name="nodeControlType"></param>
/// <param name="position"></param>
/// <param name="methodDetailsInfo">如果是表达式节点条件节点该项为null</param>
public Task<NodeInfo> CreateNodeAsync(NodeControlType nodeControlType, PositionOfUI position, MethodDetailsInfo? methodDetailsInfo = null)
public Task<NodeInfo> CreateNodeAsync(NodeControlType nodeControlType,
PositionOfUI position,
MethodDetailsInfo? methodDetailsInfo = null)
{
NodeModelBase? nodeModel;
@@ -1092,8 +933,40 @@ namespace Serein.NodeFlow.Env
}
var nodeInfo = nodeModel.ToInfo();
return Task.FromResult(nodeInfo);
;
}
/// <summary>
/// 将节点放置在容器中/从容器中取出
/// </summary>
/// <param name="childNodeGuid">子节点(主要节点)</param>
/// <param name="parentNodeGuid">父节点</param>
/// <param name="isPlace">是否组合(反之为分解节点组合关系)</param>
/// <returns></returns>
public async Task<bool> ChangeNodeContainerChild(string childNodeGuid, string parentNodeGuid, bool isPlace)
{
// 获取起始节点与目标节点
var childNode = GuidToModel(childNodeGuid);
var parentNode = GuidToModel(parentNodeGuid);
if (childNode is null || parentNode is null || parentNode is not INodeContainer nodeContainer) return false;
if (isPlace)
{
// 放置节点
parentNode.ChildrenNode.Add(childNode);
childNode.ParentNode = parentNode;
nodeContainer.PlaceNode(childNode);
}
else
{
// 取出节点
parentNode.ChildrenNode.Remove(childNode);
childNode.ParentNode = null;
nodeContainer.TakeOutNode(childNode);
}
OnNodeParentChildChange?.Invoke(new NodeContainerChildChangeEventArgs(childNodeGuid, parentNodeGuid,
isPlace ? NodeContainerChildChangeEventArgs.Type.Place : NodeContainerChildChangeEventArgs.Type.TakeOut));
return true;
}
/// <summary>
@@ -1597,42 +1470,10 @@ namespace Serein.NodeFlow.Env
/// <param name="isAdd">true增加参数false减少参数</param>
/// <param name="paramIndex">以哪个参数为模板进行拷贝,或删去某个参数(该参数必须为可选参数)</param>
/// <returns></returns>
public async Task<bool> ChangeParameter(string nodeGuid, bool isAdd, int paramIndex)
public Task<bool> ChangeParameter(string nodeGuid, bool isAdd, int paramIndex)
{
var nodeModel = GuidToModel(nodeGuid);
if (nodeModel is null) return false;
var argInfo = nodeModel.MethodDetails.ParameterDetailss
.Where(pd => !string.IsNullOrEmpty(pd.ArgDataSourceNodeGuid))
.Select(pd => (pd.ArgDataSourceNodeGuid, pd.ArgDataSourceType, pd.Index))
.ToArray();
#region
foreach((var fromGuid, var type, var index) in argInfo)
{
await UIContextOperation.InvokeAsync(() =>
OnNodeConnectChange?.Invoke(
new NodeConnectChangeEventArgs(
fromGuid, // 从哪个节点开始
nodeModel.Guid, // 连接到那个节点
JunctionOfConnectionType.Arg,
index, // 参数
type, // 连接线的样式类型
NodeConnectChangeEventArgs.ConnectChangeType.Remote // 是创建连接还是删除连接
))); // 通知UI
}
for (int i = 0; i < argInfo.Length; i++)
{
ParameterDetails? pd = nodeModel.MethodDetails.ParameterDetailss[i];
var fromNode = GuidToModel(pd.ArgDataSourceNodeGuid);
if (fromNode is null) continue;
var argSourceGuid = pd.ArgDataSourceNodeGuid;
var argSourceType = pd.ArgDataSourceType;
}
#endregion
if (nodeModel is null) return Task.FromResult(false);
bool isPass;
if (isAdd)
{
@@ -1642,23 +1483,7 @@ namespace Serein.NodeFlow.Env
{
isPass = nodeModel.MethodDetails.RemoveParamsArg(paramIndex);
}
await Task.Delay(200);
foreach ((var fromGuid, var type, var index) in argInfo)
{
await UIContextOperation.InvokeAsync(() =>
OnNodeConnectChange?.Invoke(
new NodeConnectChangeEventArgs(
fromGuid, // 从哪个节点开始
nodeModel.Guid, // 连接到那个节点
JunctionOfConnectionType.Arg,
index, // 参数
type, // 连接线的样式类型
NodeConnectChangeEventArgs.ConnectChangeType.Create // 是创建连接还是删除连接
))); // 通知UI
}
return isPass;
return Task.FromResult(isPass);
}

View File

@@ -121,6 +121,15 @@ namespace Serein.NodeFlow.Env
remove { currentFlowEnvironment.OnNodeRemove -= value; }
}
/// <summary>
/// 节点父子关系发生改变事件
/// </summary>
public event NodeContainerChildChangeHandler OnNodeParentChildChange
{
add { currentFlowEnvironment.OnNodeParentChildChange += value; }
remove { currentFlowEnvironment.OnNodeParentChildChange -= value; }
}
public event StartNodeChangeHandler OnStartNodeChange
{
add { currentFlowEnvironment.OnStartNodeChange += value; }
@@ -278,6 +287,21 @@ namespace Serein.NodeFlow.Env
return result;
}
/// <summary>
/// 将节点放置在容器中/从容器中取出
/// </summary>
/// <param name="childNodeGuid">子节点(主要节点)</param>
/// <param name="parentNodeGuid">父节点</param>
/// <param name="isPlace">是否组合(反之为分解节点组合关系)</param>
/// <returns></returns>
public async Task<bool> ChangeNodeContainerChild(string childNodeGuid, string parentNodeGuid, bool isAssembly)
{
SetProjectLoadingFlag(false);
var result = await currentFlowEnvironment.ChangeNodeContainerChild(childNodeGuid, parentNodeGuid, isAssembly); // 装饰器调用
SetProjectLoadingFlag(true);
return result;
}

View File

@@ -145,6 +145,12 @@ namespace Serein.NodeFlow.Env
{
_ = remoteFlowEnvironment.InvokeTriggerAsync(msgId, state);
}
[AutoSocketHandle(ThemeValue = EnvMsgTheme.ChangeParameter, IsReturnValue = false)]
public void ChangeParameter([UseMsgId] string msgId, bool state)
{
_ = remoteFlowEnvironment.InvokeTriggerAsync(msgId, state);
}

View File

@@ -578,6 +578,22 @@ namespace Serein.NodeFlow.Env
await environment.NotificationNodeValueChangeAsync(nodeGuid, path, value);
}
/// <summary>
/// 增加/减少节点入参可选类型参数的个数
/// </summary>
/// <param name="nodeGuid"></param>
/// <param name="isAdd"></param>
/// <param name="paramIndex"></param>
[AutoSocketHandle(ThemeValue = EnvMsgTheme.ChangeParameter)]
public async Task<object> ChangeParameter(string nodeGuid, bool isAdd, int paramIndex)
{
var result = await environment.ChangeParameter(nodeGuid, isAdd, paramIndex);
return new
{
state = result
};
}
}

View File

@@ -1,9 +1,12 @@
using Serein.Library;
using Newtonsoft.Json.Linq;
using Serein.Library;
using Serein.Library.Api;
using Serein.Library.FlowNode;
using Serein.Library.Utils;
using Serein.NodeFlow.Tool;
using Serein.Script.Node;
using System.Collections.Concurrent;
using System.IO;
using System.Security.AccessControl;
using System.Threading.Channels;
@@ -52,6 +55,10 @@ namespace Serein.NodeFlow.Env
public event NodeConnectChangeHandler OnNodeConnectChange;
public event NodeCreateHandler OnNodeCreate;
public event NodeRemoveHandler OnNodeRemove;
/// <summary>
/// 节点父子关系发生改变事件
/// </summary>
public event NodeContainerChildChangeHandler OnNodeParentChildChange;
public event StartNodeChangeHandler OnStartNodeChange;
public event FlowRunCompleteHandler OnFlowRunComplete;
public event MonitorObjectChangeHandler OnMonitorObjectChange;
@@ -169,165 +176,179 @@ namespace Serein.NodeFlow.Env
}
#endregion
#region
var projectData = flowEnvInfo.Project;
List<(NodeModelBase, string[])> regionChildNodes = new List<(NodeModelBase, string[])>();
List<(NodeModelBase, PositionOfUI)> ordinaryNodes = new List<(NodeModelBase, PositionOfUI)>();
// 加载节点
foreach (var nodeInfo in projectData.Nodes)
{
var controlType = FlowFunc.GetNodeControlType(nodeInfo);
if (controlType == NodeControlType.None)
{
continue;
}
else
{
MethodDetails? methodDetails = null;
if (!string.IsNullOrEmpty(nodeInfo.MethodName))
{
MethodDetailss.TryGetValue(nodeInfo.MethodName, out methodDetails);// 加载远程环境时尝试获取方法信息
}
var nodeModel = FlowFunc.CreateNode(this, controlType, methodDetails); // 加载远程项目时创建节点
nodeModel.LoadInfo(nodeInfo); // 创建节点model
if (nodeModel is null)
{
nodeInfo.Guid = string.Empty;
continue;
}
TryAddNode(nodeModel); // 加载项目时将节点加载到环境中
if (nodeInfo.ChildNodeGuids?.Length > 0)
{
regionChildNodes.Add((nodeModel, nodeInfo.ChildNodeGuids));
UIContextOperation?.Invoke(() => OnNodeCreate?.Invoke(new NodeCreateEventArgs(nodeModel, nodeInfo.Position)));
}
else
{
ordinaryNodes.Add((nodeModel, nodeInfo.Position));
}
}
}
#endregion
#region
// 加载区域子项
foreach ((NodeModelBase region, string[] childNodeGuids) item in regionChildNodes)
{
foreach (var childNodeGuid in item.childNodeGuids)
{
NodeModels.TryGetValue(childNodeGuid, out NodeModelBase? childNode);
if (childNode is null)
{
// 节点尚未加载
continue;
}
// 存在节点
UIContextOperation?.Invoke(() => OnNodeCreate?.Invoke(new NodeCreateEventArgs(childNode, true, item.region.Guid)));
}
}
#endregion
#region
// 加载节点
foreach ((NodeModelBase nodeModel, PositionOfUI position) item in ordinaryNodes)
{
bool IsContinue = false;
foreach ((NodeModelBase region, string[] childNodeGuids) item2 in regionChildNodes)
{
foreach (var childNodeGuid in item2.childNodeGuids)
{
if (item.nodeModel.Guid.Equals(childNodeGuid))
{
IsContinue = true;
}
}
}
if (IsContinue) continue;
//OnNodeCreate?.Invoke(new NodeCreateEventArgs(item.nodeModel, item.position));
UIContextOperation?.Invoke(() => OnNodeCreate?.Invoke(new NodeCreateEventArgs(item.nodeModel, item.position)));
}
#endregion
#region
_ = Task.Run(async () =>
{
await Task.Delay(500);
#region
foreach (var nodeInfo in projectData.Nodes)
{
if (!NodeModels.TryGetValue(nodeInfo.Guid, out NodeModelBase? fromNode))
{
// 不存在对应的起始节点
continue;
}
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 fromNodes)
{
// 遍历当前类型分支的节点(确认连接关系)
foreach (var toNode in item.toNodes)
{
UIContextOperation?.Invoke(() => OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNode.Guid,
toNode.Guid,
JunctionOfConnectionType.Invoke,
item.connectionType,
NodeConnectChangeEventArgs.ConnectChangeType.Create))); // 通知UI连接节点
}
}
}
#endregion
#region
foreach (var toNode in NodeModels.Values)
{
if(toNode.MethodDetails.ParameterDetailss is null)
{
continue;
}
for (var i = 0; i < toNode.MethodDetails.ParameterDetailss.Length; i++)
{
var pd = toNode.MethodDetails.ParameterDetailss[i];
if (!string.IsNullOrEmpty(pd.ArgDataSourceNodeGuid)
&& NodeModels.TryGetValue(pd.ArgDataSourceNodeGuid, out var fromNode))
{
UIContextOperation?.Invoke(() =>
OnNodeConnectChange?.Invoke(
new NodeConnectChangeEventArgs(
fromNode.Guid, // 从哪个节点开始
toNode.Guid, // 连接到那个节点
JunctionOfConnectionType.Arg,
(int)pd.Index, // 连接线的样式类型
pd.ArgDataSourceType,
NodeConnectChangeEventArgs.ConnectChangeType.Create // 是创建连接还是删除连接
))); // 通知UI
}
}
}
#endregion
});
#endregion
SetStartNode(projectData.StartNode); // 设置流程起点
_ = LoadNodeInfosAsync(flowEnvInfo.Project.Nodes.ToList());
SetStartNode(flowEnvInfo.Project.StartNode); // 设置流程起点
UIContextOperation?.Invoke(() =>
{
OnProjectLoaded?.Invoke(new ProjectLoadedEventArgs()); // 加载完成
});
IsLoadingProject = false;
#region
/* #region 加载节点数据,如果是区域控件,提前加载区域
var projectData = flowEnvInfo.Project;
List<(NodeModelBase, string[])> regionChildNodes = new List<(NodeModelBase, string[])>();
List<(NodeModelBase, PositionOfUI)> ordinaryNodes = new List<(NodeModelBase, PositionOfUI)>();
// 加载节点
foreach (var nodeInfo in projectData.Nodes)
{
var controlType = FlowFunc.GetNodeControlType(nodeInfo);
if (controlType == NodeControlType.None)
{
continue;
}
else
{
MethodDetails? methodDetails = null;
if (!string.IsNullOrEmpty(nodeInfo.MethodName))
{
MethodDetailss.TryGetValue(nodeInfo.MethodName, out methodDetails);// 加载远程环境时尝试获取方法信息
}
var nodeModel = FlowFunc.CreateNode(this, controlType, methodDetails); // 加载远程项目时创建节点
nodeModel.LoadInfo(nodeInfo); // 创建节点model
if (nodeModel is null)
{
nodeInfo.Guid = string.Empty;
continue;
}
TryAddNode(nodeModel); // 加载项目时将节点加载到环境中
if (nodeInfo.ChildNodeGuids?.Length > 0)
{
regionChildNodes.Add((nodeModel, nodeInfo.ChildNodeGuids));
UIContextOperation?.Invoke(() => OnNodeCreate?.Invoke(new NodeCreateEventArgs(nodeModel, nodeInfo.Position)));
}
else
{
ordinaryNodes.Add((nodeModel, nodeInfo.Position));
}
}
}
#endregion
#region 加载区域中的节点
// 加载区域子项
//foreach ((NodeModelBase region, string[] childNodeGuids) item in regionChildNodes)
//{
// foreach (var childNodeGuid in item.childNodeGuids)
// {
// NodeModels.TryGetValue(childNodeGuid, out NodeModelBase? childNode);
// if (childNode is null)
// {
// // 节点尚未加载
// continue;
// }
// // 存在节点
// UIContextOperation?.Invoke(() => OnNodeCreate?.Invoke(new NodeCreateEventArgs(childNode, true, item.region.Guid)));
// }
//}
#endregion
#region 加载普通的节点
// 加载节点
foreach ((NodeModelBase nodeModel, PositionOfUI position) item in ordinaryNodes)
{
bool IsContinue = false;
foreach ((NodeModelBase region, string[] childNodeGuids) item2 in regionChildNodes)
{
foreach (var childNodeGuid in item2.childNodeGuids)
{
if (item.nodeModel.Guid.Equals(childNodeGuid))
{
IsContinue = true;
}
}
}
if (IsContinue) continue;
//OnNodeCreate?.Invoke(new NodeCreateEventArgs(item.nodeModel, item.position));
UIContextOperation?.Invoke(() => OnNodeCreate?.Invoke(new NodeCreateEventArgs(item.nodeModel, item.position)));
}
#endregion
#region 确定节点之间的连接关系
_ = Task.Run(async () =>
{
await Task.Delay(500);
#region 连接节点的调用关系
foreach (var nodeInfo in projectData.Nodes)
{
if (!NodeModels.TryGetValue(nodeInfo.Guid, out NodeModelBase? fromNode))
{
// 不存在对应的起始节点
continue;
}
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 fromNodes)
{
// 遍历当前类型分支的节点(确认连接关系)
foreach (var toNode in item.toNodes)
{
UIContextOperation?.Invoke(() => OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNode.Guid,
toNode.Guid,
JunctionOfConnectionType.Invoke,
item.connectionType,
NodeConnectChangeEventArgs.ConnectChangeType.Create))); // 通知UI连接节点
}
}
}
#endregion
#region 连接节点的传参关系
foreach (var toNode in NodeModels.Values)
{
if(toNode.MethodDetails.ParameterDetailss is null)
{
continue;
}
for (var i = 0; i < toNode.MethodDetails.ParameterDetailss.Length; i++)
{
var pd = toNode.MethodDetails.ParameterDetailss[i];
if (!string.IsNullOrEmpty(pd.ArgDataSourceNodeGuid)
&& NodeModels.TryGetValue(pd.ArgDataSourceNodeGuid, out var fromNode))
{
UIContextOperation?.Invoke(() =>
OnNodeConnectChange?.Invoke(
new NodeConnectChangeEventArgs(
fromNode.Guid, // 从哪个节点开始
toNode.Guid, // 连接到那个节点
JunctionOfConnectionType.Arg,
(int)pd.Index, // 连接线的样式类型
pd.ArgDataSourceType,
NodeConnectChangeEventArgs.ConnectChangeType.Create // 是创建连接还是删除连接
))); // 通知UI
}
}
}
#endregion
});
#endregion*/
#endregion
}
private bool TryAddNode(NodeModelBase nodeModel)
{
//nodeModel.Guid ??= Guid.NewGuid().ToString();
@@ -345,69 +366,7 @@ namespace Serein.NodeFlow.Env
return true;
}
private void ConnectNode(NodeModelBase fromNode, NodeModelBase toNode, ConnectionInvokeType connectionType)
{
if (fromNode is null || toNode is null || fromNode == toNode)
{
return;
}
var ToExistOnFrom = true;
var FromExistInTo = true;
ConnectionInvokeType[] ct = [ConnectionInvokeType.IsSucceed,
ConnectionInvokeType.IsFail,
ConnectionInvokeType.IsError,
ConnectionInvokeType.Upstream];
foreach (ConnectionInvokeType ctType in ct)
{
var FToTo = fromNode.SuccessorNodes[ctType].Where(it => it.Guid.Equals(toNode.Guid)).ToArray();
var ToOnF = toNode.PreviousNodes[ctType].Where(it => it.Guid.Equals(fromNode.Guid)).ToArray();
ToExistOnFrom = FToTo.Length > 0;
FromExistInTo = ToOnF.Length > 0;
if (ToExistOnFrom && FromExistInTo)
{
this.WriteLine(InfoType.ERROR, "起始节点已与目标节点存在连接");
//return;
}
else
{
// 检查是否可能存在异常
if (!ToExistOnFrom && FromExistInTo)
{
this.WriteLine(InfoType.ERROR, "目标节点不是起始节点的子节点,起始节点却是目标节点的父节点");
return;
}
else if (ToExistOnFrom && !FromExistInTo)
{
//
this.WriteLine(InfoType.ERROR, " 起始节点不是目标节点的父节点,目标节点却是起始节点的子节点");
return;
}
else // if (!ToExistOnFrom && !FromExistInTo)
{
// 可以正常连接
}
}
fromNode.SuccessorNodes[connectionType].Add(toNode); // 添加到起始节点的子分支
toNode.PreviousNodes[connectionType].Add(fromNode); // 添加到目标节点的父分支
OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNode.Guid,
toNode.Guid,
JunctionOfConnectionType.Invoke,
connectionType,
NodeConnectChangeEventArgs.ConnectChangeType.Create)); // 通知UI
}
}
public async Task<FlowEnvInfo> GetEnvInfoAsync()
{
var envInfo = await msgClient.SendAndWaitDataAsync<FlowEnvInfo>(EnvMsgTheme.GetEnvInfo);
@@ -491,16 +450,16 @@ namespace Serein.NodeFlow.Env
{
nodeGuid
});
//UIContextOperation?.Invoke(() => OnStartNodeChange?.Invoke(new StartNodeChangeEventArgs(nodeGuid,nodeGuid)));
UIContextOperation?.Invoke(() => OnStartNodeChange?.Invoke(new StartNodeChangeEventArgs(nodeGuid,nodeGuid)));
}
public async Task<object> InvokeNodeAsync(IDynamicContext context, string nodeGuid)
{
this.WriteLine(InfoType.INFO, "远程环境尚未实现接口 InvokeNodeAsync");
_ = msgClient.SendAsync(EnvMsgTheme.SetStartNode, new
{
nodeGuid
});
//_ = msgClient.SendAsync(EnvMsgTheme.InvokeNodeAsync, new
//{
// nodeGuid
//});
return null;
}
@@ -716,7 +675,133 @@ namespace Serein.NodeFlow.Env
/// <returns></returns>
public async Task LoadNodeInfosAsync(List<NodeInfo> nodeInfos)
{
this.WriteLine(InfoType.WARN, "远程环境尚未实现的接口(重要,会尽快实现)LoadNodeInfoAsync");
List<NodeInfo> needPlaceNodeInfos = [];
#region NodeInfo创建NodeModel
foreach (NodeInfo? nodeInfo in nodeInfos)
{
if (!EnumHelper.TryConvertEnum<NodeControlType>(nodeInfo.Type, out var controlType))
{
continue;
}
#region
MethodDetails? methodDetails = null;
if (string.IsNullOrEmpty(nodeInfo.MethodName))
{
methodDetails = new MethodDetails();
}
else
{
if (string.IsNullOrEmpty(nodeInfo.MethodName))
{
continue;
}
MethodDetailss.TryGetValue(nodeInfo.MethodName, out methodDetails);// 加载远程环境时尝试获取方法信息
}
#endregion
var nodeModel = FlowFunc.CreateNode(this, controlType, methodDetails); // 加载项目时创建节点
if (nodeModel is null)
{
nodeInfo.Guid = string.Empty;
continue;
}
nodeModel.LoadInfo(nodeInfo); // 创建节点model
TryAddNode(nodeModel); // 加载项目时将节点加载到环境中
if (!string.IsNullOrEmpty(nodeInfo.ParentNodeGuid) &&
NodeModels.TryGetValue(nodeInfo.ParentNodeGuid, out var parentNode))
{
needPlaceNodeInfos.Add(nodeInfo); // 需要重新放置的节点
}
UIContextOperation?.Invoke(() =>
OnNodeCreate?.Invoke(new NodeCreateEventArgs(nodeModel, nodeInfo.Position))); // 添加到UI上
}
#endregion
#region
foreach (NodeInfo nodeInfo in needPlaceNodeInfos)
{
if (NodeModels.TryGetValue(nodeInfo.Guid, out var childNode) &&
NodeModels.TryGetValue(nodeInfo.ParentNodeGuid, out var parentNode))
{
childNode.ParentNode = parentNode;
parentNode.ChildrenNode.Add(childNode);
UIContextOperation?.Invoke(() => OnNodeParentChildChange?.Invoke(
new NodeContainerChildChangeEventArgs(childNode.Guid, parentNode.Guid,
NodeContainerChildChangeEventArgs.Type.Place)));
}
}
#endregion
_ = Task.Run(async () =>
{
await Task.Delay(100);
#region
foreach (var nodeInfo in nodeInfos)
{
if (!NodeModels.TryGetValue(nodeInfo.Guid, out NodeModelBase? fromNode))
{
// 不存在对应的起始节点
continue;
}
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 fromNodes)
{
// 遍历当前类型分支的节点(确认连接关系)
foreach (var toNode in item.toNodes)
{
UIContextOperation?.Invoke(() => OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNode.Guid,
toNode.Guid,
JunctionOfConnectionType.Invoke,
item.connectionType,
NodeConnectChangeEventArgs.ConnectChangeType.Create))); // 通知UI连接节点
}
}
}
#endregion
#region
foreach (var toNode in NodeModels.Values)
{
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)
&& NodeModels.TryGetValue(pd.ArgDataSourceNodeGuid, out var fromNode))
{
UIContextOperation?.Invoke(() =>
OnNodeConnectChange?.Invoke(
new NodeConnectChangeEventArgs(
fromNode.Guid, // 从哪个节点开始
toNode.Guid, // 连接到那个节点
JunctionOfConnectionType.Arg,
(int)pd.Index, // 连接线的样式类型
pd.ArgDataSourceType,
NodeConnectChangeEventArgs.ConnectChangeType.Create // 是创建连接还是删除连接
))); // 通知UI
}
}
}
#endregion
});
UIContextOperation?.Invoke(() => OnProjectLoaded?.Invoke(new ProjectLoadedEventArgs()));
}
@@ -756,6 +841,21 @@ namespace Serein.NodeFlow.Env
});
return nodeInfo;
}
/// <summary>
/// 将节点放置在容器中/从容器中取出
/// </summary>
/// <param name="childNodeGuid">子节点(主要节点)</param>
/// <param name="parentNodeGuid">父节点</param>
/// <param name="isPlace">是否组合(反之为分解节点组合关系)</param>
/// <returns></returns>
public async Task<bool> ChangeNodeContainerChild(string childNodeGuid, string parentNodeGuid, bool isAssembly)
{
this.WriteLine(InfoType.WARN, "远程环境尚未实现的接口(重要,会尽快实现)ChangeNodeParentChild");
return false;
}
public async Task<bool> RemoveNodeAsync(string nodeGuid)
{
var result = await msgClient.SendAndWaitDataAsync<bool>(EnvMsgTheme.RemoveNode, new
@@ -875,7 +975,6 @@ namespace Serein.NodeFlow.Env
public void NodeLocated(string nodeGuid)
{
//Console.WriteLine("远程环境尚未实现的接口NodeLocated");
UIContextOperation?.Invoke(() => OnNodeLocated?.Invoke(new NodeLocatedEventArgs(nodeGuid)));
}
@@ -886,8 +985,7 @@ namespace Serein.NodeFlow.Env
{
return;
}
this.WriteLine(InfoType.INFO, $"通知远程环境修改节点数据:{nodeGuid},name:{path},value:{value}");
//this.WriteLine(InfoType.INFO, $"通知远程环境修改节点数据:{nodeGuid},name:{path},value:{value}");
_ = msgClient.SendAsync(EnvMsgTheme.ValueNotification, new
{
nodeGuid = nodeGuid,
@@ -906,8 +1004,32 @@ namespace Serein.NodeFlow.Env
/// <returns></returns>
public async Task<bool> ChangeParameter(string nodeGuid, bool isAdd, int paramIndex)
{
this.WriteLine(InfoType.INFO, "远程环境尚未实现的接口ChangeParameter");
return false;
if (IsLoadingProject || IsLoadingNode)
{
return false;
}
if (!NodeModels.TryGetValue(nodeGuid,out var nodeModel))
{
return false;
}
//this.WriteLine(InfoType.INFO, $"通知远程环境修改节点可选数据:{nodeGuid},isAdd:{isAdd},paramIndex:{paramIndex}");
var result = await msgClient.SendAndWaitDataAsync<bool>(EnvMsgTheme.ChangeParameter, new
{
nodeGuid = nodeGuid,
isAdd = isAdd,
paramIndex = paramIndex,
});
if (result) {
if (isAdd)
{
nodeModel.MethodDetails.AddParamsArg(paramIndex);
}
else
{
nodeModel.MethodDetails.RemoveParamsArg(paramIndex);
}
}
return result;
}
#region

View File

@@ -71,36 +71,36 @@ namespace Serein.NodeFlow
/// <summary>
/// 从节点信息读取节点类型
/// </summary>
/// <param name="nodeInfo"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public static NodeControlType GetNodeControlType(NodeInfo nodeInfo)
{
if(!EnumHelper.TryConvertEnum<NodeControlType>(nodeInfo.Type, out var controlType))
{
return NodeControlType.None;
}
return controlType;
// 创建控件实例
//NodeControlType controlType = nodeInfo.Type switch
//{
// $"{NodeStaticConfig.NodeSpaceName}.{nameof(SingleActionNode)}" => NodeControlType.Action,// 动作节点控件
// $"{NodeStaticConfig.NodeSpaceName}.{nameof(SingleFlipflopNode)}" => NodeControlType.Flipflop, // 触发器节点控件
///// <summary>
///// 从节点信息读取节点类型
///// </summary>
///// <param name="nodeInfo"></param>
///// <returns></returns>
///// <exception cref="NotImplementedException"></exception>
//public static NodeControlType GetNodeControlType(NodeInfo nodeInfo)
//{
// if(!EnumHelper.TryConvertEnum<NodeControlType>(nodeInfo.Type, out var controlType))
// {
// return NodeControlType.None;
// }
// return controlType;
// // 创建控件实例
// //NodeControlType controlType = nodeInfo.Type switch
// //{
// // $"{NodeStaticConfig.NodeSpaceName}.{nameof(SingleActionNode)}" => NodeControlType.Action,// 动作节点控件
// // $"{NodeStaticConfig.NodeSpaceName}.{nameof(SingleFlipflopNode)}" => NodeControlType.Flipflop, // 触发器节点控件
// $"{NodeStaticConfig.NodeSpaceName}.{nameof(SingleConditionNode)}" => NodeControlType.ExpCondition,// 条件表达式控件
// $"{NodeStaticConfig.NodeSpaceName}.{nameof(SingleExpOpNode)}" => NodeControlType.ExpOp, // 操作表达式控件
// // $"{NodeStaticConfig.NodeSpaceName}.{nameof(SingleConditionNode)}" => NodeControlType.ExpCondition,// 条件表达式控件
// // $"{NodeStaticConfig.NodeSpaceName}.{nameof(SingleExpOpNode)}" => NodeControlType.ExpOp, // 操作表达式控件
// $"{NodeStaticConfig.NodeSpaceName}.{nameof(CompositeConditionNode)}" => NodeControlType.ConditionRegion, // 条件区域控件
// // $"{NodeStaticConfig.NodeSpaceName}.{nameof(CompositeConditionNode)}" => NodeControlType.ConditionRegion, // 条件区域控件
// $"{NodeStaticConfig.NodeSpaceName}.{nameof(SingleGlobalDataNode)}" => NodeControlType.GlobalData, // 数据节点
// $"{NodeStaticConfig.NodeSpaceName}.{nameof(SingleScriptNode)}" => NodeControlType.Script, // 数据节点
// _ => NodeControlType.None,
//};
//return controlType;
}
// // $"{NodeStaticConfig.NodeSpaceName}.{nameof(SingleGlobalDataNode)}" => NodeControlType.GlobalData, // 数据节点
// // $"{NodeStaticConfig.NodeSpaceName}.{nameof(SingleScriptNode)}" => NodeControlType.Script, // 数据节点
// // _ => NodeControlType.None,
// //};
// //return controlType;
//}
/// <summary>
/// 程序集封装依赖

View File

@@ -37,6 +37,11 @@ namespace Serein.NodeFlow.Model
public partial class SingleConditionNode : NodeModelBase
{
/// <summary>
/// 条件表达式节点是基础节点
/// </summary>
public override bool IsBase => true;
/// <summary>
/// 表达式参数索引
/// </summary>

View File

@@ -26,6 +26,11 @@ namespace Serein.NodeFlow.Model
public partial class SingleExpOpNode : NodeModelBase
{
/// <summary>
/// 表达式节点是基础节点
/// </summary>
public override bool IsBase => true;
/// <summary>
/// 表达式参数索引
/// </summary>

View File

@@ -31,8 +31,17 @@ namespace Serein.NodeFlow.Model
/// <summary>
/// 全局数据节点
/// </summary>
public partial class SingleGlobalDataNode : NodeModelBase
public partial class SingleGlobalDataNode : NodeModelBase, INodeContainer
{
/// <summary>
/// 全局数据节点是基础节点
/// </summary>
public override bool IsBase => true;
/// <summary>
/// 数据源只允许放置1个节点。
/// </summary>
public override int MaxChildrenCount => 1;
public SingleGlobalDataNode(IFlowEnvironment environment) : base(environment)
{
}
@@ -40,16 +49,33 @@ namespace Serein.NodeFlow.Model
/// <summary>
/// 数据来源的节点
/// </summary>
private string? DataNodeGuid;
private NodeModelBase? DataNode;
public void PlaceNode(NodeModelBase nodeModel)
{
_ = this.Env.RemoveNodeAsync(DataNode?.Guid);
DataNode = nodeModel;
}
public void TakeOutAll()
{
DataNode = null;
}
public void TakeOutNode(NodeModelBase nodeModel)
{
DataNode = null;
}
/// <summary>
/// 设置数据节点
/// </summary>
/// <param name="dataNode"></param>
public void SetDataNode(NodeModelBase dataNode)
{
DataNodeGuid = dataNode.Guid;
}
//public void SetDataNode(NodeModelBase dataNode)
//{
// DataNodeGuid = dataNode.Guid;
//}
private void ChangeName(string newName)
{
@@ -73,7 +99,7 @@ namespace Serein.NodeFlow.Model
SereinEnv.WriteLine(InfoType.ERROR, $"全局数据的KeyName不能为空[{this.Guid}]");
return null;
}
if (DataNodeGuid == null)
if (DataNode is null)
{
context.NextOrientation = ConnectionInvokeType.IsError;
SereinEnv.WriteLine(InfoType.ERROR, $"全局数据节点没有设置数据来源[{this.Guid}]");
@@ -82,7 +108,7 @@ namespace Serein.NodeFlow.Model
try
{
var result = await context.Env.InvokeNodeAsync(context, DataNodeGuid);
var result = await context.Env.InvokeNodeAsync(context, DataNode.Guid);
SereinEnv.AddOrUpdateFlowGlobalData(KeyName, result);
return result;
}
@@ -102,18 +128,9 @@ namespace Serein.NodeFlow.Model
public override NodeInfo SaveCustomData(NodeInfo nodeInfo)
{
dynamic data = new ExpandoObject();
nodeInfo.CustomData = data;
data.KeyName = KeyName; // 变量名称
if (string.IsNullOrEmpty(DataNodeGuid))
{
return nodeInfo;
}
data.DataNodeGuid = DataNodeGuid; // 数据节点Guid
nodeInfo.ChildNodeGuids = [DataNodeGuid];
nodeInfo.CustomData = data;
return nodeInfo;
}
@@ -124,7 +141,6 @@ namespace Serein.NodeFlow.Model
public override void LoadCustomData(NodeInfo nodeInfo)
{
KeyName = nodeInfo.CustomData?.KeyName;
DataNodeGuid = nodeInfo.CustomData?.DataNodeGuid;
}
/// <summary>
@@ -133,7 +149,7 @@ namespace Serein.NodeFlow.Model
public override void Remove()
{
// 移除数据节点
_ = this.Env.RemoveNodeAsync(DataNodeGuid);
_ = this.Env.RemoveNodeAsync(DataNode?.Guid);
}
}

View File

@@ -28,6 +28,13 @@ namespace Serein.NodeFlow.Model
/// </summary>
public partial class SingleScriptNode : NodeModelBase
{
/// <summary>
/// 脚本节点是基础节点
/// </summary>
public override bool IsBase => true;
private IScriptFlowApi ScriptFlowApi { get; }
private ASTNode mainNode;