From 162dc7bcf82b3597397d3d697e5e4e130f6b0f34 Mon Sep 17 00:00:00 2001 From: fengjiayi <12821976+ning_xi@user.noreply.gitee.com> Date: Fri, 4 Jul 2025 21:31:07 +0800 Subject: [PATCH] =?UTF-8?q?=E5=87=86=E5=A4=87=E6=B7=BB=E5=8A=A0=E6=B5=81?= =?UTF-8?q?=E7=A8=8B=E6=8E=A5=E5=8F=A3=E8=B0=83=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Library/Api/IEmbeddedContent.cs | 4 +- Library/Api/IFlowControl.cs | 68 + Library/Api/IFlowEdit.cs | 169 +++ Library/Api/IFlowEnvironment.cs | 354 ++---- Library/Extension/FlowModelExtension.cs | 63 +- Library/FlowNode/FlowResult.cs | 9 +- NodeFlow/Env/FlowControl.cs | 375 ++++++ NodeFlow/Env/FlowEdit.cs | 568 +++++++++ NodeFlow/Env/FlowEnvironment.cs | 276 +---- NodeFlow/Env/LocalFlowEnvironment.cs | 1100 +---------------- NodeFlow/FlowNodeExtension.cs | 2 +- NodeFlow/Model/Node/NodeModelBaseFunc.cs | 2 +- NodeFlow/Model/Node/SingleFlowCallNode.cs | 8 +- NodeFlow/Model/Node/SingleGlobalDataNode.cs | 2 +- .../Model/Operation/CreateNodeOperation.cs | 2 +- NodeFlow/Services/FlowApiService.cs | 27 - .../Node/Junction/JunctionControlBase.cs | 4 +- Workbench/Node/View/ConnectionControl.cs | 6 +- Workbench/Services/FlowNodeService.cs | 30 +- .../Themes/NodeTreeItemViewControl.xaml.cs | 4 +- Workbench/ViewModels/MainMenuBarViewModel.cs | 4 +- Workbench/Views/FlowCanvasView.xaml.cs | 20 +- Workbench/Views/ViewCanvasInfoView.xaml.cs | 2 +- 23 files changed, 1401 insertions(+), 1698 deletions(-) create mode 100644 Library/Api/IFlowControl.cs create mode 100644 Library/Api/IFlowEdit.cs create mode 100644 NodeFlow/Env/FlowControl.cs create mode 100644 NodeFlow/Env/FlowEdit.cs diff --git a/Library/Api/IEmbeddedContent.cs b/Library/Api/IEmbeddedContent.cs index bf1eb6b..7f8b54b 100644 --- a/Library/Api/IEmbeddedContent.cs +++ b/Library/Api/IEmbeddedContent.cs @@ -10,7 +10,7 @@ namespace Serein.Library.Api /// /// 流程中的控件 /// - public interface IFlowControl + public interface IFlowUIControl { /// /// 节点执行事件 @@ -33,7 +33,7 @@ namespace Serein.Library.Api /// 获取窗体控件 /// /// - IFlowControl GetFlowControl(); + IFlowUIControl GetFlowControl(); } diff --git a/Library/Api/IFlowControl.cs b/Library/Api/IFlowControl.cs new file mode 100644 index 0000000..36df475 --- /dev/null +++ b/Library/Api/IFlowControl.cs @@ -0,0 +1,68 @@ +using System.Threading.Tasks; + +namespace Serein.Library.Api +{ + /// + /// 流程运行接口 + /// + public interface IFlowControl + { + /// + /// 需要你提供一个由你实现的ISereinIOC接口实现类 + /// 当你将流程运行环境集成在你的项目时,并希望流程运行时使用你提供的对象,而非自动创建 + /// 就需要你调用这个方法,用来替换运行环境的IOC容器 + /// 注意,是流程运行时,而非运行环境 + /// + /// + void UseExternalIOC(ISereinIOC ioc); + + /// + /// 开始运行流程 + /// + /// 需要运行的流程Guid + /// + Task StartFlowAsync(string[] canvasGuids); + + /// + /// 从选定的节点开始运行 + /// + /// + /// + Task StartFlowFromSelectNodeAsync(string startNodeGuid); + + /// + /// 结束运行 + /// + Task ExitFlowAsync(); + + /// + /// 激活未启动的全局触发器 + /// + /// + void ActivateFlipflopNode(string nodeGuid); + + /// + /// 终结一个全局触发器,在它触发后将不会再次监听消息(表现为已经启动的触发器至少会再次处理一次消息,后面版本再修正这个非预期行为) + /// + /// + void TerminateFlipflopNode(string nodeGuid); + + /// + /// 流程启动器调用,监视数据更新通知 + /// + /// 更新了数据的节点Guid + /// 更新的数据 + /// 更新的数据 + void MonitorObjectNotification(string nodeGuid, object monitorData, MonitorObjectEventArgs.ObjSourceType sourceType); + + /// + /// 流程启动器调用,节点触发了中断 + /// + /// 被中断的节点Guid + /// 被触发的表达式 + /// 中断类型。0主动监视,1表达式 + void TriggerInterrupt(string nodeGuid, string expression, InterruptTriggerEventArgs.InterruptTriggerType type); + } + + +} diff --git a/Library/Api/IFlowEdit.cs b/Library/Api/IFlowEdit.cs new file mode 100644 index 0000000..e848a65 --- /dev/null +++ b/Library/Api/IFlowEdit.cs @@ -0,0 +1,169 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Serein.Library.Api +{ + /// + /// 流程编辑 + /// + public interface IFlowEdit + { + + /// + /// 节点视图模型管理类 + /// + NodeMVVMService NodeMVVMManagement { get; } + + /// + /// 从节点信息集合批量加载节点控件 + /// + /// 节点集合信息 + /// + Task LoadNodeInfosAsync(List nodeInfos); + + #region 流程节点操作接口 + + /// + /// 增加画布 + /// + /// 画布名称 + /// 宽度 + /// 高度 + /// + void CreateCanvas(string canvasName, int width, int height); + + /// + /// 删除画布 + /// + /// 画布Guid + /// + void RemoveCanvas(string canvasGuid); + + + + + /// + /// 在两个节点之间创建连接关系 + /// + /// 所在画布 + /// 起始节点Guid + /// 目标节点Guid + /// 起始节点控制点 + /// 目标节点控制点 + /// 决定了方法执行后的后继行为 + void ConnectInvokeNode(string canvasGuid, + string fromNodeGuid, + string toNodeGuid, + JunctionType fromNodeJunctionType, + JunctionType toNodeJunctionType, + ConnectionInvokeType invokeType); + + /// + /// 在两个节点之间创建连接关系 + /// + /// 所在画布 + /// 起始节点Guid + /// 目标节点Guid + /// 起始节点控制点 + /// 目标节点控制点 + /// 决定了方法参数来源 + /// 设置第几个参数 + void ConnectArgSourceNode(string canvasGuid, + string fromNodeGuid, + string toNodeGuid, + JunctionType fromNodeJunctionType, + JunctionType toNodeJunctionType, + ConnectionArgSourceType argSourceType, + int argIndex); + + /// + /// 移除两个节点之间的方法调用关系 + /// + /// 所在画布 + /// 起始节点 + /// 目标节点 + /// 连接类型 + void RemoveInvokeConnect(string canvasGuid, string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType); + + /// + /// 移除连接节点之间参数传递的关系 + /// + /// 所在画布 + /// 起始节点Guid + /// 目标节点Guid + /// 连接到第几个参数 + void RemoveArgSourceConnect(string canvasGuid, string fromNodeGuid, string toNodeGuid, int argIndex); + + + /// + /// 创建节点 + /// + /// 所在画布 + /// 控件类型 + /// 节点在画布上的位置( + /// 节点绑定的方法说明 + void CreateNode(string canvasGuid, NodeControlType nodeType, PositionOfUI position, MethodDetailsInfo methodDetailsInfo = null); + + /// + /// 移除节点 + /// + /// 所在画布 + /// 待移除的节点Guid + void RemoveNode(string canvasGuid, string nodeGuid); + + /// + /// 将节点放置在容器中 + /// + /// 所在画布 + /// 需要放置的节点Guid + /// 存放节点的容器Guid + /// + void PlaceNodeToContainer(string canvasGuid, string nodeGuid, string containerNodeGuid); + + /// + /// 将节点放置在容器中 + /// + /// 所在画布 + /// 需要取出的节点Guid + void TakeOutNodeToContainer(string canvasGuid, string nodeGuid); + + /// + /// 设置流程起点节点 + /// + /// 所在画布 + /// 尝试设置为起始节点的节点Guid + /// 被设置为起始节点的Guid + void SetStartNode(string canvasGuid, string nodeGuid); + + /// + /// 设置两个节点某个类型的方法调用关系为优先调用 + /// + /// 起始节点 + /// 目标节点 + /// 连接关系 + /// + void SetConnectPriorityInvoke(string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType); + + + /// + /// 改变可选参数的数目 + /// + /// 对应的节点Guid + /// true,增加参数;false,减少参数 + /// 以哪个参数为模板进行拷贝,或删去某个参数(该参数必须为可选参数) + /// + void ChangeParameter(string nodeGuid, bool isAdd, int paramIndex); + + #endregion + + #region UI视觉 + + /// + /// 节点定位 + /// + /// + void NodeLocate(string nodeGuid); + + #endregion + } +} diff --git a/Library/Api/IFlowEnvironment.cs b/Library/Api/IFlowEnvironment.cs index 40c485d..7962d87 100644 --- a/Library/Api/IFlowEnvironment.cs +++ b/Library/Api/IFlowEnvironment.cs @@ -748,7 +748,7 @@ namespace Serein.Library.Api public void OnEnvOutput(InfoType type, string value); } - + /// /// 运行环境 @@ -764,6 +764,15 @@ namespace Serein.Library.Api /// ISereinIOC IOC { get; } + /// + /// 流程编辑接口 + /// + IFlowEdit FlowEdit { get; } + + /// + /// 流程控制接口 + /// + IFlowControl FlowControl { get; } /// /// 流程事件接口 @@ -811,10 +820,6 @@ namespace Serein.Library.Api /// UIContextOperation UIContextOperation { get; } - /// - /// 节点视图模型管理类 - /// - NodeMVVMService NodeMVVMManagement { get; } #endregion #region 基本接口 @@ -826,6 +831,17 @@ namespace Serein.Library.Api /// 输出类型 /// 输出级别 void WriteLine(InfoType type, string message, InfoClass @class = InfoClass.Trivial); + /// + /// 提供设置UI上下文的能力 + /// 提供设置UI上下文的能力,在WinForm/WPF项目中,在UI线程外对UI元素的修改将会导致异常 + /// 需要你提供 + /// + /// + void SetUIContextOperation(UIContextOperation uiContextOperation); + #endregion + + + #region 项目相关操作 /// /// 加载项目文件 @@ -845,15 +861,69 @@ namespace Serein.Library.Api /// Task GetProjectInfoAsync(); + #endregion + + #region 获取节点信息,获取方法信息,获取Emit委托 /// - /// 从节点信息集合批量加载节点控件 + /// 获取节点信息 /// - /// 节点集合信息 + /// + /// /// - Task LoadNodeInfosAsync(List nodeInfos); + bool TryGetNodeModel(string nodeGuid, out IFlowNode nodeModel); + + /// + /// 获取方法描述信息 + /// + /// 程序集名称 + /// 方法描述 + /// 方法信息 + /// + bool TryGetMethodDetailsInfo(string assemblyName, string methodName, out MethodDetailsInfo mdInfo); + + /// + /// 获取指定方法的Emit委托 + /// + /// 程序集名称 + /// + /// + /// + bool TryGetDelegateDetails(string assemblyName, string methodName, out DelegateDetails del); + #endregion + + + #region 类库依赖相关 + + /// + /// 从文件中加载Dll + /// + /// + void LoadLibrary(string dllPath); + + /// + /// 移除DLL + /// + /// 程序集的名称 + bool TryUnloadLibrary(string assemblyFullName); + + /// + /// 运行时加载 + /// + /// 文件名 + /// + bool LoadNativeLibraryOfRuning(string file); + + /// + /// 运行时加载指定目录下的类库 + /// + /// 目录 + /// 是否递归加载 + void LoadAllNativeLibraryOfRuning(string path, bool isRecurrence = true); #endregion + + #region 远程相关 /// /// 启动远程服务 @@ -895,142 +965,9 @@ namespace Serein.Library.Api #endregion - #region 流程节点操作接口 - - /// - /// 增加画布 - /// - /// 画布名称 - /// 宽度 - /// 高度 - /// - void CreateCanvas(string canvasName, int width , int height); - - /// - /// 删除画布 - /// - /// 画布Guid - /// - void RemoveCanvas(string canvasGuid); - - - /// - /// 在两个节点之间创建连接关系 - /// - /// 所在画布 - /// 起始节点Guid - /// 目标节点Guid - /// 起始节点控制点 - /// 目标节点控制点 - /// 决定了方法执行后的后继行为 - void ConnectInvokeNode(string canvasGuid, - string fromNodeGuid, - string toNodeGuid, - JunctionType fromNodeJunctionType, - JunctionType toNodeJunctionType, - ConnectionInvokeType invokeType); - - /// - /// 在两个节点之间创建连接关系 - /// - /// 所在画布 - /// 起始节点Guid - /// 目标节点Guid - /// 起始节点控制点 - /// 目标节点控制点 - /// 决定了方法参数来源 - /// 设置第几个参数 - void ConnectArgSourceNode(string canvasGuid, - string fromNodeGuid, - string toNodeGuid, - JunctionType fromNodeJunctionType, - JunctionType toNodeJunctionType, - ConnectionArgSourceType argSourceType, - int argIndex); - - /// - /// 移除两个节点之间的方法调用关系 - /// - /// 所在画布 - /// 起始节点 - /// 目标节点 - /// 连接类型 - void RemoveInvokeConnect(string canvasGuid, string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType); - - /// - /// 移除连接节点之间参数传递的关系 - /// - /// 所在画布 - /// 起始节点Guid - /// 目标节点Guid - /// 连接到第几个参数 - void RemoveArgSourceConnect(string canvasGuid, string fromNodeGuid, string toNodeGuid, int argIndex); - - - /// - /// 创建节点 - /// - /// 所在画布 - /// 控件类型 - /// 节点在画布上的位置( - /// 节点绑定的方法说明 - void CreateNode(string canvasGuid, NodeControlType nodeType, PositionOfUI position, MethodDetailsInfo methodDetailsInfo = null); - - /// - /// 移除节点 - /// - /// 所在画布 - /// 待移除的节点Guid - void RemoveNode(string canvasGuid, string nodeGuid); - - /// - /// 将节点放置在容器中 - /// - /// 所在画布 - /// 需要放置的节点Guid - /// 存放节点的容器Guid - /// - void PlaceNodeToContainer(string canvasGuid, string nodeGuid, string containerNodeGuid); - - /// - /// 将节点放置在容器中 - /// - /// 所在画布 - /// 需要取出的节点Guid - void TakeOutNodeToContainer(string canvasGuid, string nodeGuid); - - /// - /// 设置流程起点节点 - /// - /// 所在画布 - /// 尝试设置为起始节点的节点Guid - /// 被设置为起始节点的Guid - void SetStartNode(string canvasGuid, string nodeGuid); - - /// - /// 设置两个节点某个类型的方法调用关系为优先调用 - /// - /// 起始节点 - /// 目标节点 - /// 连接关系 - /// - void SetConnectPriorityInvoke(string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType); - - - /// - /// 改变可选参数的数目 - /// - /// 对应的节点Guid - /// true,增加参数;false,减少参数 - /// 以哪个参数为模板进行拷贝,或删去某个参数(该参数必须为可选参数) - /// - void ChangeParameter(string nodeGuid, bool isAdd, int paramIndex); - - #endregion - - #region 节点中断、表达式 + #region 节点中断、表达式(暂时没用) #if false /// @@ -1074,137 +1011,8 @@ namespace Serein.Library.Api #endif #endregion - #region 流程运行相关 - /// - /// 获取节点信息 - /// - /// - /// - /// - bool TryGetNodeModel(string nodeGuid, out IFlowNode nodeModel); - /// - /// 获取方法描述信息 - /// - /// 程序集名称 - /// 方法描述 - /// 方法信息 - /// - bool TryGetMethodDetailsInfo(string assemblyName, string methodName, out MethodDetailsInfo mdInfo); - - /// - /// 获取指定方法的Emit委托 - /// - /// 程序集名称 - /// - /// - /// - bool TryGetDelegateDetails(string assemblyName, string methodName, out DelegateDetails del); - - /// - /// 提供设置UI上下文的能力 - /// 提供设置UI上下文的能力,在WinForm/WPF项目中,在UI线程外对UI元素的修改将会导致异常 - /// 需要你提供 - /// - /// - void SetUIContextOperation(UIContextOperation uiContextOperation); - - /// - /// 需要你提供一个由你实现的ISereinIOC接口实现类 - /// 当你将流程运行环境集成在你的项目时,并希望流程运行时使用你提供的对象,而非自动创建 - /// 就需要你调用这个方法,用来替换运行环境的IOC容器 - /// 注意,是流程运行时,而非运行环境 - /// - /// - void UseExternalIOC(ISereinIOC ioc); - - /// - /// 开始运行流程 - /// - /// 需要运行的流程Guid - /// - Task StartFlowAsync(string[] canvasGuids); - - /// - /// 从选定的节点开始运行 - /// - /// - /// - Task StartFlowFromSelectNodeAsync(string startNodeGuid); - - /// - /// 结束运行 - /// - Task ExitFlowAsync(); - - /// - /// 激活未启动的全局触发器 - /// - /// - void ActivateFlipflopNode(string nodeGuid); - - /// - /// 终结一个全局触发器,在它触发后将不会再次监听消息(表现为已经启动的触发器至少会再次处理一次消息,后面版本再修正这个非预期行为) - /// - /// - void TerminateFlipflopNode(string nodeGuid); - - /// - /// 流程启动器调用,监视数据更新通知 - /// - /// 更新了数据的节点Guid - /// 更新的数据 - /// 更新的数据 - void MonitorObjectNotification(string nodeGuid, object monitorData, MonitorObjectEventArgs.ObjSourceType sourceType); - - /// - /// 流程启动器调用,节点触发了中断 - /// - /// 被中断的节点Guid - /// 被触发的表达式 - /// 中断类型。0主动监视,1表达式 - void TriggerInterrupt(string nodeGuid, string expression, InterruptTriggerEventArgs.InterruptTriggerType type); - - #endregion - - #region 类库依赖相关 - - /// - /// 从文件中加载Dll - /// - /// - void LoadLibrary(string dllPath); - - /// - /// 移除DLL - /// - /// 程序集的名称 - bool TryUnloadLibrary(string assemblyFullName); - - /// - /// 运行时加载 - /// - /// 文件名 - /// - bool LoadNativeLibraryOfRuning(string file); - - /// - /// 运行时加载指定目录下的类库 - /// - /// 目录 - /// 是否递归加载 - void LoadAllNativeLibraryOfRuning(string path, bool isRecurrence = true); - - #endregion - - #region UI视觉 - - /// - /// 节点定位 - /// - /// - void NodeLocate(string nodeGuid); - - #endregion } + + } diff --git a/Library/Extension/FlowModelExtension.cs b/Library/Extension/FlowModelExtension.cs index 4e8a8d3..fa54879 100644 --- a/Library/Extension/FlowModelExtension.cs +++ b/Library/Extension/FlowModelExtension.cs @@ -200,25 +200,24 @@ namespace Serein.Library /// /// 流程运行 /// - public static async Task StartFlowAsync(this IFlowNode nodeModel, IDynamicContext context, CancellationToken token) + public static async Task StartFlowAsync(this IFlowNode nodeModel, IDynamicContext context, CancellationToken token) { Stack stack = new Stack(); HashSet processedNodes = new HashSet(); // 用于记录已处理上游节点的节点 stack.Push(nodeModel); - while (context.RunState != RunState.Completion // 没有完成 - && token.IsCancellationRequested == false // 没有取消 - && stack.Count > 0) // 循环中直到栈为空才会退出循环 + + while (true) { -#if DEBUG - await Task.Delay(1); -#endif + if (token.IsCancellationRequested) + { + throw new Exception($"流程执行被取消,未能获取到流程结果。"); + } #region 执行相关 // 从栈中弹出一个节点作为当前节点进行处理 var currentNode = stack.Pop(); context.NextOrientation = ConnectionInvokeType.None; // 重置上下文状态 - - FlowResult flowResult; + FlowResult flowResult = null; try { flowResult = await currentNode.ExecutingAsync(context, token); @@ -230,18 +229,15 @@ namespace Serein.Library } catch (Exception ex) { - flowResult = new FlowResult(currentNode,context); + flowResult = new FlowResult(currentNode, context); context.Env.WriteLine(InfoType.ERROR, $"节点[{currentNode.Guid}]异常:" + ex); context.NextOrientation = ConnectionInvokeType.IsError; context.ExceptionOfRuning = ex; } #endregion - #region 执行完成 - //var ignodeState = context.GetIgnodeFlowStateUpload(currentNode); - // 更新数据 - //if(!ignodeState) - context.AddOrUpdate(currentNode, flowResult); // 上下文中更新数据 + #region 执行完成时更新栈 + context.AddOrUpdate(currentNode, flowResult); // 上下文中更新数据 // 首先将指定类别后继分支的所有节点逆序推入栈中 var nextNodes = currentNode.SuccessorNodes[context.NextOrientation]; @@ -255,6 +251,7 @@ namespace Serein.Library stack.Push(nextNodes[index]); } } + // 然后将指上游分支的所有节点逆序推入栈中 var upstreamNodes = currentNode.SuccessorNodes[ConnectionInvokeType.Upstream]; for (int index = upstreamNodes.Count - 1; index >= 0; index--) @@ -262,17 +259,40 @@ namespace Serein.Library // 筛选出启用的节点的节点 if (upstreamNodes[index].DebugSetting.IsEnable) { - //if (!ignodeState) - context.SetPreviousNode(upstreamNodes[index], currentNode); + context.SetPreviousNode(upstreamNodes[index], currentNode); stack.Push(upstreamNodes[index]); } } - //context.RecoverIgnodeFlowStateUpload(currentNode); #endregion + #region 执行完成后检查 + + if (stack.Count == 0) + { + return flowResult; // 说明流程到了终点 + } + + if (context.RunState == RunState.Completion) + { + currentNode.Env.WriteLine(InfoType.INFO, $"流程执行到节点[{currentNode.Guid}]时提前结束,将返回当前执行结果。"); + return flowResult; // 流程执行完成,返回结果 + } + + if (token.IsCancellationRequested) + { + throw new Exception($"流程执行到节点[{currentNode.Guid}]时被取消,未能获取到流程结果。"); + } + + + #endregion +#if DEBUG + await Task.Delay(1); +#endif } + } + /// /// 获取对应的参数数组 /// @@ -478,5 +498,12 @@ namespace Serein.Library } #endif + + + + + + + } } diff --git a/Library/FlowNode/FlowResult.cs b/Library/FlowNode/FlowResult.cs index d847ae6..40fb360 100644 --- a/Library/FlowNode/FlowResult.cs +++ b/Library/FlowNode/FlowResult.cs @@ -32,10 +32,11 @@ namespace Serein.Library /// public FlowResult(IFlowNode nodeModel, IDynamicContext context, object value) { - this.NodeGuid = nodeModel.Guid; + this.Source = nodeModel; this.ContextGuid = context.Guid; this.Value = value; } + /// /// 空返回值 /// @@ -43,10 +44,11 @@ namespace Serein.Library /// public FlowResult(IFlowNode nodeModel, IDynamicContext context) { - this.NodeGuid = nodeModel.Guid; + this.Source = nodeModel; this.ContextGuid = context.Guid; this.Value = Unit.Default; } + /// /// 尝试获取值 /// @@ -74,7 +76,7 @@ namespace Serein.Library /// /// 来源节点Guid /// - public string NodeGuid { get; } + public IFlowNode Source{ get; } /// /// 来源上下文Guid /// @@ -83,6 +85,7 @@ namespace Serein.Library /// 数据值 /// public object Value { get; private set; } + /// /// 生成时间 /// diff --git a/NodeFlow/Env/FlowControl.cs b/NodeFlow/Env/FlowControl.cs new file mode 100644 index 0000000..4fbfe58 --- /dev/null +++ b/NodeFlow/Env/FlowControl.cs @@ -0,0 +1,375 @@ +using Serein.Library; +using Serein.Library.Api; +using Serein.Library.Utils; +using Serein.NodeFlow.Model; +using Serein.NodeFlow.Services; +using Serein.NodeFlow.Tool; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using static Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser; + +namespace Serein.NodeFlow.Env +{ + + internal class FlowControl : IFlowControl + { + private readonly IFlowEnvironment flowEnvironment; + private readonly IFlowEnvironmentEvent flowEnvironmentEvent; + private readonly FlowLibraryService flowLibraryService; + private readonly FlowOperationService flowOperationService; + private readonly FlowModelService flowModelService; + private readonly UIContextOperation UIContextOperation; + + public FlowControl(IFlowEnvironment flowEnvironment, + IFlowEnvironmentEvent flowEnvironmentEvent, + FlowLibraryService flowLibraryService, + FlowOperationService flowOperationService, + FlowModelService flowModelService, + UIContextOperation UIContextOperation) + { + this.flowEnvironment = flowEnvironment; + this.flowEnvironmentEvent = flowEnvironmentEvent; + this.flowLibraryService = flowLibraryService; + this.flowOperationService = flowOperationService; + this.flowModelService = flowModelService; + this.UIContextOperation = UIContextOperation; + contexts = new ObjectPool(() => new DynamicContext(flowEnvironment)); + } + + private ObjectPool contexts; + private FlowWorkManagement flowWorkManagement; + private ISereinIOC sereinIOC; + + + /// + /// 如果全局触发器还在运行,则为 Running 。 + /// + private RunState FlipFlopState = RunState.NoStart; + + + /// + /// 异步运行 + /// + /// + public async Task StartFlowAsync(string[] canvasGuids) + { + #region 校验参数 + HashSet guids = new HashSet(); + bool isBreak = false; + foreach (var canvasGuid in canvasGuids) + { + if (guids.Contains(canvasGuid)) + { + flowEnvironment.WriteLine(InfoType.WARN, $"画布重复,停止运行。{canvasGuid}"); + isBreak = true; + } + else if (!flowModelService.ContainsCanvasModel(canvasGuid)) + { + SereinEnv.WriteLine(InfoType.WARN, $"画布不存在,停止运行。{canvasGuid}"); + isBreak = true; + } + else if (!flowModelService.IsExsitNodeOnCanvas(canvasGuid)) + { + SereinEnv.WriteLine(InfoType.WARN, $"画布没有节点,停止运行。{canvasGuid}"); + isBreak = true; + } + else + { + guids.Add(canvasGuid); + } + } + if (isBreak) + { + guids.Clear(); + return false; + } + #endregion + + + #region 初始化每个画布的数据,转换为流程任务 + Dictionary flowTasks = []; + foreach (var guid in guids) + { + if (!flowModelService.TryGetCanvasModel(guid, out var canvasModel)) + { + SereinEnv.WriteLine(InfoType.WARN, $"画布不存在,停止运行。{guid}"); + return false; + } + var ft = new FlowTask(); + ft.GetNodes = () => flowModelService.GetAllNodeModel(guid); + if (canvasModel.StartNode?.Guid is null) + { + SereinEnv.WriteLine(InfoType.WARN, $"画布不存在起始节点,将停止运行。{guid}"); + return false; + } + ft.GetStartNode = () => canvasModel.StartNode; + flowTasks.Add(guid, ft); + } + #endregion + + sereinIOC.Reset(); + sereinIOC.Register(() => flowEnvironment); + sereinIOC.Register(); // 注册脚本接口 + + var flowTaskOptions = new FlowWorkOptions + { + Environment = flowEnvironment, // 流程 + Flows = flowTasks, + FlowContextPool = contexts, // 上下文对象池 + AutoRegisterTypes = flowLibraryService.GetaAutoRegisterType(), // 需要自动实例化的类型 + InitMds = flowLibraryService.GetMdsOnFlowStart(NodeType.Init), + LoadMds = flowLibraryService.GetMdsOnFlowStart(NodeType.Loading), + ExitMds = flowLibraryService.GetMdsOnFlowStart(NodeType.Exit), + }; + + + + flowWorkManagement = new FlowWorkManagement(flowTaskOptions); + var cts = new CancellationTokenSource(); + try + { + var t = await flowWorkManagement.RunAsync(cts.Token); + } + catch (Exception ex) + { + SereinEnv.WriteLine(ex); + } + finally + { + + SereinEnv.WriteLine(InfoType.INFO, $"流程运行完毕{Environment.NewLine}"); ; + } + flowTaskOptions = null; + return true; + } + + + /// + /// 从选定节点开始运行 + /// + /// + /// + public async Task StartFlowFromSelectNodeAsync(string startNodeGuid) + { + + var flowTaskOptions = new FlowWorkOptions + { + Environment = flowEnvironment, // 流程 + FlowContextPool = contexts, // 上下文对象池 + }; + var flowTaskManagement = new FlowWorkManagement(flowTaskOptions); + + if (true || flowEnvironment.FlowState == RunState.Running || FlipFlopState == RunState.Running) + { + + if (!flowModelService.TryGetNodeModel(startNodeGuid, out var nodeModel) || nodeModel is SingleFlipflopNode) + { + return false; + } + await flowTaskManagement.StartFlowInSelectNodeAsync(nodeModel); + return true; + } + else + { + return false; + } + } + + /*/// + /// 单独运行一个节点 + /// + /// + /// + public async Task InvokeNodeAsync(IDynamicContext context, string nodeGuid) + { + object result = Unit.Default; + if (this.NodeModels.TryGetValue(nodeGuid, out var model)) + { + CancellationTokenSource cts = new CancellationTokenSource(); + result = await model.ExecutingAsync(context, cts.Token); + cts?.Cancel(); + } + return result; + }*/ + + /// + /// 结束流程 + /// + public Task ExitFlowAsync() + { + flowWorkManagement?.Exit(); + UIContextOperation?.Invoke(() => flowEnvironmentEvent.OnFlowRunComplete(new FlowEventArgs())); + sereinIOC.Reset(); + flowWorkManagement = null; + GC.Collect(); + return Task.FromResult(true); + } + + /// + /// 激活全局触发器 + /// + /// + public void ActivateFlipflopNode(string nodeGuid) + { + /*if (!TryGetNodeModel(nodeGuid, out var nodeModel)) + { + return; + } + if (nodeModel is null) return; + if (flowTaskManagement is not null && nodeModel is SingleFlipflopNode flipflopNode) // 子节点为触发器 + { + if (FlowState != RunState.Completion + && flipflopNode.NotExitPreviousNode()) // 正在运行,且该触发器没有上游节点 + { + _ = flowTaskManagement.RunGlobalFlipflopAsync(this, flipflopNode);// 被父节点移除连接关系的子节点若为触发器,且无上级节点,则当前流程正在运行,则加载到运行环境中 + + } + }*/ + } + + /// + /// 关闭全局触发器 + /// + /// + public void TerminateFlipflopNode(string nodeGuid) + { + /* if (!TryGetNodeModel(nodeGuid, out var nodeModel)) + { + return; + } + if (nodeModel is null) return; + if (flowTaskManagement is not null && nodeModel is SingleFlipflopNode flipflopNode) // 子节点为触发器 + { + flowTaskManagement.TerminateGlobalFlipflopRuning(flipflopNode); + }*/ + } + /// + public void UseExternalIOC(ISereinIOC ioc) + { + this.sereinIOC = ioc; // 设置IOC容器 + } + + /// + /// 启动器调用,运行到某个节点时触发了监视对象的更新(对象预览视图将会自动更新) + /// + /// + /// + /// + public void MonitorObjectNotification(string nodeGuid, object monitorData, MonitorObjectEventArgs.ObjSourceType sourceType) + { + flowEnvironmentEvent.OnMonitorObjectChanged(new MonitorObjectEventArgs(nodeGuid, monitorData, sourceType)); + } + + /// + /// 启动器调用,节点触发了中断。 + /// + /// 节点 + /// 表达式 + /// 类型,0用户主动的中断,1表达式中断 + public void TriggerInterrupt(string nodeGuid, string expression, InterruptTriggerEventArgs.InterruptTriggerType type) + { + flowEnvironmentEvent.OnInterruptTriggered(new InterruptTriggerEventArgs(nodeGuid, expression, type)); + } + + + + + #region 流程接口调用 + + + /// + /// 调用流程接口,将返回 FlowResult.Value。如果需要 FlowResult 对象,请使用该方法的泛型版本。 + /// + /// 流程接口节点Guid + /// 调用时入参参数 + /// + /// + public async Task ApiInvokeAsync(string apiGuid, object[] param) + { + if (sereinIOC is null) + { + sereinIOC = flowEnvironment.IOC; + } + if (!flowModelService.TryGetNodeModel(apiGuid, out var nodeModel)) + { + throw new ArgumentNullException($"不存在流程接口:{apiGuid}"); + } + if (nodeModel is not SingleFlowCallNode flowCallNode) + { + throw new ArgumentNullException($"目标节点并非流程接口:{apiGuid}"); + } + var context = contexts.Allocate(); + CancellationTokenSource cts = new CancellationTokenSource(); + var flowResult = await flowCallNode.StartFlowAsync(context, cts.Token); + return flowResult.Value; + } + + /// + /// 调用流程接口,泛型类型为 FlowResult 时,将返回 FlowResult 对象。 + /// + /// + /// 流程接口节点Guid + /// 调用时入参参数 + /// + /// + public async Task ApiInvokeAsync(string apiGuid, object[] param) + { + if (sereinIOC is null) + { + sereinIOC = flowEnvironment.IOC; + } + if (!flowModelService.TryGetNodeModel(apiGuid, out var nodeModel)) + { + throw new ArgumentNullException($"不存在流程接口:{apiGuid}"); + } + if (nodeModel is not SingleFlowCallNode flowCallNode) + { + throw new ArgumentNullException($"目标节点并非流程接口:{apiGuid}"); + } + var context = contexts.Allocate(); + CancellationTokenSource cts = new CancellationTokenSource(); + var flowResult = await flowCallNode.StartFlowAsync(context, cts.Token); + + if (flowResult.Value is TResult result) + { + return result; + } + else if (flowResult is FlowResult && flowResult is TResult result2) + { + return result2; + } + else + { + throw new ArgumentNullException($"类型转换失败,流程返回数据与泛型不匹配,当前返回类型为[{flowResult.Value.GetType().FullName}]。"); + } + } + + private bool IsHasSuccessorNodes(IFlowNode nodeModel) + { + var nextTypes = new[] + { + ConnectionInvokeType.Upstream, + ConnectionInvokeType.IsSucceed, + ConnectionInvokeType.IsFail, + ConnectionInvokeType.IsError + }; + foreach (var type in nextTypes) + { + if (nodeModel.SuccessorNodes.TryGetValue(type, out var nextNodes)) + { + if(nextNodes.Count > 0) + { + return true; + } + } + } + return false; + } + + #endregion + } +} diff --git a/NodeFlow/Env/FlowEdit.cs b/NodeFlow/Env/FlowEdit.cs new file mode 100644 index 0000000..cb6d018 --- /dev/null +++ b/NodeFlow/Env/FlowEdit.cs @@ -0,0 +1,568 @@ +using Serein.Library; +using Serein.Library.Api; +using Serein.Library.Utils; +using Serein.NodeFlow.Model; +using Serein.NodeFlow.Model.Operation; +using Serein.NodeFlow.Services; +using Serein.NodeFlow.Tool; +using static Serein.Library.Api.IFlowEnvironment; + +namespace Serein.NodeFlow.Env +{ + + /// + /// 流程编辑接口实现 + /// + internal class FlowEdit : IFlowEdit + { + public FlowEdit(IFlowEnvironment flowEnvironment, + IFlowEnvironmentEvent flowEnvironmentEvent, + FlowLibraryService flowLibraryManagement, + FlowOperationService flowOperationService, + FlowModelService flowModelService, + UIContextOperation UIContextOperation, + ISereinIOC sereinIOC, + NodeMVVMService nodeMVVMService) + { + this.flowEnvironment = flowEnvironment; + this.flowEnvironmentEvent = flowEnvironmentEvent; + this.flowLibraryManagement = flowLibraryManagement; + this.flowOperationService = flowOperationService; + this.flowModelService = flowModelService; + this.UIContextOperation = UIContextOperation; + NodeMVVMManagement = nodeMVVMService; + InitNodeMVVM(nodeMVVMService); + } + + + /// + public NodeMVVMService NodeMVVMManagement { get; } + + private readonly IFlowEnvironment flowEnvironment; + private readonly IFlowEnvironmentEvent flowEnvironmentEvent; + private readonly FlowLibraryService flowLibraryManagement; + private readonly FlowOperationService flowOperationService; + private readonly FlowModelService flowModelService; + private readonly NodeMVVMService nodeMVVMService; + + + /// + /// 注册基本节点类型 + /// + private void InitNodeMVVM(NodeMVVMService nodeMVVMService) + { + nodeMVVMService.RegisterModel(NodeControlType.UI, typeof(SingleUINode)); // 动作节点 + nodeMVVMService.RegisterModel(NodeControlType.Action, typeof(SingleActionNode)); // 动作节点 + nodeMVVMService.RegisterModel(NodeControlType.Flipflop, typeof(SingleFlipflopNode)); // 触发器节点 + nodeMVVMService.RegisterModel(NodeControlType.ExpOp, typeof(SingleExpOpNode)); // 表达式节点 + nodeMVVMService.RegisterModel(NodeControlType.ExpCondition, typeof(SingleConditionNode)); // 条件表达式节点 + nodeMVVMService.RegisterModel(NodeControlType.GlobalData, typeof(SingleGlobalDataNode)); // 全局数据节点 + nodeMVVMService.RegisterModel(NodeControlType.Script, typeof(SingleScriptNode)); // 脚本节点 + nodeMVVMService.RegisterModel(NodeControlType.NetScript, typeof(SingleNetScriptNode)); // 脚本节点 + nodeMVVMService.RegisterModel(NodeControlType.FlowCall, typeof(SingleFlowCallNode)); // 流程调用节点 + } + + + private UIContextOperation UIContextOperation; + + + + /// + /// 从Guid获取画布 + /// + /// 节点Guid + /// 节点Model + /// 无法获取节点、Guid/节点为null时报错 + public bool TryGetCanvasModel(string nodeGuid, out FlowCanvasDetails canvasDetails) + { + if (string.IsNullOrEmpty(nodeGuid)) + { + canvasDetails = null; + return false; + } + return flowModelService.TryGetCanvasModel(nodeGuid, out canvasDetails); + + } + + /// + /// 从Guid获取节点 + /// + /// 节点Guid + /// 节点Model + /// 无法获取节点、Guid/节点为null时报错 + public bool TryGetNodeModel(string nodeGuid, out IFlowNode nodeModel) + { + if (string.IsNullOrEmpty(nodeGuid)) + { + nodeModel = null; + return false; + } + return flowModelService.TryGetNodeModel(nodeGuid, out nodeModel); + + } + + #region 私有方法 + + /// + /// 从节点信息创建节点,并返回状态指示是否创建成功 + /// + /// + /// + private bool CreateNodeFromNodeInfo(NodeInfo nodeInfo) + { + if (!EnumHelper.TryConvertEnum(nodeInfo.Type, out var controlType)) + { + return false; + } + + #region 获取方法描述 + MethodDetails? methodDetails; + if (controlType == NodeControlType.FlowCall) + { + if (string.IsNullOrEmpty(nodeInfo.MethodName)) + { + methodDetails = new MethodDetails(); + methodDetails.ParamsArgIndex = 0; + methodDetails.ParameterDetailss = new ParameterDetails[nodeInfo.ParameterData.Length]; + for (int i = 0; i < methodDetails.ParameterDetailss.Length; i++) + { + var pdInfo = nodeInfo.ParameterData[i]; + var t = new ParameterDetailsInfo(); + var pd = new ParameterDetails(pdInfo, i); + methodDetails.ParameterDetailss[i] = pd; + } + } + else + { + // 目标节点可能是方法节点 + flowLibraryManagement.TryGetMethodDetails(nodeInfo.AssemblyName, nodeInfo.MethodName, out methodDetails); // 加载项目时尝试获取方法信息 + } + } + else if (controlType.IsBaseNode()) + { + // 加载基础节点 + methodDetails = new MethodDetails(); + + } + else + { + if (string.IsNullOrEmpty(nodeInfo.MethodName)) return false; + // 加载方法节点 + flowLibraryManagement.TryGetMethodDetails(nodeInfo.AssemblyName, nodeInfo.MethodName, out methodDetails); // 加载项目时尝试获取方法信息 + } + #endregion + + var nodeModel = FlowNodeExtension.CreateNode(flowEnvironment, controlType, methodDetails); // 加载项目时创建节点 + if (nodeModel is null) + { + nodeInfo.Guid = string.Empty; + return false; + } + if (TryGetCanvasModel(nodeInfo.CanvasGuid, out var canvasModel)) + { + + // 节点与画布互相绑定 + // 需要在UI线程上进行添加,否则会报 “不支持从调度程序线程以外的线程对其 SourceCollection 进行的更改”异常 + nodeModel.CanvasDetails = canvasModel; + UIContextOperation?.Invoke(() => canvasModel.Nodes.Add(nodeModel)); + + nodeModel.LoadInfo(nodeInfo); // 创建节点model + TryAddNode(nodeModel); // 加载项目时将节点加载到环境中 + } + else + { + SereinEnv.WriteLine(InfoType.ERROR, $"加载节点[{nodeInfo.Guid}]时发生异常,画布[{nodeInfo.CanvasGuid}]不存在"); + return false; + } + + UIContextOperation?.Invoke(() => + flowEnvironmentEvent.OnNodeCreated(new NodeCreateEventArgs(nodeInfo.CanvasGuid, nodeModel, nodeInfo.Position))); // 添加到UI上 + return true; + } + + + + /// + /// 创建节点 + /// + /// + private bool TryAddNode(IFlowNode nodeModel) + { + nodeModel.Guid ??= Guid.NewGuid().ToString(); + flowModelService.AddNodeModel(nodeModel); + + + // 如果是触发器,则需要添加到专属集合中 + /*if (nodeModel is SingleFlipflopNode flipflopNode) + { + var guid = flipflopNode.Guid; + if (!FlipflopNodes.Exists(it => it.Guid.Equals(guid))) + { + FlipflopNodes.Add(flipflopNode); + } + }*/ + return true; + } + #endregion + + + #region 流程接口 + + private int _add_canvas_count = 1; + + + + public void CreateCanvas(string canvasName, int width, int height) + { + IOperation operation = new CreateCanvasOperation + { + CanvasInfo = new FlowCanvasDetailsInfo + { + Name = $"Canvas {_add_canvas_count++}", + Width = width, + Height = height, + Guid = Guid.NewGuid().ToString(), + ScaleX = 1.0f, + ScaleY = 1.0f, + } + }; + + flowOperationService.Execute(operation); + } + + public void RemoveCanvas(string canvasGuid) + { + IOperation operation = new RemoveCanvasOperation + { + CanvasGuid = canvasGuid + }; + flowOperationService.Execute(operation); + } + + public void ConnectInvokeNode(string canvasGuid, string fromNodeGuid, string toNodeGuid, JunctionType fromNodeJunctionType, JunctionType toNodeJunctionType, ConnectionInvokeType invokeType) + { + IOperation operation = new ChangeNodeConnectionOperation + { + CanvasGuid = canvasGuid, + FromNodeGuid = fromNodeGuid, + ToNodeGuid = toNodeGuid, + FromNodeJunctionType = fromNodeJunctionType, + ToNodeJunctionType = toNodeJunctionType, + ConnectionInvokeType = invokeType, + ChangeType = NodeConnectChangeEventArgs.ConnectChangeType.Create, + JunctionOfConnectionType = JunctionOfConnectionType.Invoke, + }; + + flowOperationService.Execute(operation); + } + + public void ConnectArgSourceNode(string canvasGuid, string fromNodeGuid, string toNodeGuid, JunctionType fromNodeJunctionType, JunctionType toNodeJunctionType, ConnectionArgSourceType argSourceType, int argIndex) + { + IOperation operation = new ChangeNodeConnectionOperation + { + CanvasGuid = canvasGuid, + FromNodeGuid = fromNodeGuid, + ToNodeGuid = toNodeGuid, + FromNodeJunctionType = fromNodeJunctionType, + ToNodeJunctionType = toNodeJunctionType, + ConnectionArgSourceType = argSourceType, + ArgIndex = argIndex, + ChangeType = NodeConnectChangeEventArgs.ConnectChangeType.Create, + JunctionOfConnectionType = JunctionOfConnectionType.Arg, + }; + flowOperationService.Execute(operation); + } + + public void RemoveInvokeConnect(string canvasGuid, string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType) + { + IOperation operation = new ChangeNodeConnectionOperation + { + CanvasGuid = canvasGuid, + FromNodeGuid = fromNodeGuid, + ToNodeGuid = toNodeGuid, + ConnectionInvokeType = connectionType, + ChangeType = NodeConnectChangeEventArgs.ConnectChangeType.Remove, + }; + flowOperationService.Execute(operation); + } + + public void RemoveArgSourceConnect(string canvasGuid, string fromNodeGuid, string toNodeGuid, int argIndex) + { + IOperation operation = new ChangeNodeConnectionOperation + { + CanvasGuid = canvasGuid, + FromNodeGuid = fromNodeGuid, + ToNodeGuid = toNodeGuid, + ArgIndex = argIndex, + ChangeType = NodeConnectChangeEventArgs.ConnectChangeType.Remove + }; + flowOperationService.Execute(operation); + } + + public void CreateNode(string canvasGuid, NodeControlType nodeType, PositionOfUI position, MethodDetailsInfo methodDetailsInfo = null) + { + IOperation operation = new CreateNodeOperation + { + CanvasGuid = canvasGuid, + NodeControlType = nodeType, + Position = position, + MethodDetailsInfo = methodDetailsInfo + }; + flowOperationService.Execute(operation); + } + + public void RemoveNode(string canvasGuid, string nodeGuid) + { + IOperation operation = new RemoveNodeOperation + { + CanvasGuid = canvasGuid, + NodeGuid = nodeGuid + }; + flowOperationService.Execute(operation); + } + + public void PlaceNodeToContainer(string canvasGuid, string nodeGuid, string containerNodeGuid) + { + IOperation operation = new ContainerPlaceNodeOperation + { + CanvasGuid = canvasGuid, + NodeGuid = nodeGuid, + ContainerNodeGuid = containerNodeGuid + }; + flowOperationService.Execute(operation); + } + + public void TakeOutNodeToContainer(string canvasGuid, string nodeGuid) + { + IOperation operation = new ContainerTakeOutNodeOperation + { + CanvasGuid = canvasGuid, + NodeGuid = nodeGuid, + }; + flowOperationService.Execute(operation); + } + + public void SetStartNode(string canvasGuid, string nodeGuid) + { + if (!TryGetCanvasModel(canvasGuid, out var canvasModel) || !TryGetNodeModel(nodeGuid, out var newStartNodeModel)) + { + return; + } + var oldNodeGuid = canvasModel.StartNode?.Guid; + /*if(TryGetNodeModel(oldNodeGuid, out var newStartNodeModel)) + { + newStartNode.IsStart = false; + }*/ + canvasModel.StartNode = newStartNodeModel; + //newStartNode.IsStart = true; + UIContextOperation?.Invoke(() => flowEnvironmentEvent.OnStartNodeChanged(new StartNodeChangeEventArgs(canvasGuid, oldNodeGuid, newStartNodeModel.Guid))); + return; + } + + public void SetConnectPriorityInvoke(string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType) + { + + IOperation operation = new ChangeNodeConnectionOperation + { + CanvasGuid = string.Empty, // 连接优先级不需要画布 + FromNodeGuid = fromNodeGuid, + ToNodeGuid = toNodeGuid, + ConnectionInvokeType = connectionType, + ChangeType = NodeConnectChangeEventArgs.ConnectChangeType.Create + }; + flowOperationService.Execute(operation); + } + + public void ChangeParameter(string nodeGuid, bool isAdd, int paramIndex) + { + IOperation operation = new ChangeParameterOperation + { + NodeGuid = nodeGuid, + IsAdd = isAdd, + ParamIndex = paramIndex + }; + flowOperationService.Execute(operation); + } + + /// + /// 从节点信息集合批量加载节点控件 + /// + /// 节点信息 + /// + /// + 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) && + TryGetNodeModel(nodeInfo.ParentNodeGuid, out var parentNode)) + { + needPlaceNodeInfos.Add(nodeInfo); // 需要重新放置的节点 + } + } + + foreach (NodeInfo nodeInfo in needPlaceNodeInfos) + { + if (TryGetNodeModel(nodeInfo.Guid, out var nodeModel) && + TryGetNodeModel(nodeInfo.ParentNodeGuid, out var containerNode) + && containerNode is INodeContainer nodeContainer) + { + var result = nodeContainer.PlaceNode(nodeModel); + if (result) + { + UIContextOperation?.Invoke(() => flowEnvironmentEvent.OnNodePlace( + new NodePlaceEventArgs(nodeInfo.CanvasGuid, nodeModel.Guid, containerNode.Guid))); + } + + + } + } + #endregion + + await Task.Delay(100); + #region 确定节点之间的方法调用关系 + foreach (var nodeInfo in nodeInfos) + { + var canvasGuid = nodeInfo.CanvasGuid; + if (!TryGetNodeModel(nodeInfo.Guid, out var fromNodeModel)) + { + return; + } + if (fromNodeModel is null) continue; + List<(ConnectionInvokeType connectionType, string[] guids)> allToNodes = [(ConnectionInvokeType.IsSucceed,nodeInfo.TrueNodes), + (ConnectionInvokeType.IsFail, nodeInfo.FalseNodes), + (ConnectionInvokeType.IsError, nodeInfo.ErrorNodes), + (ConnectionInvokeType.Upstream, nodeInfo.UpstreamNodes)]; + foreach ((ConnectionInvokeType connectionType, string[] toNodeGuids) item in allToNodes) + { + // 遍历当前类型分支的节点(确认连接关系) + foreach (var toNodeGuid in item.toNodeGuids) + { + if (!TryGetNodeModel(toNodeGuid, out var toNodeModel)) + { + return; + } + if (toNodeModel is null) + { + // 防御性代码,加载正常保存的项目文件不会进入这里 + continue; + } + + ConnectInvokeNode(canvasGuid, fromNodeModel.Guid, toNodeModel.Guid, JunctionType.NextStep, JunctionType.Execute, item.connectionType); + + //var isSuccessful = ConnectInvokeOfNode(canvasGuid, fromNodeModel, toNodeModel, item.connectionType); // 加载时确定节点间的连接关系 + } + } + + + //List<(ConnectionInvokeType connectionType, string[] guids)> allToNodes = [(ConnectionInvokeType.IsSucceed,nodeInfo.TrueNodes), + // (ConnectionInvokeType.IsFail, nodeInfo.FalseNodes), + // (ConnectionInvokeType.IsError, nodeInfo.ErrorNodes), + // (ConnectionInvokeType.Upstream, nodeInfo.UpstreamNodes)]; + + //List<(ConnectionInvokeType, NodeModelBase[])> fromNodes = allToNodes.Where(info => info.guids.Length > 0) + // .Select(info => (info.connectionType, + // info.guids.Where(guid => NodeModels.ContainsKey(guid)).Select(guid => NodeModels[guid]) + // .ToArray())) + // .ToList(); + // 遍历每种类型的节点分支(四种) + //foreach ((ConnectionInvokeType connectionType, NodeModelBase[] toNodes) item in nodeInfo) + //{ + // // 遍历当前类型分支的节点(确认连接关系) + // foreach (var toNode in item.toNodes) + // { + // _ = ConnectInvokeOfNode(fromNode, toNode, item.connectionType); // 加载时确定节点间的连接关系 + // } + //} + } + #endregion + + #region 确定节点之间的参数调用关系 + var nodeModels = flowModelService.GetAllNodeModel(); + foreach (var toNode in nodeModels) + { + var canvasGuid = toNode.CanvasDetails.Guid; + if (toNode.MethodDetails.ParameterDetailss == null) + { + continue; + } + for (var i = 0; i < toNode.MethodDetails.ParameterDetailss.Length; i++) + { + var pd = toNode.MethodDetails.ParameterDetailss[i]; + if (!string.IsNullOrEmpty(pd.ArgDataSourceNodeGuid) + && TryGetNodeModel(pd.ArgDataSourceNodeGuid, out var fromNode)) + { + + ConnectArgSourceNode(canvasGuid, fromNode.Guid, toNode.Guid, JunctionType.ReturnData, JunctionType.ArgData, pd.ArgDataSourceType, pd.Index); + } + } + } + #endregion + + + UIContextOperation?.Invoke(() => + { + flowEnvironmentEvent.OnProjectLoaded(new ProjectLoadedEventArgs()); + }); + + return; + } + #endregion + + + #region 视觉效果 + + /// + /// 定位节点 + /// + /// + public void NodeLocate(string nodeGuid) + { + if (OperatingSystem.IsWindows()) + { + UIContextOperation?.Invoke(() => flowEnvironmentEvent.OnNodeLocated(new NodeLocatedEventArgs(nodeGuid))); + } + + } + + + #endregion + } + + + +} diff --git a/NodeFlow/Env/FlowEnvironment.cs b/NodeFlow/Env/FlowEnvironment.cs index cb52fd3..c82cdd6 100644 --- a/NodeFlow/Env/FlowEnvironment.cs +++ b/NodeFlow/Env/FlowEnvironment.cs @@ -45,6 +45,9 @@ namespace Serein.NodeFlow.Env /// public class FlowEnvironment : IFlowEnvironment { + /// + /// 流程运行环境构造函数 + /// public FlowEnvironment() { ISereinIOC ioc = new SereinIOC(); @@ -52,6 +55,8 @@ namespace Serein.NodeFlow.Env .Register(()=> ioc) // 注册IOC .Register(() => this) .Register() + .Register() + .Register() .Register() .Register() .Register() @@ -63,7 +68,7 @@ namespace Serein.NodeFlow.Env currentFlowEnvironmentEvent = ioc.Get(); SereinEnv.SetEnv(currentFlowEnvironment); } - +/* /// /// 本地环境事件 /// @@ -73,7 +78,7 @@ namespace Serein.NodeFlow.Env /// 远程环境事件 /// private IFlowEnvironmentEvent remoteFlowEnvironmentEvent; - + */ /// /// 管理当前环境 @@ -86,9 +91,9 @@ namespace Serein.NodeFlow.Env /// private IFlowEnvironmentEvent currentFlowEnvironmentEvent; + + private int _loadingProjectFlag = 0; // 使用原子自增代替锁 - - /// /// 传入false时,将停止数据通知。传入true时, /// @@ -110,8 +115,12 @@ namespace Serein.NodeFlow.Env public IFlowEnvironment CurrentEnv => currentFlowEnvironment; /// public UIContextOperation UIContextOperation => currentFlowEnvironment.UIContextOperation; + /// - public NodeMVVMService NodeMVVMManagement => currentFlowEnvironment.NodeMVVMManagement; + public IFlowEdit FlowEdit => currentFlowEnvironment.FlowEdit; + + /// + public IFlowControl FlowControl => currentFlowEnvironment.FlowControl; /// public ISereinIOC IOC => currentFlowEnvironment.IOC; @@ -138,172 +147,10 @@ namespace Serein.NodeFlow.Env /// public RunState FlowState { get => currentFlowEnvironment.FlowState; set => currentFlowEnvironment.FlowState = value; } - /// - public event LoadDllHandler DllLoad { - add { currentFlowEnvironmentEvent.DllLoad += value; } - remove { currentFlowEnvironmentEvent.DllLoad -= value; } - } - - /// - public event ProjectLoadedHandler ProjectLoaded - { - add { currentFlowEnvironmentEvent.ProjectLoaded += value; } - remove { currentFlowEnvironmentEvent.ProjectLoaded -= value; } - } - - /// - public event ProjectSavingHandler? ProjectSaving - { - add { currentFlowEnvironmentEvent.ProjectSaving += value; } - remove { currentFlowEnvironmentEvent.ProjectSaving -= value; } - } - - /// - public event NodeConnectChangeHandler NodeConnectChanged - { - add { currentFlowEnvironmentEvent.NodeConnectChanged += value; } - remove { currentFlowEnvironmentEvent.NodeConnectChanged -= value; } - } - - /// - public event CanvasCreateHandler CanvasCreated - { - add { currentFlowEnvironmentEvent.CanvasCreated += value; } - remove { currentFlowEnvironmentEvent.CanvasCreated -= value; } - } - - /// - public event CanvasRemoveHandler CanvasRemoved - { - add { currentFlowEnvironmentEvent.CanvasRemoved += value; } - remove { currentFlowEnvironmentEvent.CanvasRemoved -= value; } - } - - /// - public event NodeCreateHandler NodeCreated - { - add { currentFlowEnvironmentEvent.NodeCreated += value; } - remove { currentFlowEnvironmentEvent.NodeCreated -= value; } - } - - /// - public event NodeRemoveHandler NodeRemoved - { - add { currentFlowEnvironmentEvent.NodeRemoved += value; } - remove { currentFlowEnvironmentEvent.NodeRemoved -= value; } - } - - /// - public event NodePlaceHandler NodePlace - { - add { currentFlowEnvironmentEvent.NodePlace += value; } - remove { currentFlowEnvironmentEvent.NodePlace -= value; } - } - - /// - public event NodeTakeOutHandler NodeTakeOut - { - add { currentFlowEnvironmentEvent.NodeTakeOut += value; } - remove { currentFlowEnvironmentEvent.NodeTakeOut -= value; } - } - - /// - public event StartNodeChangeHandler StartNodeChanged - { - add { currentFlowEnvironmentEvent.StartNodeChanged += value; } - remove { currentFlowEnvironmentEvent.StartNodeChanged -= value; } - } - - /// - public event FlowRunCompleteHandler FlowRunComplete - { - add { currentFlowEnvironmentEvent.FlowRunComplete += value; } - remove { currentFlowEnvironmentEvent.FlowRunComplete -= value; } - } - - /// - public event MonitorObjectChangeHandler MonitorObjectChanged - { - add { currentFlowEnvironmentEvent.MonitorObjectChanged += value; } - remove { currentFlowEnvironmentEvent.MonitorObjectChanged -= value; } - } - - /// - public event NodeInterruptStateChangeHandler NodeInterruptStateChanged - { - add { currentFlowEnvironmentEvent.NodeInterruptStateChanged += value; } - remove { currentFlowEnvironmentEvent.NodeInterruptStateChanged -= value; } - } - - /// - public event ExpInterruptTriggerHandler InterruptTriggered - { - add { currentFlowEnvironmentEvent.InterruptTriggered += value; } - remove { currentFlowEnvironmentEvent.InterruptTriggered -= value; } - } - - /// - public event IOCMembersChangedHandler IOCMembersChanged - { - add { currentFlowEnvironmentEvent.IOCMembersChanged += value; } - remove { currentFlowEnvironmentEvent.IOCMembersChanged -= value; } - } - - /// - public event NodeLocatedHandler NodeLocated - { - add { currentFlowEnvironmentEvent.NodeLocated += value; } - remove { currentFlowEnvironmentEvent.NodeLocated -= value; } - } - - /// - public event EnvOutHandler EnvOutput - { - add { currentFlowEnvironmentEvent.EnvOutput += value; } - remove { currentFlowEnvironmentEvent.EnvOutput -= value; } - } - - - /// public void ActivateFlipflopNode(string nodeGuid) { - currentFlowEnvironment.ActivateFlipflopNode(nodeGuid); - } - - /// - public void CreateCanvas(string canvasName, int width, int height) - { - currentFlowEnvironment.CreateCanvas(canvasName, width, height); - } - - /// - public void RemoveCanvas(string canvasGuid) - { - currentFlowEnvironment.RemoveCanvas(canvasGuid); - } - - /// - public void ConnectInvokeNode(string canvasGuid, - string fromNodeGuid, - string toNodeGuid, - JunctionType fromNodeJunctionType, - JunctionType toNodeJunctionType, - ConnectionInvokeType invokeType) - { - currentFlowEnvironment.ConnectInvokeNode(canvasGuid, fromNodeGuid, toNodeGuid, fromNodeJunctionType, toNodeJunctionType, invokeType); - } - - /// - public void ConnectArgSourceNode(string canvasGuid, - string fromNodeGuid, - string toNodeGuid, - JunctionType fromNodeJunctionType, - JunctionType toNodeJunctionType, - ConnectionArgSourceType argSourceType, - int argIndex) - { - currentFlowEnvironment.ConnectArgSourceNode(canvasGuid, fromNodeGuid, toNodeGuid, fromNodeJunctionType, toNodeJunctionType, argSourceType, argIndex); + currentFlowEnvironment.FlowControl.ActivateFlipflopNode(nodeGuid); } /// @@ -320,42 +167,10 @@ namespace Serein.NodeFlow.Env return (isConnect, remoteMsgUtil); } - /// - public async Task LoadNodeInfosAsync(List nodeInfos) - { - SetProjectLoadingFlag(false); - await currentFlowEnvironment.LoadNodeInfosAsync(nodeInfos); // 装饰器调用 - SetProjectLoadingFlag(true); - } - - /// - public void CreateNode(string canvasGuid, NodeControlType nodeBase, PositionOfUI position, MethodDetailsInfo methodDetailsInfo = null) - { - SetProjectLoadingFlag(false); - currentFlowEnvironment.CreateNode(canvasGuid, nodeBase, position, methodDetailsInfo); // 装饰器调用 - SetProjectLoadingFlag(true); - } - - /// - public void PlaceNodeToContainer(string canvasGuid, string nodeGuid, string containerNodeGuid) - { - SetProjectLoadingFlag(false); - currentFlowEnvironment.PlaceNodeToContainer(canvasGuid, nodeGuid, containerNodeGuid); // 装饰器调用 - SetProjectLoadingFlag(true); - } - - /// - public void TakeOutNodeToContainer(string canvasGuid, string nodeGuid) - { - SetProjectLoadingFlag(false); - currentFlowEnvironment.TakeOutNodeToContainer(canvasGuid,nodeGuid); // 装饰器调用 - SetProjectLoadingFlag(true); - } - /// public async Task ExitFlowAsync() { - return await currentFlowEnvironment.ExitFlowAsync(); + return await currentFlowEnvironment.FlowControl.ExitFlowAsync(); } /// @@ -401,19 +216,7 @@ namespace Serein.NodeFlow.Env /// public void MonitorObjectNotification(string nodeGuid, object monitorData, MonitorObjectEventArgs.ObjSourceType sourceType) { - currentFlowEnvironment.MonitorObjectNotification(nodeGuid, monitorData, sourceType); - } - - /*/// - public void MoveNode(string canvasGuid, string nodeGuid, double x, double y) - { - currentFlowEnvironment.MoveNode(canvasGuid, nodeGuid, x, y); - } -*/ - /// - public void NodeLocate(string nodeGuid) - { - currentFlowEnvironment.NodeLocate(nodeGuid); + currentFlowEnvironment.FlowControl.MonitorObjectNotification(nodeGuid, monitorData, sourceType); } /// @@ -422,31 +225,6 @@ namespace Serein.NodeFlow.Env return currentFlowEnvironment.TryUnloadLibrary(assemblyName); } - /// - public void SetConnectPriorityInvoke(string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType) - { - currentFlowEnvironment.SetConnectPriorityInvoke(fromNodeGuid, toNodeGuid, connectionType); - } - - /// - public void RemoveInvokeConnect(string canvasGuid, string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType) - { - currentFlowEnvironment.RemoveInvokeConnect(canvasGuid, fromNodeGuid, toNodeGuid, connectionType); - } - - /// - public void RemoveArgSourceConnect(string canvasGuid, string fromNodeGuid, string toNodeGuid, int argIndex) - { - currentFlowEnvironment.RemoveArgSourceConnect(canvasGuid, fromNodeGuid, toNodeGuid, argIndex); - } - - /// - public void RemoveNode(string canvasGuid, string nodeGuid) - { - currentFlowEnvironment.RemoveNode(canvasGuid, nodeGuid); - } - - /// /// 输出信息 /// @@ -489,22 +267,17 @@ namespace Serein.NodeFlow.Env #endregion - /// - public void SetStartNode(string canvasGuid, string nodeGuid) - { - currentFlowEnvironment.SetStartNode(canvasGuid, nodeGuid); - } /// public async Task StartFlowAsync(string[] canvasGuids) { - return await currentFlowEnvironment.StartFlowAsync(canvasGuids); + return await currentFlowEnvironment.FlowControl.StartFlowAsync(canvasGuids); } /// public async Task StartFlowFromSelectNodeAsync(string startNodeGuid) { - return await currentFlowEnvironment.StartFlowFromSelectNodeAsync(startNodeGuid); + return await currentFlowEnvironment.FlowControl.StartFlowFromSelectNodeAsync(startNodeGuid); } /// @@ -522,13 +295,13 @@ namespace Serein.NodeFlow.Env /// public void TerminateFlipflopNode(string nodeGuid) { - currentFlowEnvironment.TerminateFlipflopNode(nodeGuid); + currentFlowEnvironment.FlowControl.TerminateFlipflopNode(nodeGuid); } /// public void TriggerInterrupt(string nodeGuid, string expression, InterruptTriggerEventArgs.InterruptTriggerType type) { - currentFlowEnvironment.TriggerInterrupt(nodeGuid, expression, type); + currentFlowEnvironment.FlowControl.TriggerInterrupt(nodeGuid, expression, type); } /// @@ -545,7 +318,7 @@ namespace Serein.NodeFlow.Env /// public void UseExternalIOC(ISereinIOC ioc) { - currentFlowEnvironment.UseExternalIOC(ioc); + currentFlowEnvironment.FlowControl.UseExternalIOC(ioc); } /// @@ -579,11 +352,6 @@ namespace Serein.NodeFlow.Env } } - /// - public void ChangeParameter(string nodeGuid, bool isAdd, int paramIndex) - { - currentFlowEnvironment.ChangeParameter(nodeGuid, isAdd, paramIndex); - } #region 流程依赖类库的接口 diff --git a/NodeFlow/Env/LocalFlowEnvironment.cs b/NodeFlow/Env/LocalFlowEnvironment.cs index 51ddfcc..aaa3b2e 100644 --- a/NodeFlow/Env/LocalFlowEnvironment.cs +++ b/NodeFlow/Env/LocalFlowEnvironment.cs @@ -3,8 +3,6 @@ using Serein.Library.Api; 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 Serein.Script.Node; @@ -17,6 +15,7 @@ using System.Reactive; using System.Reflection; using System.Security.AccessControl; using System.Text; +using static Serein.Library.Api.IFlowEnvironment; namespace Serein.NodeFlow.Env { @@ -42,37 +41,23 @@ namespace Serein.NodeFlow.Env FlowLibraryService flowLibraryManagement, FlowOperationService flowOperationService, FlowModelService flowModelService, + IFlowControl flowControl, + IFlowEdit flowEdit, ISereinIOC sereinIOC, NodeMVVMService nodeMVVMService) { - this.Event = flowEnvironmentEvent; - this.NodeMVVMManagement = nodeMVVMService; - this.flowOperationService = flowOperationService; + Event = flowEnvironmentEvent; + NodeMVVMManagement = nodeMVVMService; + FlowEdit = flowEdit; + FlowLibraryService = flowLibraryManagement; + IOC = sereinIOC; this.flowModelService = flowModelService; + FlowControl = flowControl; + this.flowOperationService = flowOperationService; this.IsGlobalInterrupt = false; - this.FlowLibraryService = flowLibraryManagement; this.flowEnvIOC = sereinIOC; - this.IOC = sereinIOC; - InitNodeMVVM(); } - /// - /// 注册基本节点类型 - /// - 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.GlobalData, typeof(SingleGlobalDataNode)); // 全局数据节点 - NodeMVVMManagement.RegisterModel(NodeControlType.Script, typeof(SingleScriptNode)); // 脚本节点 - NodeMVVMManagement.RegisterModel(NodeControlType.NetScript, typeof(SingleNetScriptNode)); // 脚本节点 - NodeMVVMManagement.RegisterModel(NodeControlType.FlowCall, typeof(SingleFlowCallNode)); // 流程调用节点 - } - - #region 远程管理 @@ -116,104 +101,6 @@ namespace Serein.NodeFlow.Env #endregion - #region 环境运行事件 - /*/// - /// 加载Dll - /// - public event LoadDllHandler? DllLoad; - - /// - /// 移除DLL - /// - public event RemoteDllHandler? OnDllRemote; - - /// - /// 项目加载完成 - /// - public event ProjectLoadedHandler? ProjectLoaded; - - /// - /// 项目准备保存 - /// - public event ProjectSavingHandler? ProjectSaving; - - /// - /// 节点连接属性改变事件 - /// - public event NodeConnectChangeHandler? NodeConnectChanged; - - /// - /// 节点创建事件 - /// - public event NodeCreateHandler? NodeCreated; - - /// - /// 移除节点事件 - /// - public event NodeRemoveHandler? NodeRemoved; - - /// - /// 节点放置事件 - /// - public event NodePlaceHandler NodePlace; - - /// - /// 节点取出事件 - /// - public event NodeTakeOutHandler NodeTakeOut; - - /// - /// 起始节点变化事件 - /// - public event StartNodeChangeHandler? StartNodeChanged; - - /// - /// 流程运行完成事件 - /// - public event FlowRunCompleteHandler? FlowRunComplete; - - /// - /// 被监视的对象改变事件 - /// - public event MonitorObjectChangeHandler? MonitorObjectChanged; - - /// - /// 节点中断状态改变事件 - /// - public event NodeInterruptStateChangeHandler? NodeInterruptStateChanged; - - /// - /// 节点触发了中断 - /// - public event ExpInterruptTriggerHandler? InterruptTriggered; - - /// - /// 容器改变 - /// - public event IOCMembersChangedHandler? IOCMembersChanged; - - /// - /// 节点需要定位 - /// - public event NodeLocatedHandler? NodeLocated; - - /// - /// 运行环境输出 - /// - public event EnvOutHandler? EnvOutput; - - /// - /// 本地环境添加了画布 - /// - public event CanvasCreateHandler CanvasCreated; - - /// - /// 本地环境移除了画布 - /// - public event CanvasRemoveHandler CanvasRemoved; -*/ - #endregion - #region 属性 /// @@ -226,6 +113,16 @@ namespace Serein.NodeFlow.Env /// public IFlowEnvironmentEvent Event { get; set; } + /// + /// 流程编辑接口 + /// + public IFlowEdit FlowEdit { get; set; } + + /// + /// 流程控制接口 + /// + public IFlowControl FlowControl { get; set; } + /// /// UI线程操作类 /// @@ -245,10 +142,6 @@ namespace Serein.NodeFlow.Env /// 如果没有全局触发器,且没有循环分支,流程执行完成后自动为 Completion 。 /// public RunState FlowState { get; set; } = RunState.NoStart; - /// - /// 如果全局触发器还在运行,则为 Running 。 - /// - public RunState FlipFlopState { get; set; } = RunState.NoStart; /// /// 环境名称 @@ -364,205 +257,6 @@ namespace Serein.NodeFlow.Env } - /// - /// 异步运行 - /// - /// - public async Task StartFlowAsync(string[] canvasGuids) - { - #region 校验参数 - HashSet guids = new HashSet(); - bool isBreak = false; - foreach (var canvasGuid in canvasGuids) - { - if (guids.Contains(canvasGuid)) - { - SereinEnv.WriteLine(InfoType.WARN, $"画布重复,停止运行。{canvasGuid}"); - isBreak = true; - } - else if (!flowModelService.ContainsCanvasModel(canvasGuid)) - { - SereinEnv.WriteLine(InfoType.WARN, $"画布不存在,停止运行。{canvasGuid}"); - isBreak = true; - } - else if(!flowModelService.IsExsitNodeOnCanvas(canvasGuid)) - { - SereinEnv.WriteLine(InfoType.WARN, $"画布没有节点,停止运行。{canvasGuid}"); - isBreak = true; - } - else - { - guids.Add(canvasGuid); - } - } - if (isBreak) - { - guids.Clear(); - return false; - } - #endregion - - - #region 初始化每个画布的数据,转换为流程任务 - Dictionary flowTasks = []; - foreach (var guid in guids) - { - if (!TryGetCanvasModel(guid, out var canvasModel)) - { - SereinEnv.WriteLine(InfoType.WARN, $"画布不存在,停止运行。{guid}"); - return false; - } - var ft = new FlowTask(); - ft.GetNodes = () => flowModelService.GetAllNodeModel(guid); - if (canvasModel.StartNode?.Guid is null) - { - SereinEnv.WriteLine(InfoType.WARN, $"画布不存在起始节点,将停止运行。{guid}"); - return false; - } - ft.GetStartNode = () => canvasModel.StartNode; - flowTasks.Add(guid, ft); - } - #endregion - - IOC.Reset(); - IOC.Register(()=> mainFlowEnvironment); - IOC.Register(); // 注册脚本接口 - - var flowTaskOptions = new FlowWorkOptions - { - Environment = this, // 流程 - Flows = flowTasks, - FlowContextPool = new ObjectPool(() => new DynamicContext(this)), // 上下文对象池 - AutoRegisterTypes = this.FlowLibraryService.GetaAutoRegisterType(), // 需要自动实例化的类型 - InitMds = this.FlowLibraryService.GetMdsOnFlowStart(NodeType.Init), - LoadMds = this.FlowLibraryService.GetMdsOnFlowStart(NodeType.Loading), - ExitMds = this.FlowLibraryService.GetMdsOnFlowStart(NodeType.Exit), - }; - - - - flowTaskManagement = new FlowWorkManagement(flowTaskOptions); - var cts = new CancellationTokenSource(); - try - { - var t = await flowTaskManagement.RunAsync(cts.Token); - } - catch (Exception ex) - { - SereinEnv.WriteLine(ex); - } - finally - { - - SereinEnv.WriteLine(InfoType.INFO, $"流程运行完毕{Environment.NewLine}"); ; - } - flowTaskOptions = null; - return true; - - - } - - - /// - /// 从选定节点开始运行 - /// - /// - /// - public async Task StartFlowFromSelectNodeAsync(string startNodeGuid) - { - - var flowTaskOptions = new FlowWorkOptions - { - Environment = this, // 流程 - FlowContextPool = new ObjectPool(() => new DynamicContext(this)), // 上下文对象池 - }; - var flowTaskManagement = new FlowWorkManagement(flowTaskOptions); - - if (true || FlowState == RunState.Running || FlipFlopState == RunState.Running) - { - - if (!TryGetNodeModel(startNodeGuid, out var nodeModel) || nodeModel is SingleFlipflopNode) - { - return false; - } - await flowTaskManagement.StartFlowInSelectNodeAsync(nodeModel); - return true; - } - else - { - return false; - } - } - - /*/// - /// 单独运行一个节点 - /// - /// - /// - public async Task InvokeNodeAsync(IDynamicContext context, string nodeGuid) - { - object result = Unit.Default; - if (this.NodeModels.TryGetValue(nodeGuid, out var model)) - { - CancellationTokenSource cts = new CancellationTokenSource(); - result = await model.ExecutingAsync(context, cts.Token); - cts?.Cancel(); - } - return result; - }*/ - - /// - /// 结束流程 - /// - public Task ExitFlowAsync() - { - flowTaskManagement?.Exit(); - UIContextOperation?.Invoke(() => Event.OnFlowRunComplete(new FlowEventArgs())); - IOC.Reset(); - flowTaskManagement = null; - GC.Collect(); - return Task.FromResult(true); - } - - /// - /// 激活全局触发器 - /// - /// - public void ActivateFlipflopNode(string nodeGuid) - { - /*if (!TryGetNodeModel(nodeGuid, out var nodeModel)) - { - return; - } - if (nodeModel is null) return; - if (flowTaskManagement is not null && nodeModel is SingleFlipflopNode flipflopNode) // 子节点为触发器 - { - if (FlowState != RunState.Completion - && flipflopNode.NotExitPreviousNode()) // 正在运行,且该触发器没有上游节点 - { - _ = flowTaskManagement.RunGlobalFlipflopAsync(this, flipflopNode);// 被父节点移除连接关系的子节点若为触发器,且无上级节点,则当前流程正在运行,则加载到运行环境中 - - } - }*/ - } - - /// - /// 关闭全局触发器 - /// - /// - public void TerminateFlipflopNode(string nodeGuid) - { - /* if (!TryGetNodeModel(nodeGuid, out var nodeModel)) - { - return; - } - if (nodeModel is null) return; - if (flowTaskManagement is not null && nodeModel is SingleFlipflopNode flipflopNode) // 子节点为触发器 - { - flowTaskManagement.TerminateGlobalFlipflopRuning(flipflopNode); - }*/ - } - /// /// 获取当前环境信息(远程连接) /// @@ -622,12 +316,12 @@ namespace Serein.NodeFlow.Env { LoadCanvas(canvasInfo); } - await LoadNodeInfosAsync(projectData.Nodes.ToList()); // 加载节点信息 + await FlowEdit.LoadNodeInfosAsync(projectData.Nodes.ToList()); // 加载节点信息 // 加载画布 foreach (var canvasInfo in projectData.Canvass) { - SetStartNode(canvasInfo.Guid, canvasInfo.StartNode); // 设置起始节点 + FlowEdit.SetStartNode(canvasInfo.Guid, canvasInfo.StartNode); // 设置起始节点 } //await SetStartNodeAsync("", projectData.StartNode); // 设置起始节点 }); @@ -900,35 +594,7 @@ namespace Serein.NodeFlow.Env } - /// - public void UseExternalIOC(ISereinIOC ioc) - { - this.flowRunIOC = ioc; // 设置IOC容器 - } - - /// - /// 启动器调用,运行到某个节点时触发了监视对象的更新(对象预览视图将会自动更新) - /// - /// - /// - /// - public void MonitorObjectNotification(string nodeGuid, object monitorData, MonitorObjectEventArgs.ObjSourceType sourceType) - { - Event.OnMonitorObjectChanged(new MonitorObjectEventArgs(nodeGuid, monitorData, sourceType)); - } - - /// - /// 启动器调用,节点触发了中断。 - /// - /// 节点 - /// 表达式 - /// 类型,0用户主动的中断,1表达式中断 - public void TriggerInterrupt(string nodeGuid, string expression, InterruptTriggerEventArgs.InterruptTriggerType type) - { - Event.OnInterruptTriggered(new InterruptTriggerEventArgs(nodeGuid, expression, type)); - } - - + ///// ///// 环境执行中断 ///// @@ -1031,7 +697,6 @@ namespace Serein.NodeFlow.Env #region 流程依赖类库的接口 - /// /// 运行时加载 /// @@ -1055,725 +720,6 @@ namespace Serein.NodeFlow.Env #endregion - #region 私有方法 - - #region 暂时注释 - /* - /// - /// 加载指定路径的DLL文件 - /// - /// - private void LoadDllNodeInfo(string dllPath) - { - - var fileName = Path.GetFileName(dllPath); - AssemblyLoadContext flowAlc = new AssemblyLoadContext(fileName, true); - flowAlc.LoadFromAssemblyPath(dllPath); // 加载指定路径的程序集 - - foreach(var assemblt in flowAlc.Assemblies) - { - (var registerTypes, var mdlist) = LoadAssembly(assemblt); - if (mdlist.Count > 0) - { - var nodeLibraryInfo = new NodeLibraryInfo - { - //Assembly = assembly, - AssemblyName = assemblt.FullName, - FileName = Path.GetFileName(dllPath), - FilePath = dllPath, - }; - - LibraryInfos.TryAdd(nodeLibraryInfo.AssemblyName, nodeLibraryInfo); - MethodDetailsOfLibraryInfos.TryAdd(nodeLibraryInfo, mdlist); - - foreach (var md in mdlist) - { - MethodDetailss.TryAdd(md.MethodName, md); - } - - foreach (var kv in registerTypes) - { - if (!AutoRegisterTypes.TryGetValue(kv.Key, out var types)) - { - types = new List(); - AutoRegisterTypes.Add(kv.Key, types); - } - types.AddRange(kv.Value); - } - var mdInfos = mdlist.Select(md => md.ToInfo()).ToList(); // 转换成方法信息 - - if (OperatingSystem.IsWindows()) - { - UIContextOperation?.Invoke(() => OnDllLoad?.Invoke(new LoadDllEventArgs(nodeLibraryInfo, mdInfos))); // 通知UI创建dll面板显示 - - } - } - - - } - - - - - }*/ - #endregion - - - /// - /// 从节点信息创建节点,并返回状态指示是否创建成功 - /// - /// - /// - private bool CreateNodeFromNodeInfo(NodeInfo nodeInfo) - { - if (!EnumHelper.TryConvertEnum(nodeInfo.Type, out var controlType)) - { - return false; - } - - #region 获取方法描述 - MethodDetails? methodDetails; - if (controlType == NodeControlType.FlowCall) - { - if (string.IsNullOrEmpty(nodeInfo.MethodName)) - { - methodDetails = new MethodDetails(); - methodDetails.ParamsArgIndex = 0; - methodDetails.ParameterDetailss = new ParameterDetails[nodeInfo.ParameterData.Length]; - for (int i = 0; i < methodDetails.ParameterDetailss.Length; i++) - { - var pdInfo = nodeInfo.ParameterData[i]; - var t = new ParameterDetailsInfo(); - var pd = new ParameterDetails(pdInfo, i); - methodDetails.ParameterDetailss[i] = pd; - } - } - else - { - // 目标节点可能是方法节点 - FlowLibraryService.TryGetMethodDetails(nodeInfo.AssemblyName, nodeInfo.MethodName, out methodDetails); // 加载项目时尝试获取方法信息 - } - } - else if (controlType.IsBaseNode()) - { - // 加载基础节点 - methodDetails = new MethodDetails(); - - } - else - { - if (string.IsNullOrEmpty(nodeInfo.MethodName)) return false; - // 加载方法节点 - FlowLibraryService.TryGetMethodDetails(nodeInfo.AssemblyName, nodeInfo.MethodName, out methodDetails); // 加载项目时尝试获取方法信息 - } - #endregion - - var nodeModel = FlowNodeExtension.CreateNode(this, controlType, methodDetails); // 加载项目时创建节点 - if (nodeModel is null) - { - nodeInfo.Guid = string.Empty; - return false; - } - if (TryGetCanvasModel(nodeInfo.CanvasGuid, out var canvasModel)) - { - - // 节点与画布互相绑定 - // 需要在UI线程上进行添加,否则会报 “不支持从调度程序线程以外的线程对其 SourceCollection 进行的更改”异常 - nodeModel.CanvasDetails = canvasModel; - UIContextOperation?.Invoke(() => canvasModel.Nodes.Add(nodeModel)); - - nodeModel.LoadInfo(nodeInfo); // 创建节点model - TryAddNode(nodeModel); // 加载项目时将节点加载到环境中 - } - else - { - SereinEnv.WriteLine(InfoType.ERROR, $"加载节点[{nodeInfo.Guid}]时发生异常,画布[{nodeInfo.CanvasGuid}]不存在"); - return false; - } - - UIContextOperation?.Invoke(() => - Event.OnNodeCreated(new NodeCreateEventArgs(nodeInfo.CanvasGuid, nodeModel, nodeInfo.Position))); // 添加到UI上 - return true; - } - - - - /// - /// 创建节点 - /// - /// - private bool TryAddNode(IFlowNode nodeModel) - { - nodeModel.Guid ??= Guid.NewGuid().ToString(); - flowModelService.AddNodeModel(nodeModel); - - - // 如果是触发器,则需要添加到专属集合中 - /*if (nodeModel is SingleFlipflopNode flipflopNode) - { - var guid = flipflopNode.Guid; - if (!FlipflopNodes.Exists(it => it.Guid.Equals(guid))) - { - FlipflopNodes.Add(flipflopNode); - } - }*/ - return true; - } - - /// - /// 检查连接 - /// - /// 发起连接的起始节点 - /// 要连接的目标节点 - /// 发起连接节点的控制点类型 - /// 被连接节点的控制点类型 - /// - public static (JunctionOfConnectionType, bool) CheckConnect(IFlowNode fromNode, - IFlowNode toNode, - JunctionType fromNodeJunctionType, - JunctionType toNodeJunctionType) - { - var type = JunctionOfConnectionType.None; - var state = false; - if (fromNodeJunctionType == JunctionType.Execute) - { - if (toNodeJunctionType == JunctionType.NextStep && !fromNode.Guid.Equals(toNode.Guid)) - { - // “方法执行”控制点拖拽到“下一节点”控制点,且不是同一个节点, 添加方法执行关系 - type = JunctionOfConnectionType.Invoke; - state = true; - } - //else if (toNodeJunctionType == JunctionType.ArgData && fromNode.Guid.Equals(toNode.Guid)) - //{ - // // “方法执行”控制点拖拽到“方法入参”控制点,且是同一个节点,则添加获取参数关系,表示生成入参参数时自动从该节点的上一节点获取flowdata - // type = JunctionOfConnectionType.Arg; - // state = true; - //} - } - else if (fromNodeJunctionType == JunctionType.NextStep && !fromNode.Guid.Equals(toNode.Guid)) - { - // “下一节点”控制点只能拖拽到“方法执行”控制点,且不能是同一个节点 - if (toNodeJunctionType == JunctionType.Execute && !fromNode.Guid.Equals(toNode.Guid)) - { - type = JunctionOfConnectionType.Invoke; - state = true; - } - } - else if (fromNodeJunctionType == JunctionType.ArgData) - { - //if (toNodeJunctionType == JunctionType.Execute && fromNode.Guid.Equals(toNode.Guid)) // 添加获取参数关系 - //{ - // // “方法入参”控制点拖拽到“方法执行”控制点,且是同一个节点,则添加获取参数关系,生成入参参数时自动从该节点的上一节点获取flowdata - // type = JunctionOfConnectionType.Arg; - // state = true; - //} - if (toNodeJunctionType == JunctionType.ReturnData && !fromNode.Guid.Equals(toNode.Guid)) - { - // “”控制点拖拽到“方法返回值”控制点,且不是同一个节点,添加获取参数关系,生成参数时从目标节点获取flowdata - type = JunctionOfConnectionType.Arg; - state = true; - } - } - else if (fromNodeJunctionType == JunctionType.ReturnData) - { - if (toNodeJunctionType == JunctionType.ArgData && !fromNode.Guid.Equals(toNode.Guid)) - { - // “方法返回值”控制点拖拽到“方法入参”控制点,且不是同一个节点,添加获取参数关系,生成参数时从目标节点获取flowdata - type = JunctionOfConnectionType.Arg; - state = true; - } - } - // 剩下的情况都是不符预期的连接行为,忽略。 - 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; - } - - 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, $"起始节点已与目标节点存在连接。" + - $"{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()) - { - - 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 void SetStartNode(FlowCanvasDetails cavnasModel, IFlowNode newStartNode) - { - var oldNodeGuid = cavnasModel.StartNode?.Guid; - /*if(TryGetNodeModel(oldNodeGuid, out var newStartNodeModel)) - { - newStartNode.IsStart = false; - }*/ - cavnasModel.StartNode = newStartNode; - //newStartNode.IsStart = true; - UIContextOperation?.Invoke(() => Event.OnStartNodeChanged(new StartNodeChangeEventArgs(cavnasModel.Guid, oldNodeGuid, cavnasModel.StartNode.Guid))); - - } - - - - #endregion - - #region 视觉效果 - - /// - /// 定位节点 - /// - /// - public void NodeLocate(string nodeGuid) - { - if (OperatingSystem.IsWindows()) - { - UIContextOperation?.Invoke(() => Event.OnNodeLocated(new NodeLocatedEventArgs(nodeGuid))); - } - - } - - - #endregion - - - - #region 流程接口 - - private int _add_canvas_count = 1; - public void CreateCanvas(string canvasName, int width, int height) - { - IOperation operation = new CreateCanvasOperation - { - CanvasInfo = new FlowCanvasDetailsInfo - { - Name = $"Canvas {_add_canvas_count++}", - Width = width, - Height = height, - Guid = Guid.NewGuid().ToString(), - ScaleX = 1.0f, - ScaleY = 1.0f, - } - }; - - flowOperationService.Execute(operation); - } - - public void RemoveCanvas(string canvasGuid) - { - IOperation operation = new RemoveCanvasOperation - { - CanvasGuid = canvasGuid - }; - flowOperationService.Execute(operation); - } - - public void ConnectInvokeNode(string canvasGuid, string fromNodeGuid, string toNodeGuid, JunctionType fromNodeJunctionType, JunctionType toNodeJunctionType, ConnectionInvokeType invokeType) - { - IOperation operation = new ChangeNodeConnectionOperation - { - CanvasGuid = canvasGuid, - FromNodeGuid = fromNodeGuid, - ToNodeGuid = toNodeGuid, - FromNodeJunctionType = fromNodeJunctionType, - ToNodeJunctionType = toNodeJunctionType, - ConnectionInvokeType = invokeType, - ChangeType = NodeConnectChangeEventArgs.ConnectChangeType.Create, - JunctionOfConnectionType = JunctionOfConnectionType.Invoke, - }; - - flowOperationService.Execute(operation); - } - - public void ConnectArgSourceNode(string canvasGuid, string fromNodeGuid, string toNodeGuid, JunctionType fromNodeJunctionType, JunctionType toNodeJunctionType, ConnectionArgSourceType argSourceType, int argIndex) - { - IOperation operation = new ChangeNodeConnectionOperation - { - CanvasGuid = canvasGuid, - FromNodeGuid = fromNodeGuid, - ToNodeGuid = toNodeGuid, - FromNodeJunctionType = fromNodeJunctionType, - ToNodeJunctionType = toNodeJunctionType, - ConnectionArgSourceType = argSourceType, - ArgIndex = argIndex, - ChangeType = NodeConnectChangeEventArgs.ConnectChangeType.Create, - JunctionOfConnectionType = JunctionOfConnectionType.Arg, - }; - flowOperationService.Execute(operation); - } - - public void RemoveInvokeConnect(string canvasGuid, string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType) - { - IOperation operation = new ChangeNodeConnectionOperation - { - CanvasGuid = canvasGuid, - FromNodeGuid = fromNodeGuid, - ToNodeGuid = toNodeGuid, - ConnectionInvokeType = connectionType, - ChangeType = NodeConnectChangeEventArgs.ConnectChangeType.Remove, - }; - flowOperationService.Execute(operation); - } - - public void RemoveArgSourceConnect(string canvasGuid, string fromNodeGuid, string toNodeGuid, int argIndex) - { - IOperation operation = new ChangeNodeConnectionOperation - { - CanvasGuid = canvasGuid, - FromNodeGuid = fromNodeGuid, - ToNodeGuid = toNodeGuid, - ArgIndex = argIndex, - ChangeType = NodeConnectChangeEventArgs.ConnectChangeType.Remove - }; - flowOperationService.Execute(operation); - } - - public void CreateNode(string canvasGuid, NodeControlType nodeType, PositionOfUI position, MethodDetailsInfo methodDetailsInfo = null) - { - IOperation operation = new CreateNodeOperation - { - CanvasGuid = canvasGuid, - NodeControlType = nodeType, - Position = position, - MethodDetailsInfo = methodDetailsInfo - }; - flowOperationService.Execute(operation); - } - - public void RemoveNode(string canvasGuid, string nodeGuid) - { - IOperation operation = new RemoveNodeOperation - { - CanvasGuid = canvasGuid, - NodeGuid = nodeGuid - }; - flowOperationService.Execute(operation); - } - - public void PlaceNodeToContainer(string canvasGuid, string nodeGuid, string containerNodeGuid) - { - IOperation operation = new ContainerPlaceNodeOperation - { - CanvasGuid = canvasGuid, - NodeGuid = nodeGuid, - ContainerNodeGuid = containerNodeGuid - }; - flowOperationService.Execute(operation); - } - - public void TakeOutNodeToContainer(string canvasGuid, string nodeGuid) - { - IOperation operation = new ContainerTakeOutNodeOperation - { - CanvasGuid = canvasGuid, - NodeGuid = nodeGuid, - }; - flowOperationService.Execute(operation); - } - - public void SetStartNode(string canvasGuid, string nodeGuid) - { - if (!TryGetCanvasModel(canvasGuid, out var canvasModel) || !TryGetNodeModel(nodeGuid, out var newStartNodeModel)) - { - return; - } - 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) && - TryGetNodeModel(nodeInfo.ParentNodeGuid, out var parentNode)) - { - needPlaceNodeInfos.Add(nodeInfo); // 需要重新放置的节点 - } - } - - foreach (NodeInfo nodeInfo in needPlaceNodeInfos) - { - if (TryGetNodeModel(nodeInfo.Guid, out var nodeModel) && - TryGetNodeModel(nodeInfo.ParentNodeGuid, out var containerNode) - && containerNode is INodeContainer nodeContainer) - { - var result = nodeContainer.PlaceNode(nodeModel); - if (result) - { - UIContextOperation?.Invoke(() => Event.OnNodePlace( - new NodePlaceEventArgs(nodeInfo.CanvasGuid, nodeModel.Guid, containerNode.Guid))); - } - - - } - } - #endregion - - await Task.Delay(100); - #region 确定节点之间的方法调用关系 - foreach (var nodeInfo in nodeInfos) - { - var canvasGuid = nodeInfo.CanvasGuid; - if (!TryGetNodeModel(nodeInfo.Guid, out var fromNodeModel)) - { - return; - } - if (fromNodeModel is null) continue; - List<(ConnectionInvokeType connectionType, string[] guids)> allToNodes = [(ConnectionInvokeType.IsSucceed,nodeInfo.TrueNodes), - (ConnectionInvokeType.IsFail, nodeInfo.FalseNodes), - (ConnectionInvokeType.IsError, nodeInfo.ErrorNodes), - (ConnectionInvokeType.Upstream, nodeInfo.UpstreamNodes)]; - foreach ((ConnectionInvokeType connectionType, string[] toNodeGuids) item in allToNodes) - { - // 遍历当前类型分支的节点(确认连接关系) - foreach (var toNodeGuid in item.toNodeGuids) - { - if (!TryGetNodeModel(toNodeGuid, out var toNodeModel)) - { - return; - } - if (toNodeModel is null) - { - // 防御性代码,加载正常保存的项目文件不会进入这里 - continue; - } - - ConnectInvokeNode(canvasGuid, fromNodeModel.Guid, toNodeModel.Guid, JunctionType.NextStep, JunctionType.Execute, item.connectionType); - - //var isSuccessful = ConnectInvokeOfNode(canvasGuid, fromNodeModel, toNodeModel, item.connectionType); // 加载时确定节点间的连接关系 - } - } - - - //List<(ConnectionInvokeType connectionType, string[] guids)> allToNodes = [(ConnectionInvokeType.IsSucceed,nodeInfo.TrueNodes), - // (ConnectionInvokeType.IsFail, nodeInfo.FalseNodes), - // (ConnectionInvokeType.IsError, nodeInfo.ErrorNodes), - // (ConnectionInvokeType.Upstream, nodeInfo.UpstreamNodes)]; - - //List<(ConnectionInvokeType, NodeModelBase[])> fromNodes = allToNodes.Where(info => info.guids.Length > 0) - // .Select(info => (info.connectionType, - // info.guids.Where(guid => NodeModels.ContainsKey(guid)).Select(guid => NodeModels[guid]) - // .ToArray())) - // .ToList(); - // 遍历每种类型的节点分支(四种) - //foreach ((ConnectionInvokeType connectionType, NodeModelBase[] toNodes) item in nodeInfo) - //{ - // // 遍历当前类型分支的节点(确认连接关系) - // foreach (var toNode in item.toNodes) - // { - // _ = ConnectInvokeOfNode(fromNode, toNode, item.connectionType); // 加载时确定节点间的连接关系 - // } - //} - } - #endregion - - #region 确定节点之间的参数调用关系 - var nodeModels = flowModelService.GetAllNodeModel(); - foreach (var toNode in nodeModels) - { - var canvasGuid = toNode.CanvasDetails.Guid; - if (toNode.MethodDetails.ParameterDetailss == null) - { - continue; - } - for (var i = 0; i < toNode.MethodDetails.ParameterDetailss.Length; i++) - { - var pd = toNode.MethodDetails.ParameterDetailss[i]; - if (!string.IsNullOrEmpty(pd.ArgDataSourceNodeGuid) - && TryGetNodeModel(pd.ArgDataSourceNodeGuid, out var fromNode)) - { - - ConnectArgSourceNode(canvasGuid, fromNode.Guid, toNode.Guid, JunctionType.ReturnData, JunctionType.ArgData , pd.ArgDataSourceType, pd.Index); - } - } - } - #endregion - - - UIContextOperation?.Invoke(() => - { - Event.OnProjectLoaded(new ProjectLoadedEventArgs()); - }); - - return; - } - #endregion } diff --git a/NodeFlow/FlowNodeExtension.cs b/NodeFlow/FlowNodeExtension.cs index 67f5d1d..f2c12a4 100644 --- a/NodeFlow/FlowNodeExtension.cs +++ b/NodeFlow/FlowNodeExtension.cs @@ -43,7 +43,7 @@ namespace Serein.NodeFlow // 尝试获取需要创建的节点类型 - if (!env.NodeMVVMManagement.TryGetType(nodeControlType, out var nodeMVVM) || nodeMVVM.ModelType == null) + if (!env.FlowEdit.NodeMVVMManagement.TryGetType(nodeControlType, out var nodeMVVM) || nodeMVVM.ModelType == null) { throw new Exception($"无法创建{nodeControlType}节点,节点类型尚未注册。"); } diff --git a/NodeFlow/Model/Node/NodeModelBaseFunc.cs b/NodeFlow/Model/Node/NodeModelBaseFunc.cs index d1ce2d8..9a49e37 100644 --- a/NodeFlow/Model/Node/NodeModelBaseFunc.cs +++ b/NodeFlow/Model/Node/NodeModelBaseFunc.cs @@ -115,7 +115,7 @@ namespace Serein.NodeFlow.Model // 执行触发检查是否需要中断 if (DebugSetting.IsInterrupt) { - context.Env.TriggerInterrupt(Guid, "", InterruptTriggerEventArgs.InterruptTriggerType.Monitor); // 通知运行环境该节点中断了 + context.Env.FlowControl.TriggerInterrupt(Guid, "", InterruptTriggerEventArgs.InterruptTriggerType.Monitor); // 通知运行环境该节点中断了 await DebugSetting.GetInterruptTask.Invoke(); SereinEnv.WriteLine(InfoType.INFO, $"[{this.MethodDetails?.MethodName}]中断已取消,开始执行后继分支"); if (token.IsCancellationRequested) { return null; } diff --git a/NodeFlow/Model/Node/SingleFlowCallNode.cs b/NodeFlow/Model/Node/SingleFlowCallNode.cs index 7987162..eddc5eb 100644 --- a/NodeFlow/Model/Node/SingleFlowCallNode.cs +++ b/NodeFlow/Model/Node/SingleFlowCallNode.cs @@ -38,17 +38,15 @@ namespace Serein.NodeFlow.Model public partial class SingleFlowCallNode : NodeModelBase { /// - /// 接口节点 + /// 被调用的节点 /// private IFlowNode targetNode; /// /// 缓存的方法信息 /// public MethodDetails CacheMethodDetails { get; private set; } - /// - /// 接口节点Guid - /// - //public string? TargetNodeGuid => targetNode?.Guid; + + public SingleFlowCallNode(IFlowEnvironment environment) : base(environment) diff --git a/NodeFlow/Model/Node/SingleGlobalDataNode.cs b/NodeFlow/Model/Node/SingleGlobalDataNode.cs index 6bda89a..27f1064 100644 --- a/NodeFlow/Model/Node/SingleGlobalDataNode.cs +++ b/NodeFlow/Model/Node/SingleGlobalDataNode.cs @@ -96,7 +96,7 @@ namespace Serein.NodeFlow.Model { foreach (var nodeModel in ChildrenNode) { - nodeModel.Env.TakeOutNodeToContainer(nodeModel.CanvasDetails.Guid, nodeModel.Guid); + nodeModel.Env.FlowEdit.TakeOutNodeToContainer(nodeModel.CanvasDetails.Guid, nodeModel.Guid); } DataNode = null; } diff --git a/NodeFlow/Model/Operation/CreateNodeOperation.cs b/NodeFlow/Model/Operation/CreateNodeOperation.cs index aaf3250..e688504 100644 --- a/NodeFlow/Model/Operation/CreateNodeOperation.cs +++ b/NodeFlow/Model/Operation/CreateNodeOperation.cs @@ -112,7 +112,7 @@ namespace Serein.NodeFlow.Model.Operation if(flowNode is null) return false; // 没有创建过节点 var canvasGuid = flowCanvasDetails.Guid; var nodeGuid = flowNode.Guid; - flowEnvironment.RemoveNode(canvasGuid, nodeGuid); + flowEnvironment.FlowEdit.RemoveNode(canvasGuid, nodeGuid); return true; } diff --git a/NodeFlow/Services/FlowApiService.cs b/NodeFlow/Services/FlowApiService.cs index 4c8fd53..cee0599 100644 --- a/NodeFlow/Services/FlowApiService.cs +++ b/NodeFlow/Services/FlowApiService.cs @@ -5,7 +5,6 @@ using System.Linq; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; -using static Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser; namespace Serein.NodeFlow.Services { @@ -31,32 +30,6 @@ namespace Serein.NodeFlow.Services - /* object result = flowApiService.Invoke("", params); - TResult result = flowApiService.Invoke("", params); - object result = await flowApiService.InvokeAsync("", params); - TResult result = await flowApiService.InvokeAsync("", params);*/ - - - public object Invoke(string apiName, object[] param) - { - return null; - } - - public TResult Invoke(string apiName, object[] param) - { - return default(TResult); - } - - public async Task InvokeAsync(string apiName, object[] param) - { - return null; - } - - public async Task InvokeAsync(string apiName, object[] param) - { - return default(TResult); - - } } diff --git a/Workbench/Node/Junction/JunctionControlBase.cs b/Workbench/Node/Junction/JunctionControlBase.cs index eb1fe6e..2fbdaf8 100644 --- a/Workbench/Node/Junction/JunctionControlBase.cs +++ b/Workbench/Node/Junction/JunctionControlBase.cs @@ -159,11 +159,11 @@ namespace Serein.Workbench.Node.View private void AddParamAsync() { - this.MyNode.Env.ChangeParameter(MyNode.Guid, true, ArgIndex); + this.MyNode.Env.FlowEdit.ChangeParameter(MyNode.Guid, true, ArgIndex); } private void RemoveParamAsync() { - this.MyNode.Env.ChangeParameter(MyNode.Guid, false, ArgIndex); + this.MyNode.Env.FlowEdit.ChangeParameter(MyNode.Guid, false, ArgIndex); } } diff --git a/Workbench/Node/View/ConnectionControl.cs b/Workbench/Node/View/ConnectionControl.cs index 0cbbb30..b94272a 100644 --- a/Workbench/Node/View/ConnectionControl.cs +++ b/Workbench/Node/View/ConnectionControl.cs @@ -243,11 +243,11 @@ namespace Serein.Workbench.Node.View var jctEnd = End.JunctionType.ToConnectyionType(); if (jct == JunctionOfConnectionType.Invoke) { - env.RemoveInvokeConnect(canvasGuid, Start.MyNode.Guid, End.MyNode.Guid, InvokeType); + env.FlowEdit.RemoveInvokeConnect(canvasGuid, Start.MyNode.Guid, End.MyNode.Guid, InvokeType); } else if (jct == JunctionOfConnectionType.Arg) { - env.RemoveArgSourceConnect(canvasGuid,Start.MyNode.Guid, End.MyNode.Guid, ArgIndex) ; + env.FlowEdit.RemoveArgSourceConnect(canvasGuid,Start.MyNode.Guid, End.MyNode.Guid, ArgIndex) ; } } @@ -259,7 +259,7 @@ namespace Serein.Workbench.Node.View var env = Start.MyNode.Env; if (Start.JunctionType.ToConnectyionType() == JunctionOfConnectionType.Invoke) { - env.SetConnectPriorityInvoke(Start.MyNode.Guid, End.MyNode.Guid, InvokeType); + env.FlowEdit.SetConnectPriorityInvoke(Start.MyNode.Guid, End.MyNode.Guid, InvokeType); } } diff --git a/Workbench/Services/FlowNodeService.cs b/Workbench/Services/FlowNodeService.cs index 509794f..41b6562 100644 --- a/Workbench/Services/FlowNodeService.cs +++ b/Workbench/Services/FlowNodeService.cs @@ -174,15 +174,15 @@ namespace Serein.Workbench.Services /// private void InitNodeType() { - flowEnvironment.NodeMVVMManagement.RegisterUI(NodeControlType.UI, typeof(UINodeControl), typeof(UINodeControlViewModel)); - flowEnvironment.NodeMVVMManagement.RegisterUI(NodeControlType.Action, typeof(ActionNodeControl), typeof(ActionNodeControlViewModel)); - flowEnvironment.NodeMVVMManagement.RegisterUI(NodeControlType.Flipflop, typeof(FlipflopNodeControl), typeof(FlipflopNodeControlViewModel)); - flowEnvironment.NodeMVVMManagement.RegisterUI(NodeControlType.ExpOp, typeof(ExpOpNodeControl), typeof(ExpOpNodeControlViewModel)); - flowEnvironment.NodeMVVMManagement.RegisterUI(NodeControlType.ExpCondition, typeof(ConditionNodeControl), typeof(ConditionNodeControlViewModel)); - flowEnvironment.NodeMVVMManagement.RegisterUI(NodeControlType.GlobalData, typeof(GlobalDataControl), typeof(GlobalDataNodeControlViewModel)); - flowEnvironment.NodeMVVMManagement.RegisterUI(NodeControlType.Script, typeof(ScriptNodeControl), typeof(ScriptNodeControlViewModel)); - flowEnvironment.NodeMVVMManagement.RegisterUI(NodeControlType.NetScript, typeof(NetScriptNodeControl), typeof(NetScriptNodeControlViewModel)); - flowEnvironment.NodeMVVMManagement.RegisterUI(NodeControlType.FlowCall, typeof(FlowCallNodeControl), typeof(FlowCallNodeControlViewModel)); + flowEnvironment.FlowEdit.NodeMVVMManagement.RegisterUI(NodeControlType.UI, typeof(UINodeControl), typeof(UINodeControlViewModel)); + flowEnvironment.FlowEdit.NodeMVVMManagement.RegisterUI(NodeControlType.Action, typeof(ActionNodeControl), typeof(ActionNodeControlViewModel)); + flowEnvironment.FlowEdit.NodeMVVMManagement.RegisterUI(NodeControlType.Flipflop, typeof(FlipflopNodeControl), typeof(FlipflopNodeControlViewModel)); + flowEnvironment.FlowEdit.NodeMVVMManagement.RegisterUI(NodeControlType.ExpOp, typeof(ExpOpNodeControl), typeof(ExpOpNodeControlViewModel)); + flowEnvironment.FlowEdit.NodeMVVMManagement.RegisterUI(NodeControlType.ExpCondition, typeof(ConditionNodeControl), typeof(ConditionNodeControlViewModel)); + flowEnvironment.FlowEdit.NodeMVVMManagement.RegisterUI(NodeControlType.GlobalData, typeof(GlobalDataControl), typeof(GlobalDataNodeControlViewModel)); + flowEnvironment.FlowEdit.NodeMVVMManagement.RegisterUI(NodeControlType.Script, typeof(ScriptNodeControl), typeof(ScriptNodeControlViewModel)); + flowEnvironment.FlowEdit.NodeMVVMManagement.RegisterUI(NodeControlType.NetScript, typeof(NetScriptNodeControl), typeof(NetScriptNodeControlViewModel)); + flowEnvironment.FlowEdit.NodeMVVMManagement.RegisterUI(NodeControlType.FlowCall, typeof(FlowCallNodeControl), typeof(FlowCallNodeControlViewModel)); } /// @@ -319,7 +319,7 @@ namespace Serein.Workbench.Services return; } - if (!flowEnvironment.NodeMVVMManagement.TryGetType(nodeModel.ControlType, out var nodeMVVM)) + if (!flowEnvironment.FlowEdit.NodeMVVMManagement.TryGetType(nodeModel.ControlType, out var nodeMVVM)) { SereinEnv.WriteLine(InfoType.INFO, $"无法创建{nodeModel.ControlType}节点,节点类型尚未注册。"); return; @@ -635,7 +635,7 @@ namespace Serein.Workbench.Services node.Position = new PositionOfUI(positionOfUI.X + offsetX, positionOfUI.Y + offsetY); } - _ = flowEnvironment.LoadNodeInfosAsync(nodes); + _ = flowEnvironment.FlowEdit.LoadNodeInfosAsync(nodes); } catch (Exception ex) { @@ -656,7 +656,7 @@ namespace Serein.Workbench.Services { int width = 1200; int height = 780; - flowEnvironment.CreateCanvas("", width, height); + flowEnvironment.FlowEdit.CreateCanvas("", width, height); } /// @@ -669,7 +669,7 @@ namespace Serein.Workbench.Services return; } var model = ((FlowCanvasViewModel)CurrentSelectCanvas.DataContext).Model; - flowEnvironment.RemoveCanvas(model.Guid); + flowEnvironment.FlowEdit.RemoveCanvas(model.Guid); } /// @@ -688,7 +688,7 @@ namespace Serein.Workbench.Services { return; } - flowEnvironment.CreateNode(canvasGuid, nodeType, position, methodDetailsInfo); + flowEnvironment.FlowEdit.CreateNode(canvasGuid, nodeType, position, methodDetailsInfo); } /// @@ -707,7 +707,7 @@ namespace Serein.Workbench.Services return; } - flowEnvironment.RemoveNode(model.CanvasDetails.Guid, model.Guid); + flowEnvironment.FlowEdit.RemoveNode(model.CanvasDetails.Guid, model.Guid); } #endregion diff --git a/Workbench/Themes/NodeTreeItemViewControl.xaml.cs b/Workbench/Themes/NodeTreeItemViewControl.xaml.cs index b348f88..be6f0f1 100644 --- a/Workbench/Themes/NodeTreeItemViewControl.xaml.cs +++ b/Workbench/Themes/NodeTreeItemViewControl.xaml.cs @@ -142,7 +142,7 @@ namespace Serein.Workbench.Themes { try { - await flowEnvironment.StartFlowFromSelectNodeAsync(tmpNodeTreeModel.RootNode.Guid); + await flowEnvironment.FlowControl.StartFlowFromSelectNodeAsync(tmpNodeTreeModel.RootNode.Guid); } catch (Exception ex) { @@ -150,7 +150,7 @@ namespace Serein.Workbench.Themes return; } })); - contextMenu.Items.Add(WpfFuncTool.CreateMenuItem("定位", (s, e) => flowEnvironment.NodeLocate(tmpNodeTreeModel.RootNode.Guid))); + contextMenu.Items.Add(WpfFuncTool.CreateMenuItem("定位", (s, e) => flowEnvironment.FlowEdit.NodeLocate(tmpNodeTreeModel.RootNode.Guid))); treeViewItem.ContextMenu = contextMenu; treeViewItem.Margin = new Thickness(-20, 0, 0, 0); diff --git a/Workbench/ViewModels/MainMenuBarViewModel.cs b/Workbench/ViewModels/MainMenuBarViewModel.cs index c8f5e8e..2f25672 100644 --- a/Workbench/ViewModels/MainMenuBarViewModel.cs +++ b/Workbench/ViewModels/MainMenuBarViewModel.cs @@ -114,7 +114,7 @@ namespace Serein.Workbench.ViewModels if(canvass.Length > 0) { string[] guids = [..canvass.Select(c => c.Guid)]; - flowEnvironment.StartFlowAsync(guids); + flowEnvironment.FlowControl.StartFlowAsync(guids); } } @@ -122,7 +122,7 @@ namespace Serein.Workbench.ViewModels { var canvas = flowNodeService.CurrentSelectCanvas; if (canvas is null) return; - flowEnvironment.StartFlowAsync([canvas.Guid]); + flowEnvironment.FlowControl.StartFlowAsync([canvas.Guid]); } private void StopCurrentCanvasFlow() { } private void OpenDynamicCompiler() { } diff --git a/Workbench/Views/FlowCanvasView.xaml.cs b/Workbench/Views/FlowCanvasView.xaml.cs index de827c4..6e33c43 100644 --- a/Workbench/Views/FlowCanvasView.xaml.cs +++ b/Workbench/Views/FlowCanvasView.xaml.cs @@ -370,7 +370,7 @@ namespace Serein.Workbench.Views if (TryPlaceNodeInRegion(nodeControl, position, out var regionControl)) // 判断添加到区域容器 { // 通知运行环境调用加载节点子项的方法 - flowEnvironment.PlaceNodeToContainer(Guid, + flowEnvironment.FlowEdit.PlaceNodeToContainer(Guid, nodeControl.ViewModel.NodeModel.Guid, // 待移动的节点 regionControl.ViewModel.NodeModel.Guid); // 目标的容器节点 return; @@ -557,14 +557,14 @@ namespace Serein.Workbench.Views if (keyEventService.GetKeyState(Key.LeftCtrl) || keyEventService.GetKeyState(Key.RightCtrl)) { // Ctrl + F5 调试当前流程 - _ = flowEnvironment.StartFlowAsync([flowNodeService.CurrentSelectCanvas.Guid]); + _ = flowEnvironment.FlowControl.StartFlowAsync([flowNodeService.CurrentSelectCanvas.Guid]); } else if (selectNodeControls.Count == 1 ) { // F5 调试当前选定节点 var nodeModel = selectNodeControls[0].ViewModel.NodeModel; SereinEnv.WriteLine(InfoType.INFO, $"调试运行当前节点:{nodeModel.Guid}"); - _ = flowEnvironment.StartFlowFromSelectNodeAsync(nodeModel.Guid); + _ = flowEnvironment.FlowControl.StartFlowFromSelectNodeAsync(nodeModel.Guid); //_ = nodeModel.StartFlowAsync(new DynamicContext(flowEnvironment), new CancellationToken()); } @@ -897,7 +897,7 @@ namespace Serein.Workbench.Views { var canvasGuid = this.Guid; - flowEnvironment.ConnectInvokeNode( + flowEnvironment.FlowEdit.ConnectInvokeNode( canvasGuid, cd.StartJunction.MyNode.Guid, cd.CurrentJunction.MyNode.Guid, @@ -921,7 +921,7 @@ namespace Serein.Workbench.Views } var canvasGuid = this.Guid; - flowEnvironment.ConnectArgSourceNode( + flowEnvironment.FlowEdit.ConnectArgSourceNode( canvasGuid, cd.StartJunction.MyNode.Guid, cd.CurrentJunction.MyNode.Guid, @@ -1268,7 +1268,7 @@ namespace Serein.Workbench.Views if (!string.IsNullOrEmpty(guid)) { var canvasGuid = this.Guid; - flowEnvironment.RemoveNode(canvasGuid, guid); + flowEnvironment.FlowEdit.RemoveNode(canvasGuid, guid); } } } @@ -1464,13 +1464,13 @@ namespace Serein.Workbench.Views { if (menuItem.Header.ToString() == "启动触发器") { - flowEnvironment.ActivateFlipflopNode(nodeGuid); + flowEnvironment.FlowControl.ActivateFlipflopNode(nodeGuid); menuItem.Header = "终结触发器"; } else { - flowEnvironment.TerminateFlipflopNode(nodeGuid); + flowEnvironment.FlowControl.TerminateFlipflopNode(nodeGuid); menuItem.Header = "启动触发器"; } @@ -1490,10 +1490,10 @@ namespace Serein.Workbench.Views - contextMenu.Items.Add(WpfFuncTool.CreateMenuItem("设为起点", (s, e) => flowEnvironment.SetStartNode(canvasGuid, nodeGuid))); + contextMenu.Items.Add(WpfFuncTool.CreateMenuItem("设为起点", (s, e) => flowEnvironment.FlowEdit.SetStartNode(canvasGuid, nodeGuid))); contextMenu.Items.Add(WpfFuncTool.CreateMenuItem("删除", async (s, e) => { - flowEnvironment.RemoveNode(canvasGuid, nodeGuid); + flowEnvironment.FlowEdit.RemoveNode(canvasGuid, nodeGuid); })); #region 右键菜单功能 - 控件对齐 diff --git a/Workbench/Views/ViewCanvasInfoView.xaml.cs b/Workbench/Views/ViewCanvasInfoView.xaml.cs index 1016f8c..739067b 100644 --- a/Workbench/Views/ViewCanvasInfoView.xaml.cs +++ b/Workbench/Views/ViewCanvasInfoView.xaml.cs @@ -39,7 +39,7 @@ namespace Serein.Workbench.Views if (sender is Grid grid && grid.DataContext is IFlowNode nodeModel) { NodeInfoViewModel.ViewNodeModel = nodeModel; - App.GetService().NodeLocate(nodeModel.Guid); + App.GetService().FlowEdit.NodeLocate(nodeModel.Guid); } // 定位节点