From 345fee39ba8fc6381d0beb0357e49005a29bc0c6 Mon Sep 17 00:00:00 2001 From: fengjiayi <12821976+ning_xi@user.noreply.gitee.com> Date: Fri, 4 Jul 2025 11:35:34 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96LocalFlowEnviromment(1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- NodeFlow/Env/LocalFlowEnvironment.cs | 1408 ++++++----------- NodeFlow/FlowNodeExtension.cs | 2 +- NodeFlow/Model/Node/SingleActionNode.cs | 2 +- NodeFlow/Model/Node/SingleFlipflopNode.cs | 2 +- NodeFlow/Model/Node/SingleUINode.cs | 2 +- .../ChangeNodeConnectionOperation.cs | 2 +- .../Model/Operation/CreateNodeOperation.cs | 2 +- NodeFlow/Services/FlowModelService.cs | 4 +- NodeFlow/Services/FlowOperationService.cs | 2 +- NodeFlow/Services/FlowWorkManagement.cs | 2 +- NodeFlow/Tool/FlowLibraryManagement.cs | 2 +- .../ViewModel/ActionNodeControlViewModel.cs | 2 +- .../ViewModel/FlipflopNodeControlViewModel.cs | 2 +- .../Node/ViewModel/UINodeControlViewModel.cs | 2 +- 14 files changed, 492 insertions(+), 944 deletions(-) diff --git a/NodeFlow/Env/LocalFlowEnvironment.cs b/NodeFlow/Env/LocalFlowEnvironment.cs index 236d219..a9a54e1 100644 --- a/NodeFlow/Env/LocalFlowEnvironment.cs +++ b/NodeFlow/Env/LocalFlowEnvironment.cs @@ -4,6 +4,8 @@ using Serein.Library.FlowNode; using Serein.Library.Utils; using Serein.Library.Utils.SereinExpression; using Serein.NodeFlow.Model; +using Serein.NodeFlow.Model.Operation; +using Serein.NodeFlow.Services; using Serein.NodeFlow.Tool; using System; using System.Collections.Specialized; @@ -12,81 +14,55 @@ using System.Net.Http.Headers; using System.Net.Mime; using System.Reactive; using System.Reflection; +using System.Security.AccessControl; using System.Text; namespace Serein.NodeFlow.Env { - public class ADmmm - { - private readonly IFlowEnvironment flowEnvironment; - private readonly IFlowEnvironmentEvent flowEnvironmentEvent; - public ADmmm(IFlowEnvironment flowEnvironment, IFlowEnvironmentEvent flowEnvironmentEvent) - { - this.flowEnvironment = flowEnvironment; - this.flowEnvironmentEvent = flowEnvironmentEvent; - - - } - - } - - - /// /// 运行环境 /// - public class LocalFlowEnvironment : IFlowEnvironment/*, IFlowEnvironmentEvent*/ + internal partial class LocalFlowEnvironment : IFlowEnvironment/*, IFlowEnvironmentEvent*/ { /// /// 节点的命名空间 /// public const string SpaceName = $"{nameof(Serein)}.{nameof(NodeFlow)}.{nameof(Model)}"; - public const string ThemeKey = "theme"; + /*public const string ThemeKey = "theme"; public const string DataKey = "data"; public const string MsgIdKey = "msgid"; - + */ /// /// 流程运行环境 /// - public LocalFlowEnvironment(IFlowEnvironmentEvent flowEnvironmentEvent) + public LocalFlowEnvironment(IFlowEnvironmentEvent flowEnvironmentEvent, + FlowLibraryManagement flowLibraryManagement, + FlowOperationService flowOperationService, + NodeMVVMService nodeMVVMService) { - this.sereinIOC = new SereinIOC(); this.Event = flowEnvironmentEvent; + this.NodeMVVMManagement = nodeMVVMService; + this.flowOperationService = flowOperationService; this.IsGlobalInterrupt = false; - this.flowTaskManagement = null; - this.sereinIOC.OnIOCMembersChanged += e => - { - if (OperatingSystem.IsWindows()) - { - UIContextOperation?.Invoke(() => Event.OnIOCMembersChanged(e)); // 监听IOC容器的注册 - } + this.FlowLibraryManagement = flowLibraryManagement; + InitNodeMVVM(); + } - }; - this.FlowLibraryManagement = new FlowLibraryManagement(this); // 实例化类库管理 - this.NodeMVVMManagement = new NodeMVVMManagement(); - #region 注册基本节点类型 + /// + /// 注册基本节点类型 + /// + private void InitNodeMVVM() + { NodeMVVMManagement.RegisterModel(NodeControlType.UI, typeof(SingleUINode)); // 动作节点 - NodeMVVMManagement.RegisterModel(NodeControlType.Action, typeof(SingleActionNode)); // 动作节点 NodeMVVMManagement.RegisterModel(NodeControlType.Flipflop, typeof(SingleFlipflopNode)); // 触发器节点 NodeMVVMManagement.RegisterModel(NodeControlType.ExpOp, typeof(SingleExpOpNode)); // 表达式节点 NodeMVVMManagement.RegisterModel(NodeControlType.ExpCondition, typeof(SingleConditionNode)); // 条件表达式节点 - //NodeMVVMManagement.RegisterModel(NodeControlType.ConditionRegion, typeof(CompositeConditionNode)); // 条件区域 NodeMVVMManagement.RegisterModel(NodeControlType.GlobalData, typeof(SingleGlobalDataNode)); // 全局数据节点 NodeMVVMManagement.RegisterModel(NodeControlType.Script, typeof(SingleScriptNode)); // 脚本节点 NodeMVVMManagement.RegisterModel(NodeControlType.NetScript, typeof(SingleNetScriptNode)); // 脚本节点 NodeMVVMManagement.RegisterModel(NodeControlType.FlowCall, typeof(SingleFlowCallNode)); // 流程调用节点 - #endregion - - #region 注册基本服务类 - PersistennceInstance.Add(typeof(FlowInterruptTool), new FlowInterruptTool()); // 缓存流程实例 - PersistennceInstance.Add(typeof(IFlowEnvironment), (LocalFlowEnvironment)this); // 缓存流程实例 - PersistennceInstance.Add(typeof(ISereinIOC), this); // 缓存容器服务 - - ReRegisterPersistennceInstance(); - - #endregion } @@ -94,7 +70,7 @@ namespace Serein.NodeFlow.Env #region 远程管理 - private MsgControllerOfServer clientMsgManage; + //private MsgControllerOfServer clientMsgManage; /// /// 表示是否正在控制远程 @@ -108,12 +84,12 @@ namespace Serein.NodeFlow.Env /// public async Task StartRemoteServerAsync(int port = 7525) { - if (clientMsgManage is null) + /*if (clientMsgManage is null) { clientMsgManage = new MsgControllerOfServer(this); //clientMsgManage = new MsgControllerOfServer(this,"123456"); } - _ = clientMsgManage.StartRemoteServerAsync(port); + _ = clientMsgManage.StartRemoteServerAsync(port);*/ } /// @@ -121,14 +97,14 @@ namespace Serein.NodeFlow.Env /// public void StopRemoteServer() { - try + /*try { clientMsgManage.StopRemoteServer(); } catch (Exception ex) { SereinEnv.WriteLine(InfoType.ERROR, "结束远程管理异常:" + ex); - } + }*/ } #endregion @@ -248,10 +224,12 @@ namespace Serein.NodeFlow.Env /// public UIContextOperation UIContextOperation { get; private set; } + /// - /// 节点视图模型管理类 + /// 节点MVVM管理服务 /// - public NodeMVVMManagement NodeMVVMManagement { get; set; } + public NodeMVVMService NodeMVVMManagement { get; private set; } + /// /// 信息输出等级 @@ -296,11 +274,11 @@ namespace Serein.NodeFlow.Env { get { - if (ioc is null) + if (flowRunIOC is null) { - ioc = new SereinIOC(); + flowRunIOC = new SereinIOC(); } - return ioc; + return flowRunIOC; } } @@ -309,9 +287,9 @@ namespace Serein.NodeFlow.Env #region 私有变量 /// - /// IOC容器 + /// 流程运行时的IOC容器 /// - private ISereinIOC ioc; + private ISereinIOC flowRunIOC; /// /// 通过程序集名称管理动态加载的程序集,用于节点创建提供方法描述,流程运行时提供Emit委托 @@ -319,14 +297,9 @@ namespace Serein.NodeFlow.Env private readonly FlowLibraryManagement FlowLibraryManagement; /// - /// IOC对象容器管理 + /// 流程节点操作服务 /// - private readonly SereinIOC sereinIOC; - - /// - /// 本地运行环境缓存的持久化实例 - /// - private Dictionary PersistennceInstance { get; } = new Dictionary(); + private readonly FlowOperationService flowOperationService; /// /// 环境加载的节点集合 @@ -345,6 +318,7 @@ namespace Serein.NodeFlow.Env private List FlipflopNodes { get; } = []; + /// /// 流程任务管理 /// @@ -536,7 +510,7 @@ namespace Serein.NodeFlow.Env /// public void ActivateFlipflopNode(string nodeGuid) { - if (!TryGetNodeModel(nodeGuid, out var nodeModel)) + /*if (!TryGetNodeModel(nodeGuid, out var nodeModel)) { return; } @@ -549,7 +523,7 @@ namespace Serein.NodeFlow.Env _ = flowTaskManagement.RunGlobalFlipflopAsync(this, flipflopNode);// 被父节点移除连接关系的子节点若为触发器,且无上级节点,则当前流程正在运行,则加载到运行环境中 } - } + }*/ } /// @@ -558,7 +532,7 @@ namespace Serein.NodeFlow.Env /// public void TerminateFlipflopNode(string nodeGuid) { - if (!TryGetNodeModel(nodeGuid, out var nodeModel)) + /* if (!TryGetNodeModel(nodeGuid, out var nodeModel)) { return; } @@ -566,7 +540,7 @@ namespace Serein.NodeFlow.Env if (flowTaskManagement is not null && nodeModel is SingleFlipflopNode flipflopNode) // 子节点为触发器 { flowTaskManagement.TerminateGlobalFlipflopRuning(flipflopNode); - } + }*/ } /// @@ -633,7 +607,7 @@ namespace Serein.NodeFlow.Env // 加载画布 foreach (var canvasInfo in projectData.Canvass) { - await SetStartNodeAsync(canvasInfo.Guid, canvasInfo.StartNode); // 设置起始节点 + SetStartNode(canvasInfo.Guid, canvasInfo.StartNode); // 设置起始节点 } //await SetStartNodeAsync("", projectData.StartNode); // 设置起始节点 }); @@ -660,9 +634,9 @@ namespace Serein.NodeFlow.Env Addres = addres, Port = port, Token = token, - ThemeJsonKey = LocalFlowEnvironment.ThemeKey, + /*ThemeJsonKey = LocalFlowEnvironment.ThemeKey, MsgIdJsonKey = LocalFlowEnvironment.MsgIdKey, - DataJsonKey = LocalFlowEnvironment.DataKey, + DataJsonKey = LocalFlowEnvironment.DataKey,*/ }; var remoteMsgUtil = new RemoteMsgUtil(controlConfiguration); var result = await remoteMsgUtil.ConnectAsync(); @@ -843,29 +817,6 @@ namespace Serein.NodeFlow.Env private int _addCanvasCount = 0; - /// - /// 增加画布 - /// - /// 画布名称 - /// 宽度 - /// 高度 - /// - public async Task CreateCanvasAsync(string canvasName, int width, int height) - { - var info = new FlowCanvasDetailsInfo() - { - Guid = Guid.NewGuid().ToString(), - Height = height, - Width = width, - ViewX = 0, - ViewY = 0, - ScaleY = 1, - ScaleX = 1, - Name = !string.IsNullOrWhiteSpace(canvasName) ? canvasName : $"流程图{_addCanvasCount++}", - }; - var model = LoadCanvas(info); - return info; - } private FlowCanvasDetails LoadCanvas(FlowCanvasDetailsInfo info) { @@ -879,549 +830,6 @@ namespace Serein.NodeFlow.Env return model; } - /// - /// 删除画布 - /// - /// 画布Guid - /// - public async Task RemoveCanvasAsync(string canvasGuid) - { - - if (!FlowCanvass.TryGetValue(canvasGuid, out var model)) - { - return false; - } - var count = NodeModels.Values.Count(node => node.CanvasDetails.Guid.Equals(canvasGuid)); - if (count > 0) - { - SereinEnv.WriteLine(InfoType.WARN, "无法删除具有节点的画布"); - return false; - } - if (FlowCanvass.Remove(canvasGuid)) - { - UIContextOperation?.Invoke(() => - { - Event.OnCanvasRemoved(new CanvasRemoveEventArgs(canvasGuid)); - }); - return true; - } - - return false; - } - - - /// - /// 从节点信息集合批量加载节点控件 - /// - /// 节点信息 - /// - /// - public async Task LoadNodeInfosAsync(List nodeInfos) - { - #region 从NodeInfo创建NodeModel - // 流程接口节点最后才创建 - - List 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 needPlaceNodeInfos = []; - foreach (NodeInfo? nodeInfo in nodeInfos) - { - if (!string.IsNullOrEmpty(nodeInfo.ParentNodeGuid) && - NodeModels.TryGetValue(nodeInfo.ParentNodeGuid, out var parentNode)) - { - needPlaceNodeInfos.Add(nodeInfo); // 需要重新放置的节点 - } - } - - foreach (NodeInfo nodeInfo in needPlaceNodeInfos) - { - if (NodeModels.TryGetValue(nodeInfo.Guid, out var nodeModel) && - NodeModels.TryGetValue(nodeInfo.ParentNodeGuid, out var containerNode) - && containerNode is INodeContainer nodeContainer) - { - var result = nodeContainer.PlaceNode(nodeModel); - if (result) - { - UIContextOperation?.Invoke(() => Event.OnNodePlace( - new NodePlaceEventArgs(nodeInfo.CanvasGuid, nodeModel.Guid, containerNode.Guid))); - } - - - } - } - #endregion - - #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; - } - ; - 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 确定节点之间的参数调用关系 - foreach (var toNode in NodeModels.Values) - { - 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) - && NodeModels.TryGetValue(pd.ArgDataSourceNodeGuid, out var fromNode)) - { - - await ConnectArgSourceOfNodeAsync(canvasGuid, fromNode, toNode, pd.ArgDataSourceType, pd.Index); - } - } - } - #endregion - - - UIContextOperation?.Invoke(() => - { - Event.OnProjectLoaded(new ProjectLoadedEventArgs()); - }); - - return; - } - - /// - /// 流程正在运行时创建节点 - /// - /// 所属画布 - /// 所属类型 - /// 所处位置 - /// 如果是表达式节点条件节点,该项为null - public Task CreateNodeAsync(string canvasGuid, - NodeControlType nodeControlType, - PositionOfUI position, - MethodDetailsInfo? methodDetailsInfo = null) - { - if (!TryGetCanvasModel(canvasGuid, out var canvasModel)) - { - return Task.FromResult(null); - } - IFlowNode? nodeModel; - if (methodDetailsInfo is null - || string.IsNullOrEmpty(methodDetailsInfo.AssemblyName) - || string.IsNullOrEmpty(methodDetailsInfo.MethodName)) - { - nodeModel = FlowNodeExtension.CreateNode(this, nodeControlType); // 加载基础节点 - } - else - { - if (FlowLibraryManagement.TryGetMethodDetails(methodDetailsInfo.AssemblyName, // 创建节点 - methodDetailsInfo.MethodName, - out var methodDetails)) - { - nodeModel = FlowNodeExtension.CreateNode(this, nodeControlType, methodDetails); // 一般的加载节点方法 - } - else - { - return Task.FromResult(null); - } - } - nodeModel.CanvasDetails = canvasModel; - canvasModel.Nodes.Add(nodeModel); // 节点与画布互相绑定 - TryAddNode(nodeModel); - nodeModel.Position = position; // 设置位置 - - // 通知UI更改 - UIContextOperation?.Invoke(() => Event.OnNodeCreated(new NodeCreateEventArgs(canvasGuid, nodeModel, position))); - var nodeInfo = nodeModel.ToInfo(); - return Task.FromResult(nodeInfo); - } - - - /// - /// 将节点放置在容器中 - /// - /// - public Task PlaceNodeToContainerAsync(string canvasGuid, - string nodeGuid, string containerNodeGuid) - { - if (!FlowCanvass.ContainsKey(canvasGuid)) - { - return Task.FromResult(false); - } - // 获取目标节点与容器节点 - if (!TryGetNodeModel(nodeGuid, out var nodeModel)) - { - return Task.FromResult(false); - } - if (nodeModel.ContainerNode is INodeContainer tmpContainer) - { - SereinEnv.WriteLine(InfoType.WARN, $"节点放置失败,节点[{nodeGuid}]已经放置于容器节点[{((IFlowNode)tmpContainer).Guid}]"); - return Task.FromResult(false); - } - - if (!TryGetNodeModel(containerNodeGuid, out var containerNode)) - { - return Task.FromResult(false); - } - if (containerNode is not INodeContainer nodeContainer) return Task.FromResult(false); - - var result = nodeContainer.PlaceNode(nodeModel); // 放置在容器节点 - if (result) - { - UIContextOperation?.Invoke(() => - { - Event.OnNodePlace(new NodePlaceEventArgs(canvasGuid, nodeGuid, containerNodeGuid)); // 通知UI更改节点放置位置 - }); - } - return Task.FromResult(result); - - } - - /// - /// 将节点从容器节点中脱离 - /// - /// - public Task TakeOutNodeToContainerAsync(string canvasGuid, - string nodeGuid) - { - if (!FlowCanvass.ContainsKey(canvasGuid)) - { - return Task.FromResult(false); - } - // 获取目标节点与容器节点 - if (!TryGetNodeModel(nodeGuid, out var nodeModel)) - { - return Task.FromResult(false); - } - if (nodeModel.ContainerNode is not INodeContainer nodeContainer) - { - return Task.FromResult(false); - } - var result = nodeContainer.TakeOutNode(nodeModel); // 从容器节点取出 - if (result) - { - UIContextOperation?.Invoke(() => - { - Event.OnNodeTakeOut(new NodeTakeOutEventArgs(canvasGuid, nodeGuid)); // 重新放置在画布上 - }); - } - return Task.FromResult(result); - - - } - - - - /// - /// 移除节点 - /// - /// - /// - public async Task RemoveNodeAsync(string canvasGuid, string nodeGuid) - { - if (!TryGetCanvasModel(canvasGuid, out var canvasModel)) - { - return false; - } - if (!TryGetNodeModel(nodeGuid, out var remoteNode)) - { - return false; - } - - if (remoteNode is SingleFlipflopNode flipflopNode) - { - flowTaskManagement?.TerminateGlobalFlipflopRuning(flipflopNode); // 假设被移除的是全局触发器,尝试从启动器移除 - } - - remoteNode.Remove(); // 调用节点的移除方法 - - // 遍历所有前置节点,从那些前置节点中的后继节点集合移除该节点 - foreach (var pnc in remoteNode.PreviousNodes) - { - var pCType = pnc.Key; // 连接类型 - for (int i = 0; i < pnc.Value.Count; i++) - { - IFlowNode? pNode = pnc.Value[i]; - pNode.SuccessorNodes[pCType].Remove(remoteNode); - - UIContextOperation?.Invoke(() => Event.OnNodeConnectChanged(new NodeConnectChangeEventArgs( - canvasGuid, - pNode.Guid, - remoteNode.Guid, - JunctionOfConnectionType.Invoke, - pCType, // 对应的连接关系 - NodeConnectChangeEventArgs.ConnectChangeType.Remove))); // 通知UI - - } - } - - - if (remoteNode.ControlType == NodeControlType.FlowCall) - { - - } - else - { - // 遍历所有后继节点,从那些后继节点中的前置节点集合移除该节点 - foreach (var snc in remoteNode.SuccessorNodes) - { - var connectionType = snc.Key; // 连接类型 - for (int i = 0; i < snc.Value.Count; i++) - { - IFlowNode? toNode = snc.Value[i]; - - await RemoteConnectAsync(canvasGuid, remoteNode, toNode, connectionType); - - } - } - - } - - - - // 从集合中移除节点,解除与画布的绑定关系 - NodeModels.Remove(nodeGuid); - UIContextOperation?.Invoke(() => canvasModel.Nodes.Remove(remoteNode)); - - UIContextOperation?.Invoke(() => Event.OnNodeRemoved(new NodeRemoveEventArgs(canvasGuid, nodeGuid))); - return true; - } - - /// - /// 连接节点,创建方法调用关系 - /// - /// 起始节点 - /// 目标节点 - /// 起始节点控制点 - /// 目标节点控制点 - /// 连接关系 - public Task ConnectInvokeNodeAsync(string canvasGuid, - string fromNodeGuid, - string toNodeGuid, - JunctionType fromNodeJunctionType, - JunctionType toNodeJunctionType, - ConnectionInvokeType invokeType) - { - - // 获取起始节点与目标节点 - if (!FlowCanvass.ContainsKey(canvasGuid) || !TryGetNodeModel(fromNodeGuid, out var fromNode) || !TryGetNodeModel(toNodeGuid, out var toNode)) - { - return Task.FromResult(false); - } - - if (fromNode is null || toNode is null) return Task.FromResult(false); - (var type, var state) = CheckConnect(fromNode, toNode, fromNodeJunctionType, toNodeJunctionType); - if (!state) - { - SereinEnv.WriteLine(InfoType.WARN, "出现非预期的连接行为"); - return Task.FromResult(false); // 出现不符预期的连接行为,忽略此次连接行为 - } - - if (type == JunctionOfConnectionType.Invoke) - { - if (fromNodeJunctionType == JunctionType.Execute) - { - // 如果 起始控制点 是“方法调用”,需要反转 from to 节点 - (fromNode, toNode) = (toNode, fromNode); - } - // 从起始节点“下一个方法”控制点,连接到目标节点“方法调用”控制点 - state = ConnectInvokeOfNode(canvasGuid, fromNode, toNode, invokeType); // 本地环境进行连接 - } - return Task.FromResult(state); - - } - - - /// - /// 设置两个节点某个类型的方法调用关系为优先调用 - /// - /// 起始节点 - /// 目标节点 - /// 连接关系 - /// 是否成功调用 - public Task SetConnectPriorityInvoke(string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType) - { - // 获取起始节点与目标节点 - if (!TryGetNodeModel(fromNodeGuid, out var fromNode) || !TryGetNodeModel(toNodeGuid, out var toNode)) - { - return Task.FromResult(false); - } - if (fromNode is null || toNode is null) return Task.FromResult(false); - if (fromNode.SuccessorNodes.TryGetValue(connectionType, out var nodes)) - { - var idx = nodes.IndexOf(toNode); - if (idx > -1) - { - nodes.RemoveAt(idx); - nodes.Insert(0, toNode); - return Task.FromResult(true); - } - } - return Task.FromResult(false); - } - - /// - /// 移除连接节点之间方法调用的关系 - /// - /// 起始节点Guid - /// 目标节点Guid - /// 连接关系 - /// - public async Task RemoveConnectInvokeAsync(string canvasGuid, string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType) - { - // 获取起始节点与目标节点 - if (!FlowCanvass.ContainsKey(canvasGuid) || !TryGetNodeModel(fromNodeGuid, out var fromNode) || !TryGetNodeModel(toNodeGuid, out var toNode)) - { - return false; - } - if (fromNode is null || toNode is null) return false; - - var result = await RemoteConnectAsync(canvasGuid, fromNode, toNode, connectionType); - return result; - } - - /// - /// 创建节点之间的参数来源关系 - /// - /// 起始节点 - /// 目标节点 - /// 起始节点控制点(result控制点) - /// 目标节点控制点(argData控制点) - /// 目标节点的第几个参数 - /// 调用目标节点对应方法时,对应参数来源类型 - /// - public async Task ConnectArgSourceNodeAsync(string canvasGuid, - string fromNodeGuid, - string toNodeGuid, - JunctionType fromNodeJunctionType, - JunctionType toNodeJunctionType, - ConnectionArgSourceType connectionArgSourceType, - int argIndex) - { - - // 获取起始节点与目标节点 - if (!FlowCanvass.ContainsKey(canvasGuid) || !TryGetNodeModel(fromNodeGuid, out var fromNode) || !TryGetNodeModel(toNodeGuid, out var toNode)) - { - return false; - } - if (fromNode is null || toNode is null) return false; - (var type, var state) = CheckConnect(fromNode, toNode, fromNodeJunctionType, toNodeJunctionType); - if (!state) - { - SereinEnv.WriteLine(InfoType.WARN, "出现非预期的连接行为"); - return false; // 出现不符预期的连接行为,忽略此次连接行为 - } - - if (type == JunctionOfConnectionType.Arg) - { - // 从起始节点“返回值”控制点,连接到目标节点“方法入参”控制点 - if (fromNodeJunctionType == JunctionType.ArgData) - { - // 如果 起始控制点 是“方法入参”,需要反转 from to 节点 - (fromNode, toNode) = (toNode, fromNode); - } - - // 确定方法入参关系 - state = await ConnectArgSourceOfNodeAsync(canvasGuid, fromNode, toNode, connectionArgSourceType, argIndex); // 本地环境进行连接 - } - return state; - - } - - - /// - /// 移除连接节点之间参数传递的关系 - /// - /// 起始节点Guid - /// 目标节点Guid - /// 连接到第几个参数 - public async Task RemoveConnectArgSourceAsync(string canvasGuid, string fromNodeGuid, string toNodeGuid, int argIndex) - { - // 获取起始节点与目标节点 - if (!FlowCanvass.ContainsKey(canvasGuid) || !TryGetNodeModel(fromNodeGuid, out var fromNode) || !TryGetNodeModel(toNodeGuid, out var toNode)) - { - return false; - } - if (fromNode is null || toNode is null) return false; - var result = await RemoteConnectAsync(canvasGuid, fromNode, toNode, argIndex); - return result; - } - /// /// 获取方法描述 @@ -1466,33 +874,16 @@ namespace Serein.NodeFlow.Env if (uiContextOperation is not null) { this.UIContextOperation = uiContextOperation; - PersistennceInstance[typeof(UIContextOperation)] = uiContextOperation; // 缓存封装好的UI线程上下文 + //PersistennceInstance[typeof(UIContextOperation)] = uiContextOperation; // 缓存封装好的UI线程上下文 } - } /// public void UseExternalIOC(ISereinIOC ioc) { - this.ioc = ioc; // 设置IOC容器 - } - - - /// - /// 设置起点控件 - /// - /// 画布 - /// 节点Guid - public Task SetStartNodeAsync(string canvasGuid, string newNodeGuid) - { - if (!TryGetCanvasModel(canvasGuid, out var canvasModel) || !TryGetNodeModel(newNodeGuid, out var newStartNodeModel)) - { - return Task.FromResult(string.Empty); - } - SetStartNode(canvasModel, newStartNodeModel); - return Task.FromResult(canvasModel.StartNode.Guid ?? string.Empty); + this.flowRunIOC = ioc; // 设置IOC容器 } /// @@ -1580,32 +971,7 @@ namespace Serein.NodeFlow.Env } - /// - /// 改变可选参数的数目 - /// - /// 对应的节点Guid - /// true,增加参数;false,减少参数 - /// 以哪个参数为模板进行拷贝,或删去某个参数(该参数必须为可选参数) - /// - public Task ChangeParameter(string nodeGuid, bool isAdd, int paramIndex) - { - if (!TryGetNodeModel(nodeGuid, out var nodeModel)) - { - return Task.FromResult(false); - } - if (nodeModel is null) return Task.FromResult(false); - bool isPass; - if (isAdd) - { - isPass = nodeModel.MethodDetails.AddParamsArg(paramIndex); - } - else - { - isPass = nodeModel.MethodDetails.RemoveParamsArg(paramIndex); - } - return Task.FromResult(isPass); - } - + /// /// 从Guid获取画布 @@ -1811,71 +1177,6 @@ namespace Serein.NodeFlow.Env } - /// - /// 移除连接关系 - /// - /// 起始节点Model - /// 目标节点Model - /// 连接关系 - /// - private async Task RemoteConnectAsync(string canvasGuid, IFlowNode fromNode, IFlowNode toNode, ConnectionInvokeType connectionType) - { - if (!FlowCanvass.ContainsKey(canvasGuid)) - { - return false; - } - fromNode.SuccessorNodes[connectionType].Remove(toNode); - toNode.PreviousNodes[connectionType].Remove(fromNode); - - - if (OperatingSystem.IsWindows()) - { - UIContextOperation?.Invoke(() => Event.OnNodeConnectChanged( - new NodeConnectChangeEventArgs( - canvasGuid, - fromNode.Guid, - toNode.Guid, - JunctionOfConnectionType.Invoke, - connectionType, - NodeConnectChangeEventArgs.ConnectChangeType.Remove))); - } - return true; - } - /// - /// 移除连接关系 - /// - /// 起始节点Model - /// 目标节点Model - /// 连接关系 - /// - private async Task RemoteConnectAsync(string canvasGuid, IFlowNode fromNode, IFlowNode toNode, int argIndex) - { - if (!FlowCanvass.ContainsKey(canvasGuid)) - { - return false; - } - if (string.IsNullOrEmpty(toNode.MethodDetails.ParameterDetailss[argIndex].ArgDataSourceNodeGuid)) - { - return false; - } - toNode.MethodDetails.ParameterDetailss[argIndex].ArgDataSourceNodeGuid = null; - toNode.MethodDetails.ParameterDetailss[argIndex].ArgDataSourceType = ConnectionArgSourceType.GetPreviousNodeData; // 恢复默认值 - - if (OperatingSystem.IsWindows()) - { - UIContextOperation?.Invoke(() => Event.OnNodeConnectChanged( - new NodeConnectChangeEventArgs( - canvasGuid, - fromNode.Guid, - toNode.Guid, - JunctionOfConnectionType.Arg, - argIndex, - ConnectionArgSourceType.GetPreviousNodeData, - NodeConnectChangeEventArgs.ConnectChangeType.Remove))); - } - return true; - } - /// /// 创建节点 @@ -1965,186 +1266,122 @@ namespace Serein.NodeFlow.Env // 剩下的情况都是不符预期的连接行为,忽略。 return (type, state); } + /* + /// + /// 连接节点 + /// + /// 起始节点 + /// 目标节点 + /// 连接关系 + private bool ConnectInvokeOfNode(string canvasGuid, IFlowNode fromNode, IFlowNode toNode, ConnectionInvokeType invokeType) + { + if (fromNode.ControlType == NodeControlType.FlowCall) + { + SereinEnv.WriteLine(InfoType.ERROR, $"流程接口节点不可调用下一个节点。" + + $"{Environment.NewLine}流程节点:{fromNode.Guid}"); + return false; + } + if (!FlowCanvass.ContainsKey(canvasGuid)) + { + return false; + } + if (fromNode is null || toNode is null || fromNode == toNode) + { + return false; + } - /// - /// 连接节点 - /// - /// 起始节点 - /// 目标节点 - /// 连接关系 - private bool ConnectInvokeOfNode(string canvasGuid, IFlowNode fromNode, IFlowNode toNode, ConnectionInvokeType invokeType) - { - if (fromNode.ControlType == NodeControlType.FlowCall) - { - SereinEnv.WriteLine(InfoType.ERROR, $"流程接口节点不可调用下一个节点。" + - $"{Environment.NewLine}流程节点:{fromNode.Guid}"); - return false; - } - if (!FlowCanvass.ContainsKey(canvasGuid)) - { - return false; - } - if (fromNode is null || toNode is null || fromNode == toNode) - { - return false; - } + var ToExistOnFrom = true; + var FromExistInTo = true; + ConnectionInvokeType[] ct = [ConnectionInvokeType.IsSucceed, + ConnectionInvokeType.IsFail, + ConnectionInvokeType.IsError, + ConnectionInvokeType.Upstream]; - var ToExistOnFrom = true; - var FromExistInTo = true; - ConnectionInvokeType[] ct = [ConnectionInvokeType.IsSucceed, - ConnectionInvokeType.IsFail, - ConnectionInvokeType.IsError, - ConnectionInvokeType.Upstream]; - - if (toNode is SingleFlipflopNode flipflopNode) - { - flowTaskManagement?.TerminateGlobalFlipflopRuning(flipflopNode); // 假设被连接的是全局触发器,尝试移除 - } - var isOverwriting = false; - ConnectionInvokeType overwritingCt = ConnectionInvokeType.None; - var isPass = false; - 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) - { - if (ctType == invokeType) - { - SereinEnv.WriteLine(InfoType.WARN, $"起始节点已与目标节点存在连接。" + + //if (toNode is SingleFlipflopNode flipflopNode) + //{ + // flowTaskManagement?.TerminateGlobalFlipflopRuning(flipflopNode); // 假设被连接的是全局触发器,尝试移除 + //} + var isOverwriting = false; + ConnectionInvokeType overwritingCt = ConnectionInvokeType.None; + var isPass = false; + 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) + { + if (ctType == invokeType) + { + SereinEnv.WriteLine(InfoType.WARN, $"起始节点已与目标节点存在连接。" + + $"{Environment.NewLine}起始节点:{fromNode.Guid}" + + $"{Environment.NewLine}目标节点:{toNode.Guid}"); + return false; + } + isOverwriting = true; + overwritingCt = ctType; + } + else + { + // 检查是否可能存在异常 + if (!ToExistOnFrom && FromExistInTo) + { + SereinEnv.WriteLine(InfoType.ERROR, $"起始节点不是目标节点的父节点,目标节点却是起始节点的子节点。" + $"{Environment.NewLine}起始节点:{fromNode.Guid}" + $"{Environment.NewLine}目标节点:{toNode.Guid}"); - return false; - } - isOverwriting = true; - overwritingCt = ctType; - } - else - { - // 检查是否可能存在异常 - if (!ToExistOnFrom && FromExistInTo) - { - SereinEnv.WriteLine(InfoType.ERROR, $"起始节点不是目标节点的父节点,目标节点却是起始节点的子节点。" + - $"{Environment.NewLine}起始节点:{fromNode.Guid}" + - $"{Environment.NewLine}目标节点:{toNode.Guid}"); - isPass = false; - } - else if (ToExistOnFrom && !FromExistInTo) - { - // - SereinEnv.WriteLine(InfoType.ERROR, $"起始节点不是目标节点的父节点,目标节点却是起始节点的子节点。" + - $"{Environment.NewLine}起始节点:{fromNode.Guid}" + - $"{Environment.NewLine}目标节点:{toNode.Guid}" + - $""); - isPass = false; - } - else - { - isPass = true; - } - } - } - if (isPass) - { - if (isOverwriting) // 需要替换 - { - fromNode.SuccessorNodes[overwritingCt].Remove(toNode); // 从起始节点子分支中移除 - toNode.PreviousNodes[overwritingCt].Remove(fromNode); // 从目标节点父分支中移除 - } - fromNode.SuccessorNodes[invokeType].Add(toNode); // 添加到起始节点的子分支 - toNode.PreviousNodes[invokeType].Add(fromNode); // 添加到目标节点的父分支 - if (OperatingSystem.IsWindows()) - { + isPass = false; + } + else if (ToExistOnFrom && !FromExistInTo) + { + // + SereinEnv.WriteLine(InfoType.ERROR, $"起始节点不是目标节点的父节点,目标节点却是起始节点的子节点。" + + $"{Environment.NewLine}起始节点:{fromNode.Guid}" + + $"{Environment.NewLine}目标节点:{toNode.Guid}" + + $""); + isPass = false; + } + else + { + isPass = true; + } + } + } + if (isPass) + { + if (isOverwriting) // 需要替换 + { + fromNode.SuccessorNodes[overwritingCt].Remove(toNode); // 从起始节点子分支中移除 + toNode.PreviousNodes[overwritingCt].Remove(fromNode); // 从目标节点父分支中移除 + } + fromNode.SuccessorNodes[invokeType].Add(toNode); // 添加到起始节点的子分支 + toNode.PreviousNodes[invokeType].Add(fromNode); // 添加到目标节点的父分支 + if (OperatingSystem.IsWindows()) + { - UIContextOperation?.Invoke(() => - Event.OnNodeConnectChanged( - new NodeConnectChangeEventArgs( - canvasGuid, - fromNode.Guid, // 从哪个节点开始 - toNode.Guid, // 连接到那个节点 - JunctionOfConnectionType.Invoke, - invokeType, // 连接线的样式类型 - NodeConnectChangeEventArgs.ConnectChangeType.Create // 是创建连接还是删除连接 - ))); // 通知UI - } - // Invoke - // GetResult - return true; - } - else - { - return false; - } - - - } - - /// - /// 连接节点参数 - /// - /// - /// - /// - /// - /// - private async Task ConnectArgSourceOfNodeAsync(string canvasGuid, - IFlowNode fromNode, - IFlowNode toNode, - ConnectionArgSourceType connectionArgSourceType, - int argIndex) - { - if (!FlowCanvass.ContainsKey(canvasGuid)) - { - return false; - } - - var toNodeArgSourceGuid = toNode.MethodDetails.ParameterDetailss[argIndex].ArgDataSourceNodeGuid; - var toNodeArgSourceType = toNode.MethodDetails.ParameterDetailss[argIndex].ArgDataSourceType; - if (fromNode.Guid == toNodeArgSourceGuid && toNodeArgSourceType == connectionArgSourceType) - { - SereinEnv.WriteLine(InfoType.INFO, $"节点之间已建立过连接关系,此次操作将不会执行" + - $"起始节点:{fromNode.Guid}" + - $"目标节点:{toNode.Guid}" + - $"参数索引:{argIndex}" + - $"参数类型:{connectionArgSourceType}"); - UIContextOperation?.Invoke(() => - Event.OnNodeConnectChanged( - new NodeConnectChangeEventArgs( + UIContextOperation?.Invoke(() => + Event.OnNodeConnectChanged( + new NodeConnectChangeEventArgs( canvasGuid, - fromNode.Guid, // 从哪个节点开始 - toNode.Guid, // 连接到那个节点 - JunctionOfConnectionType.Arg, - argIndex, // 连接线的样式类型 - connectionArgSourceType, - NodeConnectChangeEventArgs.ConnectChangeType.Create // 是创建连接还是删除连接 - ))); // 通知UI + fromNode.Guid, // 从哪个节点开始 + toNode.Guid, // 连接到那个节点 + JunctionOfConnectionType.Invoke, + invokeType, // 连接线的样式类型 + NodeConnectChangeEventArgs.ConnectChangeType.Create // 是创建连接还是删除连接 + ))); // 通知UI + } + // Invoke + // GetResult + return true; + } + else + { + return false; + } - return true; - } - if (!string.IsNullOrEmpty(toNodeArgSourceGuid)) - { - await RemoteConnectAsync(canvasGuid, fromNode, toNode, argIndex); - } + }*/ - toNode.MethodDetails.ParameterDetailss[argIndex].ArgDataSourceNodeGuid = fromNode.Guid; - toNode.MethodDetails.ParameterDetailss[argIndex].ArgDataSourceType = connectionArgSourceType; - - UIContextOperation?.Invoke(() => - Event.OnNodeConnectChanged( - new NodeConnectChangeEventArgs( - canvasGuid, - fromNode.Guid, // 从哪个节点开始 - toNode.Guid, // 连接到那个节点 - JunctionOfConnectionType.Arg, - argIndex, // 连接线的样式类型 - connectionArgSourceType, - NodeConnectChangeEventArgs.ConnectChangeType.Create // 是创建连接还是删除连接 - ))); // 通知UI - return true; - } /// @@ -2165,19 +1402,7 @@ namespace Serein.NodeFlow.Env } - /// - /// 向容器登记缓存的持久化实例 - /// - private void ReRegisterPersistennceInstance() - { - lock (PersistennceInstance) - { - foreach (var kvp in PersistennceInstance) - { - IOC.Register(kvp.Key, () => kvp.Value); - } - } - } + #endregion @@ -2196,9 +1421,332 @@ namespace Serein.NodeFlow.Env } + #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 + }; + 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 + }; + 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; + } + SetStartNode(canvasModel, newStartNodeModel); + return; + } + + void IFlowEnvironment.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); + } + + + + /// + /// 从节点信息集合批量加载节点控件 + /// + /// 节点信息 + /// + /// + public async Task LoadNodeInfosAsync(List nodeInfos) + { + #region 从NodeInfo创建NodeModel + // 流程接口节点最后才创建 + + List 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 needPlaceNodeInfos = []; + foreach (NodeInfo? nodeInfo in nodeInfos) + { + if (!string.IsNullOrEmpty(nodeInfo.ParentNodeGuid) && + NodeModels.TryGetValue(nodeInfo.ParentNodeGuid, out var parentNode)) + { + needPlaceNodeInfos.Add(nodeInfo); // 需要重新放置的节点 + } + } + + foreach (NodeInfo nodeInfo in needPlaceNodeInfos) + { + if (NodeModels.TryGetValue(nodeInfo.Guid, out var nodeModel) && + NodeModels.TryGetValue(nodeInfo.ParentNodeGuid, out var containerNode) + && containerNode is INodeContainer nodeContainer) + { + var result = nodeContainer.PlaceNode(nodeModel); + if (result) + { + UIContextOperation?.Invoke(() => Event.OnNodePlace( + new NodePlaceEventArgs(nodeInfo.CanvasGuid, nodeModel.Guid, containerNode.Guid))); + } + + + } + } + #endregion + + #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.Execute, JunctionType.NextStep, 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 确定节点之间的参数调用关系 + foreach (var toNode in NodeModels.Values) + { + 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) + && NodeModels.TryGetValue(pd.ArgDataSourceNodeGuid, out var fromNode)) + { + + ConnectArgSourceNode(canvasGuid, fromNode.Guid, toNode.Guid, JunctionType.ReturnData, JunctionType.ArgData , pd.ArgDataSourceType, pd.Index); + } + } + } + #endregion + + + UIContextOperation?.Invoke(() => + { + Event.OnProjectLoaded(new ProjectLoadedEventArgs()); + }); + + return; + } + #endregion } diff --git a/NodeFlow/FlowNodeExtension.cs b/NodeFlow/FlowNodeExtension.cs index ebdca1f..1b63c82 100644 --- a/NodeFlow/FlowNodeExtension.cs +++ b/NodeFlow/FlowNodeExtension.cs @@ -1,7 +1,7 @@ using Serein.Library; using Serein.Library.Api; using Serein.Library.Utils; -using Serein.NodeFlow.Model.Node; +using Serein.NodeFlow.Model; using System.Collections.Concurrent; using System.ComponentModel; using System.Reflection; diff --git a/NodeFlow/Model/Node/SingleActionNode.cs b/NodeFlow/Model/Node/SingleActionNode.cs index 8f807e9..496b1fb 100644 --- a/NodeFlow/Model/Node/SingleActionNode.cs +++ b/NodeFlow/Model/Node/SingleActionNode.cs @@ -2,7 +2,7 @@ using Serein.Library; using System.Security.AccessControl; -namespace Serein.NodeFlow.Model.Node +namespace Serein.NodeFlow.Model { /// /// 单动作节点(用于动作控件) diff --git a/NodeFlow/Model/Node/SingleFlipflopNode.cs b/NodeFlow/Model/Node/SingleFlipflopNode.cs index ab479e6..c58da1e 100644 --- a/NodeFlow/Model/Node/SingleFlipflopNode.cs +++ b/NodeFlow/Model/Node/SingleFlipflopNode.cs @@ -3,7 +3,7 @@ using Serein.Library; using Serein.Library.Utils; using System; -namespace Serein.NodeFlow.Model.Node +namespace Serein.NodeFlow.Model { /// /// 触发器节点 diff --git a/NodeFlow/Model/Node/SingleUINode.cs b/NodeFlow/Model/Node/SingleUINode.cs index 7ce9c9a..ceac5c7 100644 --- a/NodeFlow/Model/Node/SingleUINode.cs +++ b/NodeFlow/Model/Node/SingleUINode.cs @@ -6,7 +6,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Serein.NodeFlow.Model.Node +namespace Serein.NodeFlow.Model { public class SingleUINode : NodeModelBase { diff --git a/NodeFlow/Model/Operation/ChangeNodeConnectionOperation.cs b/NodeFlow/Model/Operation/ChangeNodeConnectionOperation.cs index e3fc394..f8f194a 100644 --- a/NodeFlow/Model/Operation/ChangeNodeConnectionOperation.cs +++ b/NodeFlow/Model/Operation/ChangeNodeConnectionOperation.cs @@ -1,7 +1,7 @@ using Serein.Library; using Serein.Library.Api; using Serein.NodeFlow.Env; -using Serein.NodeFlow.Model.Node; +using Serein.NodeFlow.Model; using System; using System.Collections.Generic; using System.Linq; diff --git a/NodeFlow/Model/Operation/CreateNodeOperation.cs b/NodeFlow/Model/Operation/CreateNodeOperation.cs index e28fa66..9c27190 100644 --- a/NodeFlow/Model/Operation/CreateNodeOperation.cs +++ b/NodeFlow/Model/Operation/CreateNodeOperation.cs @@ -1,6 +1,6 @@ using Serein.Library; using Serein.Library.Api; -using Serein.NodeFlow.Model.Node; +using Serein.NodeFlow.Model; using Serein.NodeFlow.Services; using Serein.NodeFlow.Tool; using System; diff --git a/NodeFlow/Services/FlowModelService.cs b/NodeFlow/Services/FlowModelService.cs index a759281..f9fde89 100644 --- a/NodeFlow/Services/FlowModelService.cs +++ b/NodeFlow/Services/FlowModelService.cs @@ -1,6 +1,6 @@ using Serein.Library; using Serein.Library.Api; -using Serein.NodeFlow.Model.Node; +using Serein.NodeFlow.Model; using System; using System.Collections.Generic; using System.Linq; @@ -9,7 +9,7 @@ using System.Threading.Tasks; namespace Serein.NodeFlow.Services { - public class FlowModelService + internal class FlowModelService { private readonly IFlowEnvironment environment; diff --git a/NodeFlow/Services/FlowOperationService.cs b/NodeFlow/Services/FlowOperationService.cs index ae9fa09..b5fe287 100644 --- a/NodeFlow/Services/FlowOperationService.cs +++ b/NodeFlow/Services/FlowOperationService.cs @@ -8,7 +8,7 @@ using System.Threading.Tasks; namespace Serein.NodeFlow.Services { - public class FlowOperationService + internal class FlowOperationService { private readonly ISereinIOC sereinIOC; diff --git a/NodeFlow/Services/FlowWorkManagement.cs b/NodeFlow/Services/FlowWorkManagement.cs index 7af53f0..0170274 100644 --- a/NodeFlow/Services/FlowWorkManagement.cs +++ b/NodeFlow/Services/FlowWorkManagement.cs @@ -2,7 +2,7 @@ using Serein.Library; using Serein.Library.Api; using Serein.Library.Utils; -using Serein.NodeFlow.Model.Node; +using Serein.NodeFlow.Model; using Serein.NodeFlow.Tool; using System; using System.Collections.Concurrent; diff --git a/NodeFlow/Tool/FlowLibraryManagement.cs b/NodeFlow/Tool/FlowLibraryManagement.cs index 8ec72bd..b51d0ad 100644 --- a/NodeFlow/Tool/FlowLibraryManagement.cs +++ b/NodeFlow/Tool/FlowLibraryManagement.cs @@ -18,7 +18,7 @@ namespace Serein.NodeFlow.Tool /// /// 管理加载在运行环境中的外部程序集 /// - public class FlowLibraryManagement + internal class FlowLibraryManagement { public FlowLibraryManagement(IFlowEnvironment flowEnvironment) { diff --git a/Workbench/Node/ViewModel/ActionNodeControlViewModel.cs b/Workbench/Node/ViewModel/ActionNodeControlViewModel.cs index 38139e4..8325690 100644 --- a/Workbench/Node/ViewModel/ActionNodeControlViewModel.cs +++ b/Workbench/Node/ViewModel/ActionNodeControlViewModel.cs @@ -1,4 +1,4 @@ -using Serein.NodeFlow.Model.Node; +using Serein.NodeFlow.Model; using Serein.Workbench.Node.View; namespace Serein.Workbench.Node.ViewModel diff --git a/Workbench/Node/ViewModel/FlipflopNodeControlViewModel.cs b/Workbench/Node/ViewModel/FlipflopNodeControlViewModel.cs index 57caa6a..3ab4e2e 100644 --- a/Workbench/Node/ViewModel/FlipflopNodeControlViewModel.cs +++ b/Workbench/Node/ViewModel/FlipflopNodeControlViewModel.cs @@ -1,4 +1,4 @@ -using Serein.NodeFlow.Model.Node; +using Serein.NodeFlow.Model; using Serein.Workbench.Node.View; namespace Serein.Workbench.Node.ViewModel diff --git a/Workbench/Node/ViewModel/UINodeControlViewModel.cs b/Workbench/Node/ViewModel/UINodeControlViewModel.cs index 94904a5..01fabea 100644 --- a/Workbench/Node/ViewModel/UINodeControlViewModel.cs +++ b/Workbench/Node/ViewModel/UINodeControlViewModel.cs @@ -1,7 +1,7 @@ using CommunityToolkit.Mvvm.ComponentModel; using Serein.Library; using Serein.Library.Api; -using Serein.NodeFlow.Model.Node; +using Serein.NodeFlow.Model; using System; using System.Collections.Generic; using System.Linq;