diff --git a/Library/Api/IFlowEnvironment.cs b/Library/Api/IFlowEnvironment.cs
index 172b81a..e6f34de 100644
--- a/Library/Api/IFlowEnvironment.cs
+++ b/Library/Api/IFlowEnvironment.cs
@@ -28,7 +28,6 @@ namespace Serein.Library.Api
public delegate void ProjectSavingHandler(ProjectSavingEventArgs eventArgs);
-
///
/// 加载项目文件时成功加载了DLL文件
///
@@ -46,12 +45,34 @@ namespace Serein.Library.Api
///
public delegate void NodeConnectChangeHandler(NodeConnectChangeEventArgs eventArgs);
+
+
+
+ ///
+ /// 环境中新增了一个画布
+ ///
+ ///
+ public delegate void CanvasCreateHandler(CanvasCreateEventArgs eventArgs);
+
+ ///
+ /// 环境中移除了一个画布
+ ///
+ ///
+ public delegate void CanvasRemoveHandler(CanvasRemoveEventArgs eventArgs);
+
///
/// 环境中加载了一个节点
///
///
public delegate void NodeCreateHandler(NodeCreateEventArgs eventArgs);
+ ///
+ /// 环境中移除了一个节点
+ ///
+ ///
+
+ public delegate void NodeRemoveHandler(NodeRemoveEventArgs eventArgs);
+
///
/// 节点放置事件
///
@@ -132,23 +153,9 @@ namespace Serein.Library.Api
public string ErrorTips { get; protected set; } = string.Empty;
}
- //public class LoadNodeEventArgs : FlowEventArgs
- //{
- // public LoadNodeEventArgs(NodeInfo NodeInfo, MethodDetails MethodDetailss)
- // {
- // this.NodeInfo = NodeInfo;
- // this.MethodDetailss = MethodDetailss;
- // }
- // ///
- // /// 项目文件节点信息参数
- // ///
- // public NodeInfo NodeInfo { get; protected set; }
- // ///
- // /// 已加载在环境中的方法描述
- // ///
- // public MethodDetails MethodDetailss { get; protected set; }
- //}
-
+ ///
+ /// 项目加载完成
+ ///
public class ProjectLoadedEventArgs : FlowEventArgs
{
public ProjectLoadedEventArgs()
@@ -156,6 +163,9 @@ namespace Serein.Library.Api
}
}
+ ///
+ /// 项目保存
+ ///
public class ProjectSavingEventArgs : FlowEventArgs
{
public ProjectSavingEventArgs()
@@ -163,6 +173,9 @@ namespace Serein.Library.Api
}
}
+ ///
+ /// 加载了DLL外部依赖
+ ///
public class LoadDllEventArgs : FlowEventArgs
{
public LoadDllEventArgs(NodeLibraryInfo nodeLibraryInfo, List MethodDetailss)
@@ -180,6 +193,9 @@ namespace Serein.Library.Api
public List MethodDetailss { get; protected set; }
}
+ ///
+ /// 移除了DLL外部依赖
+ ///
public class RemoteDllEventArgs : FlowEventArgs
{
public RemoteDllEventArgs()
@@ -187,6 +203,9 @@ namespace Serein.Library.Api
}
}
+ ///
+ /// 改变节点连接关系
+ ///
public class NodeConnectChangeEventArgs : FlowEventArgs
{
@@ -213,12 +232,14 @@ namespace Serein.Library.Api
///
///
///
- public NodeConnectChangeEventArgs(string fromNodeGuid,
+ public NodeConnectChangeEventArgs(string canvasGuid,
+ string fromNodeGuid,
string toNodeGuid,
JunctionOfConnectionType junctionOfConnectionType, // 指示需要创建什么类型的连接线
ConnectionInvokeType connectionInvokeType, // 节点调用的方法类型(true/false/error/cancel )
ConnectChangeType changeType) // 需要创建连接线还是删除连接线
{
+ this.CanvasGuid = canvasGuid;
this.FromNodeGuid = fromNodeGuid;
this.ToNodeGuid = toNodeGuid;
this.ConnectionInvokeType = connectionInvokeType;
@@ -235,13 +256,15 @@ namespace Serein.Library.Api
///
///
///
- public NodeConnectChangeEventArgs(string fromNodeGuid,
+ public NodeConnectChangeEventArgs(string canvasGuid,
+ string fromNodeGuid,
string toNodeGuid,
JunctionOfConnectionType junctionOfConnectionType, // 指示需要创建什么类型的连接线
int argIndex,
ConnectionArgSourceType connectionArgSourceType, // 节点对应的方法入参所需参数来源
ConnectChangeType changeType) // 需要创建连接线还是删除连接线
{
+ CanvasGuid = canvasGuid;
this.FromNodeGuid = fromNodeGuid;
this.ToNodeGuid = toNodeGuid;
this.ChangeType = changeType;
@@ -250,6 +273,9 @@ namespace Serein.Library.Api
this.JunctionOfConnectionType = junctionOfConnectionType;
}
+
+ public string CanvasGuid { get; }
+
///
/// 连接关系中始节点的Guid
///
@@ -282,7 +308,36 @@ namespace Serein.Library.Api
}
+ ///
+ /// 添加了一个画布
+ ///
+ public class CanvasCreateEventArgs : FlowEventArgs
+ {
+ public CanvasCreateEventArgs(
+ FlowCanvasInfo info)
+ {
+ Info = info;
+ }
+ public FlowCanvasInfo Info { get; }
+ }
+
+ ///
+ /// 移除了一个画布
+ ///
+ public class CanvasRemoveEventArgs : FlowEventArgs
+ {
+ public CanvasRemoveEventArgs(string canvasGuid)
+ {
+ CanvasGuid = canvasGuid;
+ }
+
+ public string CanvasGuid { get; }
+ }
+
+ ///
+ /// 添加了节点
+ ///
public class NodeCreateEventArgs : FlowEventArgs
{
///
@@ -290,31 +345,56 @@ namespace Serein.Library.Api
///
/// 节点对象
/// 位置
- public NodeCreateEventArgs(NodeModelBase nodeModel, PositionOfUI position)
+ public NodeCreateEventArgs(string canvasGuid, NodeModelBase nodeModel, PositionOfUI position)
{
+ CanvasGuid = canvasGuid;
this.NodeModel = nodeModel;
this.Position = position;
}
+ public string CanvasGuid { get; }
+
///
/// 节点Model对象
///
public NodeModelBase NodeModel { get; private set; }
public PositionOfUI Position { get; private set; }
- //public bool IsAddInRegion { get; private set; }
public string RegeionGuid { get; private set; }
}
+ ///
+ /// 移除了节点的事件
+ ///
+ public class NodeRemoveEventArgs : FlowEventArgs
+ {
+ public NodeRemoveEventArgs(string canvasGuid, string nodeGuid)
+ {
+ CanvasGuid = canvasGuid;
+ this.NodeGuid = nodeGuid;
+ }
+
+ public string CanvasGuid { get; }
+
+ ///
+ /// 被移除节点的Guid
+ ///
+ public string NodeGuid { get; private set; }
+ }
+
///
/// 节点放置事件参数
///
public class NodePlaceEventArgs : FlowEventArgs
{
- public NodePlaceEventArgs(string nodeGuid, string containerNodeGuid)
+ public NodePlaceEventArgs(string canvasGuid, string nodeGuid, string containerNodeGuid)
{
+ CanvasGuid = canvasGuid;
NodeGuid = nodeGuid;
ContainerNodeGuid = containerNodeGuid;
}
+
+ public string CanvasGuid { get; }
+
///
/// 子节点,该数据为此次时间的主节点
///
@@ -330,10 +410,14 @@ namespace Serein.Library.Api
///
public class NodeTakeOutEventArgs : FlowEventArgs
{
- public NodeTakeOutEventArgs(string nodeGuid)
+ public NodeTakeOutEventArgs(string canvasGuid, string nodeGuid)
{
+ CanvasGuid = canvasGuid;
NodeGuid = nodeGuid;
}
+
+ public string CanvasGuid { get; }
+
///
/// 需要取出的节点Guid
///
@@ -341,34 +425,21 @@ namespace Serein.Library.Api
}
- ///
- /// 环境中移除了一个节点
- ///
- ///
-
- public delegate void NodeRemoveHandler(NodeRemoveEventArgs eventArgs);
- public class NodeRemoveEventArgs : FlowEventArgs
- {
- public NodeRemoveEventArgs(string nodeGuid)
- {
- this.NodeGuid = nodeGuid;
- }
- ///
- /// 被移除节点的Guid
- ///
- public string NodeGuid { get; private set; }
- }
public class StartNodeChangeEventArgs : FlowEventArgs
{
- public StartNodeChangeEventArgs(string oldNodeGuid, string newNodeGuid)
+ public StartNodeChangeEventArgs(string canvasGuid, string oldNodeGuid, string newNodeGuid)
{
+ CanvasGuid = canvasGuid;
this.OldNodeGuid = oldNodeGuid;
this.NewNodeGuid = newNodeGuid; ;
}
+
+ public string CanvasGuid { get; }
+
///
/// 原来的起始节点Guid
///
@@ -577,6 +648,16 @@ namespace Serein.Library.Api
///
event NodeConnectChangeHandler OnNodeConnectChange;
+ ///
+ /// 增加画布事件
+ ///
+ event CanvasCreateHandler OnCanvasCreate;
+
+ ///
+ /// 删除画布事件
+ ///
+ event CanvasRemoveHandler OnCanvasRemove;
+
///
/// 节点创建事件
///
@@ -793,20 +874,37 @@ namespace Serein.Library.Api
#region 流程节点操作接口
+ ///
+ /// 增加画布
+ ///
+ /// 画布名称
+ /// 宽度
+ /// 高度
+ ///
+ Task CreateCanvasAsync(string canvasName, int width , int height);
+
+ ///
+ /// 删除画布
+ ///
+ /// 画布Guid
+ ///
+ Task RemoteCanvasAsync(string canvasGuid);
+
+
///
/// 移动了某个节点(远程插件使用)
///
///
///
///
- void MoveNode(string nodeGuid,double x, double y);
+ void MoveNode(string canvasGuid, string nodeGuid, double x, double y);
///
/// 设置流程起点节点
///
/// 尝试设置为起始节点的节点Guid
/// 被设置为起始节点的Guid
- Task SetStartNodeAsync(string nodeGuid);
+ Task SetStartNodeAsync(string canvasGuid, string nodeGuid);
///
/// 在两个节点之间创建连接关系
@@ -816,11 +914,12 @@ namespace Serein.Library.Api
/// 起始节点控制点
/// 目标节点控制点
/// 决定了方法执行后的后继行为
- Task ConnectInvokeNodeAsync(string fromNodeGuid,
- string toNodeGuid,
- JunctionType fromNodeJunctionType,
- JunctionType toNodeJunctionType,
- ConnectionInvokeType invokeType);
+ Task ConnectInvokeNodeAsync(string canvasGuid,
+ string fromNodeGuid,
+ string toNodeGuid,
+ JunctionType fromNodeJunctionType,
+ JunctionType toNodeJunctionType,
+ ConnectionInvokeType invokeType);
///
/// 在两个节点之间创建连接关系
@@ -831,12 +930,13 @@ namespace Serein.Library.Api
/// 目标节点控制点
/// 决定了方法参数来源
/// 设置第几个参数
- Task ConnectArgSourceNodeAsync(string fromNodeGuid,
- string toNodeGuid,
- JunctionType fromNodeJunctionType,
- JunctionType toNodeJunctionType,
- ConnectionArgSourceType argSourceType,
- int argIndex);
+ Task ConnectArgSourceNodeAsync(string canvasGuid,
+ string fromNodeGuid,
+ string toNodeGuid,
+ JunctionType fromNodeJunctionType,
+ JunctionType toNodeJunctionType,
+ ConnectionArgSourceType argSourceType,
+ int argIndex);
@@ -846,19 +946,19 @@ namespace Serein.Library.Api
/// 控件类型
/// 节点在画布上的位置(
/// 节点绑定的方法说明
- Task CreateNodeAsync(NodeControlType nodeType, PositionOfUI position, MethodDetailsInfo methodDetailsInfo = null);
+ Task CreateNodeAsync(string canvasGuid, NodeControlType nodeType, PositionOfUI position, MethodDetailsInfo methodDetailsInfo = null);
///
/// 将节点放置在容器中
///
///
- Task PlaceNodeToContainerAsync(string nodeGuid, string containerNodeGuid);
+ Task PlaceNodeToContainerAsync(string canvasGuid, string nodeGuid, string containerNodeGuid);
///
/// 将节点从容器中脱离
///
///
- Task TakeOutNodeToContainerAsync(string nodeGuid);
+ Task TakeOutNodeToContainerAsync(string canvasGuid, string nodeGuid);
///
@@ -876,7 +976,7 @@ namespace Serein.Library.Api
/// 起始节点
/// 目标节点
/// 连接类型
- Task RemoveConnectInvokeAsync(string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType);
+ Task RemoveConnectInvokeAsync(string canvasGuid, string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType);
///
/// 移除连接节点之间参数传递的关系
@@ -885,13 +985,13 @@ namespace Serein.Library.Api
/// 目标节点Guid
/// 连接到第几个参数
/// 参数来源类型
- Task RemoveConnectArgSourceAsync(string fromNodeGuid, string toNodeGuid, int argIndex);
+ Task RemoveConnectArgSourceAsync(string canvasGuid, string fromNodeGuid, string toNodeGuid, int argIndex);
///
/// 移除节点/区域/基础控件
///
/// 待移除的节点Guid
- Task RemoveNodeAsync(string nodeGuid);
+ Task RemoveNodeAsync(string canvasGuid, string nodeGuid);
///
/// 改变可选参数的数目
diff --git a/Library/Extension/NodeModelExtension.cs b/Library/Extension/FlowModelExtension.cs
similarity index 94%
rename from Library/Extension/NodeModelExtension.cs
rename to Library/Extension/FlowModelExtension.cs
index b400bf4..9e6e652 100644
--- a/Library/Extension/NodeModelExtension.cs
+++ b/Library/Extension/FlowModelExtension.cs
@@ -7,14 +7,52 @@ using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using System.Xml.Linq;
namespace Serein.Library
{
///
/// 节点方法拓展
///
- public static class NodeModelExtension
+ public static class FlowModelExtension
{
+ ///
+ /// 导出为画布信息
+ ///
+ ///
+ ///
+ public static FlowCanvasInfo ToInfo(this FlowCanvasModel model)
+ {
+ return new FlowCanvasInfo
+ {
+ Guid = model.Guid,
+ Height = model.Height,
+ Width = model.Width,
+ Name = model.Name,
+ ScaleX = model.ScaleX,
+ ScaleY = model.ScaleY,
+ ViewX = model.ViewX,
+ ViewY = model.ViewY,
+ };
+ }
+
+ ///
+ /// 从画布信息加载
+ ///
+ ///
+ ///
+ public static void LoadInfo(this FlowCanvasModel model, FlowCanvasInfo info)
+ {
+ model.Guid = info.Guid;
+ model.Height = info.Height;
+ model.Width = info.Width;
+ model.Name = info.Name;
+ model.ScaleX = info.ScaleX;
+ model.ScaleY = info.ScaleY;
+ model.ViewX = info.ViewX;
+ model.ViewY = info.ViewY;
+ }
+
///
/// 输出方法参数信息
///
diff --git a/Library/FlowNode/ContainerFlowEnvironment.cs b/Library/FlowNode/ContainerFlowEnvironment.cs
deleted file mode 100644
index 607b65c..0000000
--- a/Library/FlowNode/ContainerFlowEnvironment.cs
+++ /dev/null
@@ -1,390 +0,0 @@
-using Serein.Library.Api;
-using Serein.Library.Utils;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Serein.Library
-{
-
- ///
- /// 不提供流程操作能力,仅提供容器功能
- ///
- public class ContainerFlowEnvironment : IFlowEnvironment, ISereinIOC
- {
- ///
- /// 本地运行环境缓存的持久化实例
- ///
- private Dictionary PersistennceInstance { get; } = new Dictionary();
- public ContainerFlowEnvironment()
- {
-
- }
-
- private ISereinIOC sereinIOC => this;
- public ISereinIOC IOC => sereinIOC;
-
- public string EnvName => throw new NotImplementedException();
- public string ProjectFileLocation => throw new NotImplementedException();
-
- public bool IsGlobalInterrupt => throw new NotImplementedException();
-
- public bool IsControlRemoteEnv => throw new NotImplementedException();
-
- public InfoClass InfoClass { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
- public RunState FlowState { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
- public RunState FlipFlopState { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
-
- public IFlowEnvironment CurrentEnv => this;
-
- public UIContextOperation UIContextOperation { get; set; }
- public NodeMVVMManagement NodeMVVMManagement { get; set; }
-
- ///
- /// 设置在UI线程操作的线程上下文
- ///
- ///
- public void SetUIContextOperation(UIContextOperation uiContextOperation)
- {
- this.UIContextOperation = uiContextOperation;
- }
-
- public void ActivateFlipflopNode(string nodeGuid)
- {
- throw new NotImplementedException();
- }
-
- public Task ChangeParameter(string nodeGuid, bool isAdd, int paramIndex)
- {
- throw new NotImplementedException();
- }
-
- public Task ConnectArgSourceNodeAsync(string fromNodeGuid, string toNodeGuid, JunctionType fromNodeJunctionType, JunctionType toNodeJunctionType, ConnectionArgSourceType argSourceType, int argIndex)
- {
- throw new NotImplementedException();
- }
-
- public Task ConnectInvokeNodeAsync(string fromNodeGuid, string toNodeGuid, JunctionType fromNodeJunctionType, JunctionType toNodeJunctionType, ConnectionInvokeType invokeType)
- {
- throw new NotImplementedException();
- }
-
- public Task<(bool, RemoteMsgUtil)> ConnectRemoteEnv(string addres, int port, string token)
- {
- throw new NotImplementedException();
- }
-
- public Task CreateNodeAsync(NodeControlType nodeType, PositionOfUI position, MethodDetailsInfo methodDetailsInfo = null)
- {
- throw new NotImplementedException();
- }
-
- public Task ExitFlowAsync()
- {
- throw new NotImplementedException();
- }
-
- public void ExitRemoteEnv()
- {
- throw new NotImplementedException();
- }
-
- public Task GetEnvInfoAsync()
- {
- throw new NotImplementedException();
- }
-
- public Task GetProjectInfoAsync()
- {
- throw new NotImplementedException();
- }
-
- public Task
- public FlowCanvas Canvas { get; set; }
+ public FlowCanvasInfo Canvas { get; set; }
///
/// 版本
@@ -98,8 +98,12 @@ namespace Serein.Library
///
/// 画布信息,项目文件相关
///
- public class FlowCanvas
+ public class FlowCanvasInfo
{
+ public string Guid { get; set; }
+
+ public string Name { get; set; }
+
///
/// 宽度
///
@@ -178,6 +182,12 @@ namespace Serein.Library
///
public class NodeInfo
{
+ ///
+ /// 所属画布Guid
+ ///
+ public string CanvasGuid { get; set; }
+
+
///
/// 节点的GUID
///
diff --git a/NodeFlow/Env/EnvMsgTheme.cs b/NodeFlow/Env/EnvMsgTheme.cs
index 15bf610..b69cc04 100644
--- a/NodeFlow/Env/EnvMsgTheme.cs
+++ b/NodeFlow/Env/EnvMsgTheme.cs
@@ -22,6 +22,14 @@
///
public const string ExitFlow = nameof(ExitFlow);
///
+ /// 尝试新增画布
+ ///
+ public const string CreateCanvas = nameof(CreateCanvas);
+ ///
+ /// 尝试移除画布
+ ///
+ public const string RemoveCanvas = nameof(RemoveCanvas);
+ ///
/// 尝试移动某个节点
///
public const string MoveNode = nameof(MoveNode);
diff --git a/NodeFlow/Env/FlowEnvironment.cs b/NodeFlow/Env/FlowEnvironment.cs
index 6a7010f..bb6158a 100644
--- a/NodeFlow/Env/FlowEnvironment.cs
+++ b/NodeFlow/Env/FlowEnvironment.cs
@@ -1,5 +1,6 @@
using Serein.Library;
using Serein.Library.Api;
+using Serein.Library.FlowNode;
using Serein.Library.Utils;
using Serein.Library.Utils.SereinExpression;
using Serein.NodeFlow.Model;
@@ -201,6 +202,16 @@ namespace Serein.NodeFlow.Env
///
public event EnvOutHandler? OnEnvOut;
+ ///
+ /// 本地环境添加了画布
+ ///
+ public event CanvasCreateHandler OnCanvasCreate;
+
+ ///
+ /// 本地环境移除了画布
+ ///
+ public event CanvasRemoveHandler OnCanvasRemove;
+
#endregion
#region 属性
@@ -271,40 +282,6 @@ namespace Serein.NodeFlow.Env
///
private readonly FlowLibraryManagement FlowLibraryManagement;
-#if false
-
- ///
- /// Library 与 MethodDetailss的依赖关系
- ///
- public ConcurrentDictionary> MethodDetailsOfLibraryInfos { get; } = [];
-
-
- ///
- /// 存储已加载的程序集
- /// Key:程序集的FullName
- /// Value:构造的方法信息
- ///
- public ConcurrentDictionary LibraryInfos { get; } = [];
-
- ///
- /// 存储已加载的方法信息。描述所有DLL中NodeAction特性的方法的原始副本
- /// Key:反射时获取的MethodInfo.MehtodName
- /// Value:构造的方法信息
- ///
- public ConcurrentDictionary MethodDetailss { get; } = [];
-
- ///
- /// 从dll中加载的类的注册类型
- ///
- private Dictionary> AutoRegisterTypes { get; } = [];
-
- ///
- /// 存放所有通过Emit加载的委托
- /// md.Methodname - delegate
- ///
- private ConcurrentDictionary MethodDelegates { get; } = [];
-#endif
-
///
/// IOC对象容器管理
///
@@ -321,6 +298,11 @@ namespace Serein.NodeFlow.Env
///
private Dictionary NodeModels { get; } = [];
+ ///
+ /// 运行环境加载的画布集合
+ ///
+ private Dictionary FlowCanvass { get; } = [];
+
///
/// 存放触发器节点(运行时全部调用)
///
@@ -382,7 +364,6 @@ namespace Serein.NodeFlow.Env
}
-
///
/// 异步运行
///
@@ -581,7 +562,7 @@ namespace Serein.NodeFlow.Env
_ = Task.Run( async () =>
{
await LoadNodeInfosAsync(projectData.Nodes.ToList()); // 加载节点信息
- await SetStartNodeAsync(projectData.StartNode); // 设置起始节点
+ await SetStartNodeAsync("", projectData.StartNode); // 设置起始节点
});
}
@@ -786,7 +767,46 @@ namespace Serein.NodeFlow.Env
//}
}
-
+ ///
+ /// 增加画布
+ ///
+ /// 画布名称
+ /// 宽度
+ /// 高度
+ ///
+ public Task CreateCanvasAsync(string canvasName, int width, int height)
+ {
+ var model = new FlowCanvasModel(this)
+ {
+ Guid = Guid.NewGuid().ToString(),
+ Height = height,
+ Name = canvasName,
+ Width = height,
+ };
+ var info = model.ToInfo();
+ FlowCanvass.Add(model.Guid, model);
+ OnCanvasCreate.Invoke(new CanvasCreateEventArgs(info));
+ return Task.FromResult(info);
+ }
+
+ ///
+ /// 删除画布
+ ///
+ /// 画布Guid
+ ///
+ public Task RemoteCanvasAsync(string canvasGuid)
+ {
+
+ if (!FlowCanvass.TryGetValue(canvasGuid, out var model))
+ {
+ return Task.FromResult(false);
+ }
+ var count = NodeModels.Values.Count(node => node.CanvasGuid.Equals(canvasGuid));
+ return Task.FromResult(count == 0);
+ }
+
+
+
///
/// 从节点信息集合批量加载节点控件
///
@@ -827,7 +847,7 @@ namespace Serein.NodeFlow.Env
TryAddNode(nodeModel); // 加载项目时将节点加载到环境中
await UIContextOperation.InvokeAsync(() =>
- OnNodeCreate?.Invoke(new NodeCreateEventArgs(nodeModel, nodeInfo.Position))); // 添加到UI上
+ OnNodeCreate?.Invoke(new NodeCreateEventArgs(nodeInfo.CanvasGuid, nodeModel, nodeInfo.Position))); // 添加到UI上
}
#endregion
@@ -853,7 +873,7 @@ namespace Serein.NodeFlow.Env
if (result)
{
await UIContextOperation.InvokeAsync(() => OnNodePlace?.Invoke(
- new NodePlaceEventArgs(nodeModel.Guid, containerNode.Guid)));
+ new NodePlaceEventArgs(nodeInfo.CanvasGuid, nodeModel.Guid, containerNode.Guid)));
}
@@ -864,6 +884,7 @@ namespace Serein.NodeFlow.Env
#region 确定节点之间的方法调用关系
foreach (var nodeInfo in nodeInfos)
{
+ var canvasGuid = nodeInfo.CanvasGuid;
if (!TryGetNodeModel(nodeInfo.Guid, out var fromNodeModel))
{
return;
@@ -886,7 +907,7 @@ namespace Serein.NodeFlow.Env
// 防御性代码,加载正常保存的项目文件不会进入这里
continue;
};
- var isSuccessful = ConnectInvokeOfNode(fromNodeModel, toNodeModel, item.connectionType); // 加载时确定节点间的连接关系
+ var isSuccessful = ConnectInvokeOfNode(canvasGuid, fromNodeModel, toNodeModel, item.connectionType); // 加载时确定节点间的连接关系
}
}
@@ -916,6 +937,7 @@ namespace Serein.NodeFlow.Env
#region 确定节点之间的参数调用关系
foreach (var toNode in NodeModels.Values)
{
+ var canvasGuid = toNode.Guid;
if (toNode.MethodDetails.ParameterDetailss == null)
{
continue;
@@ -927,7 +949,7 @@ namespace Serein.NodeFlow.Env
&& NodeModels.TryGetValue(pd.ArgDataSourceNodeGuid, out var fromNode))
{
- await ConnectArgSourceOfNodeAsync(fromNode, toNode, pd.ArgDataSourceType, pd.Index);
+ await ConnectArgSourceOfNodeAsync(canvasGuid, fromNode, toNode, pd.ArgDataSourceType, pd.Index);
}
}
}
@@ -945,14 +967,19 @@ namespace Serein.NodeFlow.Env
///
/// 流程正在运行时创建节点
///
- ///
- ///
+ /// 所属画布
+ /// 所属类型
+ /// 所处位置
/// 如果是表达式节点条件节点,该项为null
- public Task CreateNodeAsync(NodeControlType nodeControlType,
+ public Task CreateNodeAsync(string canvasGuid,
+ NodeControlType nodeControlType,
PositionOfUI position,
MethodDetailsInfo? methodDetailsInfo = null)
{
-
+ if (!FlowCanvass.ContainsKey(canvasGuid))
+ {
+ return Task.FromResult(null);
+ }
NodeModelBase? nodeModel;
if (methodDetailsInfo is null)
{
@@ -976,13 +1003,13 @@ namespace Serein.NodeFlow.Env
nodeModel.Position = position;
// 通知UI更改
- UIContextOperation?.Invoke(() => OnNodeCreate?.Invoke(new NodeCreateEventArgs(nodeModel, position)));
+ UIContextOperation?.Invoke(() => OnNodeCreate?.Invoke(new NodeCreateEventArgs(canvasGuid, nodeModel, position)));
// 因为需要UI先布置了元素,才能通知UI变更特效
// 如果不存在流程起始控件,默认设置为流程起始控件
if (StartNode is null)
{
- SetStartNode(nodeModel);
+ SetStartNode(canvasGuid, nodeModel);
}
var nodeInfo = nodeModel.ToInfo();
return Task.FromResult(nodeInfo);
@@ -993,8 +1020,13 @@ namespace Serein.NodeFlow.Env
/// 将节点放置在容器中
///
///
- public Task PlaceNodeToContainerAsync(string nodeGuid, string containerNodeGuid)
+ public Task PlaceNodeToContainerAsync(string canvasGuid,
+ string nodeGuid, string containerNodeGuid)
{
+ if (!FlowCanvass.ContainsKey(canvasGuid))
+ {
+ return Task.FromResult(false);
+ }
// 获取目标节点与容器节点
if (!TryGetNodeModel(nodeGuid, out var nodeModel))
{
@@ -1017,7 +1049,7 @@ namespace Serein.NodeFlow.Env
{
_ = UIContextOperation?.InvokeAsync(() =>
{
- OnNodePlace?.Invoke(new NodePlaceEventArgs(nodeGuid, containerNodeGuid)); // 通知UI更改节点放置位置
+ OnNodePlace?.Invoke(new NodePlaceEventArgs(canvasGuid, nodeGuid, containerNodeGuid)); // 通知UI更改节点放置位置
});
}
return Task.FromResult(result);
@@ -1028,8 +1060,13 @@ namespace Serein.NodeFlow.Env
/// 将节点从容器节点中脱离
///
///
- public Task TakeOutNodeToContainerAsync(string nodeGuid)
+ public Task TakeOutNodeToContainerAsync(string canvasGuid,
+ string nodeGuid)
{
+ if (!FlowCanvass.ContainsKey(canvasGuid))
+ {
+ return Task.FromResult(false);
+ }
// 获取目标节点与容器节点
if (!TryGetNodeModel(nodeGuid, out var nodeModel))
{
@@ -1044,7 +1081,7 @@ namespace Serein.NodeFlow.Env
{
_ = UIContextOperation?.InvokeAsync(() =>
{
- OnNodeTakeOut?.Invoke(new NodeTakeOutEventArgs(nodeGuid)); // 重新放置在画布上
+ OnNodeTakeOut?.Invoke(new NodeTakeOutEventArgs(canvasGuid, nodeGuid)); // 重新放置在画布上
});
}
return Task.FromResult(result);
@@ -1059,8 +1096,12 @@ namespace Serein.NodeFlow.Env
///
///
///
- public async Task RemoveNodeAsync(string nodeGuid)
+ public async Task RemoveNodeAsync(string canvasGuid, string nodeGuid)
{
+ if (!FlowCanvass.ContainsKey(canvasGuid))
+ {
+ return false;
+ }
if (!TryGetNodeModel(nodeGuid, out var remoteNode))
{
return false;
@@ -1083,6 +1124,7 @@ namespace Serein.NodeFlow.Env
pNode.SuccessorNodes[pCType].Remove(remoteNode);
UIContextOperation?.Invoke(() => OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(
+ canvasGuid,
pNode.Guid,
remoteNode.Guid,
JunctionOfConnectionType.Invoke,
@@ -1100,7 +1142,7 @@ namespace Serein.NodeFlow.Env
{
NodeModelBase? toNode = snc.Value[i];
- await RemoteConnectAsync(remoteNode, toNode, connectionType);
+ await RemoteConnectAsync(canvasGuid, remoteNode, toNode, connectionType);
}
}
@@ -1109,7 +1151,7 @@ namespace Serein.NodeFlow.Env
// 从集合中移除节点
NodeModels.Remove(nodeGuid);
- UIContextOperation?.Invoke(() => OnNodeRemove?.Invoke(new NodeRemoveEventArgs(nodeGuid)));
+ UIContextOperation?.Invoke(() => OnNodeRemove?.Invoke(new NodeRemoveEventArgs(canvasGuid, nodeGuid)));
return true;
}
@@ -1121,15 +1163,16 @@ namespace Serein.NodeFlow.Env
/// 起始节点控制点
/// 目标节点控制点
/// 连接关系
- public Task ConnectInvokeNodeAsync(string fromNodeGuid,
+ public Task ConnectInvokeNodeAsync(string canvasGuid,
+ string fromNodeGuid,
string toNodeGuid,
JunctionType fromNodeJunctionType,
JunctionType toNodeJunctionType,
ConnectionInvokeType invokeType)
{
-
+
// 获取起始节点与目标节点
- if (!TryGetNodeModel(fromNodeGuid, out var fromNode) || !TryGetNodeModel(toNodeGuid, out var toNode))
+ if (!FlowCanvass.ContainsKey(canvasGuid) || !TryGetNodeModel(fromNodeGuid, out var fromNode) || !TryGetNodeModel(toNodeGuid, out var toNode))
{
return Task.FromResult(false);
}
@@ -1150,7 +1193,7 @@ namespace Serein.NodeFlow.Env
(fromNode, toNode) = (toNode, fromNode);
}
// 从起始节点“下一个方法”控制点,连接到目标节点“方法调用”控制点
- state = ConnectInvokeOfNode(fromNode, toNode, invokeType); // 本地环境进行连接
+ state = ConnectInvokeOfNode(canvasGuid, fromNode, toNode, invokeType); // 本地环境进行连接
}
return Task.FromResult(state);
@@ -1192,16 +1235,16 @@ namespace Serein.NodeFlow.Env
/// 目标节点Guid
/// 连接关系
///
- public async Task RemoveConnectInvokeAsync(string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType)
+ public async Task RemoveConnectInvokeAsync(string canvasGuid, string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType)
{
// 获取起始节点与目标节点
- if (!TryGetNodeModel(fromNodeGuid, out var fromNode) || !TryGetNodeModel(toNodeGuid, out var toNode))
+ if (!FlowCanvass.ContainsKey(canvasGuid) || !TryGetNodeModel(fromNodeGuid, out var fromNode) || !TryGetNodeModel(toNodeGuid, out var toNode))
{
return false;
}
if (fromNode is null || toNode is null) return false;
- var result = await RemoteConnectAsync(fromNode, toNode, connectionType);
+ var result = await RemoteConnectAsync(canvasGuid, fromNode, toNode, connectionType);
return result;
}
@@ -1215,7 +1258,8 @@ namespace Serein.NodeFlow.Env
/// 目标节点的第几个参数
/// 调用目标节点对应方法时,对应参数来源类型
///
- public async Task ConnectArgSourceNodeAsync(string fromNodeGuid,
+ public async Task ConnectArgSourceNodeAsync(string canvasGuid,
+ string fromNodeGuid,
string toNodeGuid,
JunctionType fromNodeJunctionType,
JunctionType toNodeJunctionType,
@@ -1224,7 +1268,7 @@ namespace Serein.NodeFlow.Env
{
// 获取起始节点与目标节点
- if (!TryGetNodeModel(fromNodeGuid, out var fromNode) || !TryGetNodeModel(toNodeGuid, out var toNode))
+ if (!FlowCanvass.ContainsKey(canvasGuid) || !TryGetNodeModel(fromNodeGuid, out var fromNode) || !TryGetNodeModel(toNodeGuid, out var toNode))
{
return false;
}
@@ -1246,7 +1290,7 @@ namespace Serein.NodeFlow.Env
}
// 确定方法入参关系
- state = await ConnectArgSourceOfNodeAsync(fromNode, toNode, connectionArgSourceType, argIndex); // 本地环境进行连接
+ state = await ConnectArgSourceOfNodeAsync(canvasGuid, fromNode, toNode, connectionArgSourceType, argIndex); // 本地环境进行连接
}
return state;
@@ -1259,15 +1303,15 @@ namespace Serein.NodeFlow.Env
/// 起始节点Guid
/// 目标节点Guid
/// 连接到第几个参数
- public async Task RemoveConnectArgSourceAsync(string fromNodeGuid, string toNodeGuid, int argIndex)
+ public async Task RemoveConnectArgSourceAsync(string canvasGuid, string fromNodeGuid, string toNodeGuid, int argIndex)
{
// 获取起始节点与目标节点
- if (!TryGetNodeModel(fromNodeGuid, out var fromNode) || !TryGetNodeModel(toNodeGuid, out var toNode))
+ if (!FlowCanvass.ContainsKey(canvasGuid) || !TryGetNodeModel(fromNodeGuid, out var fromNode) || !TryGetNodeModel(toNodeGuid, out var toNode))
{
return false;
}
if (fromNode is null || toNode is null) return false;
- var result = await RemoteConnectAsync(fromNode, toNode, argIndex);
+ var result = await RemoteConnectAsync(canvasGuid, fromNode, toNode, argIndex);
return result;
}
@@ -1328,9 +1372,9 @@ namespace Serein.NodeFlow.Env
///
///
///
- public void MoveNode(string nodeGuid, double x, double y)
+ public void MoveNode(string canvasGuid, string nodeGuid, double x, double y)
{
- if (!TryGetNodeModel(nodeGuid, out var nodeModel))
+ if (!FlowCanvass.ContainsKey(canvasGuid) || !TryGetNodeModel(nodeGuid, out var nodeModel))
{
return;
}
@@ -1344,13 +1388,13 @@ namespace Serein.NodeFlow.Env
/// 设置起点控件
///
///
- public Task SetStartNodeAsync(string newNodeGuid)
+ public Task SetStartNodeAsync(string canvasGuid, string newNodeGuid)
{
- if (!TryGetNodeModel(newNodeGuid, out var newStartNodeModel))
+ if (!FlowCanvass.ContainsKey(canvasGuid) || !TryGetNodeModel(newNodeGuid, out var newStartNodeModel))
{
return Task.FromResult(StartNode?.Guid ?? string.Empty);
}
- SetStartNode(newStartNodeModel);
+ SetStartNode(canvasGuid, newStartNodeModel);
return Task.FromResult(StartNode?.Guid ?? string.Empty);
}
@@ -1483,7 +1527,6 @@ namespace Serein.NodeFlow.Env
#endregion
-
#region 流程依赖类库的接口
@@ -1580,21 +1623,27 @@ namespace Serein.NodeFlow.Env
/// 目标节点Model
/// 连接关系
///
- private async Task RemoteConnectAsync(NodeModelBase fromNode, NodeModelBase toNode, ConnectionInvokeType connectionType)
+ private async Task RemoteConnectAsync(string canvasGuid, NodeModelBase fromNode, NodeModelBase toNode, ConnectionInvokeType connectionType)
{
+ if (!FlowCanvass.ContainsKey(canvasGuid))
+ {
+ return false;
+ }
fromNode.SuccessorNodes[connectionType].Remove(toNode);
toNode.PreviousNodes[connectionType].Remove(fromNode);
if (OperatingSystem.IsWindows())
{
- await UIContextOperation.InvokeAsync(() => OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(
- fromNode.Guid,
- toNode.Guid,
- JunctionOfConnectionType.Invoke,
- connectionType,
- NodeConnectChangeEventArgs.ConnectChangeType.Remove)));
- }
+ await UIContextOperation.InvokeAsync(() => OnNodeConnectChange?.Invoke(
+ new NodeConnectChangeEventArgs(
+ canvasGuid,
+ fromNode.Guid,
+ toNode.Guid,
+ JunctionOfConnectionType.Invoke,
+ connectionType,
+ NodeConnectChangeEventArgs.ConnectChangeType.Remove)));
+ }
return true;
}
///
@@ -1604,8 +1653,12 @@ namespace Serein.NodeFlow.Env
/// 目标节点Model
/// 连接关系
///
- private async Task RemoteConnectAsync(NodeModelBase fromNode, NodeModelBase toNode, int argIndex)
+ private async Task RemoteConnectAsync(string canvasGuid, NodeModelBase fromNode, NodeModelBase toNode, int argIndex)
{
+ if (!FlowCanvass.ContainsKey(canvasGuid))
+ {
+ return false;
+ }
if (string.IsNullOrEmpty(toNode.MethodDetails.ParameterDetailss[argIndex].ArgDataSourceNodeGuid))
{
return false;
@@ -1615,14 +1668,16 @@ namespace Serein.NodeFlow.Env
if (OperatingSystem.IsWindows())
{
- await UIContextOperation.InvokeAsync(() => OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(
- fromNode.Guid,
- toNode.Guid,
- JunctionOfConnectionType.Arg,
- argIndex,
- ConnectionArgSourceType.GetPreviousNodeData,
- NodeConnectChangeEventArgs.ConnectChangeType.Remove)));
- }
+ await UIContextOperation.InvokeAsync(() => OnNodeConnectChange?.Invoke(
+ new NodeConnectChangeEventArgs(
+ canvasGuid,
+ fromNode.Guid,
+ toNode.Guid,
+ JunctionOfConnectionType.Arg,
+ argIndex,
+ ConnectionArgSourceType.GetPreviousNodeData,
+ NodeConnectChangeEventArgs.ConnectChangeType.Remove)));
+ }
return true;
}
@@ -1721,8 +1776,12 @@ namespace Serein.NodeFlow.Env
/// 起始节点
/// 目标节点
/// 连接关系
- private bool ConnectInvokeOfNode(NodeModelBase fromNode, NodeModelBase toNode, ConnectionInvokeType invokeType)
+ private bool ConnectInvokeOfNode(string canvasGuid, NodeModelBase fromNode, NodeModelBase toNode, ConnectionInvokeType invokeType)
{
+ if (!FlowCanvass.ContainsKey(canvasGuid))
+ {
+ return false;
+ }
if (fromNode is null || toNode is null || fromNode == toNode)
{
return false;
@@ -1783,6 +1842,7 @@ namespace Serein.NodeFlow.Env
UIContextOperation?.Invoke(() =>
OnNodeConnectChange?.Invoke(
new NodeConnectChangeEventArgs(
+ canvasGuid,
fromNode.Guid, // 从哪个节点开始
toNode.Guid, // 连接到那个节点
JunctionOfConnectionType.Invoke,
@@ -1810,21 +1870,28 @@ namespace Serein.NodeFlow.Env
///
///
///
- private async Task ConnectArgSourceOfNodeAsync(NodeModelBase fromNode,
+ private async Task ConnectArgSourceOfNodeAsync(string canvasGuid,
+ NodeModelBase fromNode,
NodeModelBase toNode,
ConnectionArgSourceType connectionArgSourceType,
int argIndex)
{
+ if (!FlowCanvass.ContainsKey(canvasGuid))
+ {
+ return false;
+ }
+
var toNodeArgSourceGuid = toNode.MethodDetails.ParameterDetailss[argIndex].ArgDataSourceNodeGuid;
if (!string.IsNullOrEmpty(toNodeArgSourceGuid))
{
- await RemoteConnectAsync(fromNode, toNode, argIndex);
+ await RemoteConnectAsync(canvasGuid, fromNode, toNode, argIndex);
}
toNode.MethodDetails.ParameterDetailss[argIndex].ArgDataSourceNodeGuid = fromNode.Guid;
toNode.MethodDetails.ParameterDetailss[argIndex].ArgDataSourceType = connectionArgSourceType;
await UIContextOperation.InvokeAsync(() =>
OnNodeConnectChange?.Invoke(
new NodeConnectChangeEventArgs(
+ canvasGuid,
fromNode.Guid, // 从哪个节点开始
toNode.Guid, // 连接到那个节点
JunctionOfConnectionType.Arg,
@@ -1841,11 +1908,15 @@ namespace Serein.NodeFlow.Env
///
///
///
- private void SetStartNode(NodeModelBase newStartNode)
+ private void SetStartNode(string canvasGuid, NodeModelBase newStartNode)
{
+ if (!FlowCanvass.ContainsKey(canvasGuid))
+ {
+ return;
+ }
var oldNodeGuid = StartNode?.Guid;
StartNode = newStartNode;
- UIContextOperation?.Invoke(() => OnStartNodeChange?.Invoke(new StartNodeChangeEventArgs(oldNodeGuid, StartNode.Guid)));
+ UIContextOperation?.Invoke(() => OnStartNodeChange?.Invoke(new StartNodeChangeEventArgs(canvasGuid, oldNodeGuid, StartNode.Guid)));
//if (OperatingSystem.IsWindows())
//{
diff --git a/NodeFlow/Env/FlowEnvironmentDecorator.cs b/NodeFlow/Env/FlowEnvironmentDecorator.cs
index fdc2aa0..c19b175 100644
--- a/NodeFlow/Env/FlowEnvironmentDecorator.cs
+++ b/NodeFlow/Env/FlowEnvironmentDecorator.cs
@@ -56,6 +56,8 @@ namespace Serein.NodeFlow.Env
private int _loadingProjectFlag = 0; // 使用原子自增代替锁
+
+
///
/// 传入false时,将停止数据通知。传入true时,
///
@@ -131,6 +133,18 @@ namespace Serein.NodeFlow.Env
remove { currentFlowEnvironmentEvent.OnNodeConnectChange -= value; }
}
+
+ public event CanvasCreateHandler OnCanvasCreate
+ {
+ add { currentFlowEnvironmentEvent.OnCanvasCreate += value; }
+ remove { currentFlowEnvironmentEvent.OnCanvasCreate -= value; }
+ }
+ public event CanvasRemoveHandler OnCanvasRemove
+ {
+ add { currentFlowEnvironmentEvent.OnCanvasRemove += value; }
+ remove { currentFlowEnvironmentEvent.OnCanvasRemove -= value; }
+ }
+
public event NodeCreateHandler OnNodeCreate
{
add { currentFlowEnvironmentEvent.OnNodeCreate += value; }
@@ -217,7 +231,27 @@ namespace Serein.NodeFlow.Env
currentFlowEnvironment.ActivateFlipflopNode(nodeGuid);
}
-
+ ///
+ /// 增加画布
+ ///
+ /// 画布名称
+ /// 宽度
+ /// 高度
+ ///
+ public async Task CreateCanvasAsync(string canvasName, int width, int height)
+ {
+ return await currentFlowEnvironment.CreateCanvasAsync(canvasName, width, height);
+ }
+
+ ///
+ /// 删除画布
+ ///
+ /// 画布Guid
+ ///
+ public async Task RemoteCanvasAsync(string canvasGuid)
+ {
+ return await currentFlowEnvironment.RemoteCanvasAsync(canvasGuid);
+ }
///
@@ -228,13 +262,14 @@ namespace Serein.NodeFlow.Env
/// 起始节点控制点
/// 目标节点控制点
/// 决定了方法执行后的后继行为
- public async Task ConnectInvokeNodeAsync(string fromNodeGuid,
+ public async Task ConnectInvokeNodeAsync(string canvasGuid,
+ string fromNodeGuid,
string toNodeGuid,
JunctionType fromNodeJunctionType,
JunctionType toNodeJunctionType,
ConnectionInvokeType invokeType)
{
- return await currentFlowEnvironment.ConnectInvokeNodeAsync(fromNodeGuid, toNodeGuid, fromNodeJunctionType, toNodeJunctionType, invokeType);
+ return await currentFlowEnvironment.ConnectInvokeNodeAsync(canvasGuid, fromNodeGuid, toNodeGuid, fromNodeJunctionType, toNodeJunctionType, invokeType);
}
@@ -247,14 +282,15 @@ namespace Serein.NodeFlow.Env
/// 目标节点控制点
/// 决定了方法参数来源
/// 设置第几个参数
- public async Task ConnectArgSourceNodeAsync(string fromNodeGuid,
+ public async Task ConnectArgSourceNodeAsync(string canvasGuid,
+ string fromNodeGuid,
string toNodeGuid,
JunctionType fromNodeJunctionType,
JunctionType toNodeJunctionType,
ConnectionArgSourceType argSourceType,
int argIndex)
{
- return await currentFlowEnvironment.ConnectArgSourceNodeAsync(fromNodeGuid, toNodeGuid, fromNodeJunctionType, toNodeJunctionType, argSourceType, argIndex);
+ return await currentFlowEnvironment.ConnectArgSourceNodeAsync(canvasGuid, fromNodeGuid, toNodeGuid, fromNodeJunctionType, toNodeJunctionType, argSourceType, argIndex);
}
@@ -291,10 +327,10 @@ namespace Serein.NodeFlow.Env
SetProjectLoadingFlag(true);
}
- public async Task CreateNodeAsync(NodeControlType nodeBase, PositionOfUI position, MethodDetailsInfo methodDetailsInfo = null)
+ public async Task CreateNodeAsync(string canvasGuid, NodeControlType nodeBase, PositionOfUI position, MethodDetailsInfo methodDetailsInfo = null)
{
SetProjectLoadingFlag(false);
- var result = await currentFlowEnvironment.CreateNodeAsync(nodeBase, position, methodDetailsInfo); // 装饰器调用
+ var result = await currentFlowEnvironment.CreateNodeAsync(canvasGuid, nodeBase, position, methodDetailsInfo); // 装饰器调用
SetProjectLoadingFlag(true);
return result;
}
@@ -304,10 +340,10 @@ namespace Serein.NodeFlow.Env
/// 将节点放置在容器中
///
///
- public async Task PlaceNodeToContainerAsync(string nodeGuid, string containerNodeGuid)
+ public async Task PlaceNodeToContainerAsync(string canvasGuid, string nodeGuid, string containerNodeGuid)
{
SetProjectLoadingFlag(false);
- var result = await currentFlowEnvironment.PlaceNodeToContainerAsync(nodeGuid, containerNodeGuid); // 装饰器调用
+ var result = await currentFlowEnvironment.PlaceNodeToContainerAsync(canvasGuid, nodeGuid, containerNodeGuid); // 装饰器调用
SetProjectLoadingFlag(true);
return result;
}
@@ -316,10 +352,10 @@ namespace Serein.NodeFlow.Env
/// 将节点从容器中脱离
///
///
- public async Task TakeOutNodeToContainerAsync(string nodeGuid)
+ public async Task TakeOutNodeToContainerAsync(string canvasGuid, string nodeGuid)
{
SetProjectLoadingFlag(false);
- var result = await currentFlowEnvironment.TakeOutNodeToContainerAsync(nodeGuid); // 装饰器调用
+ var result = await currentFlowEnvironment.TakeOutNodeToContainerAsync(canvasGuid,nodeGuid); // 装饰器调用
SetProjectLoadingFlag(true);
return result;
}
@@ -374,9 +410,9 @@ namespace Serein.NodeFlow.Env
currentFlowEnvironment.MonitorObjectNotification(nodeGuid, monitorData, sourceType);
}
- public void MoveNode(string nodeGuid, double x, double y)
+ public void MoveNode(string canvasGuid, string nodeGuid, double x, double y)
{
- currentFlowEnvironment.MoveNode(nodeGuid, x, y);
+ currentFlowEnvironment.MoveNode(canvasGuid, nodeGuid, x, y);
}
public void NodeLocated(string nodeGuid)
@@ -408,9 +444,9 @@ namespace Serein.NodeFlow.Env
///
///
///
- public async Task RemoveConnectInvokeAsync(string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType)
+ public async Task RemoveConnectInvokeAsync(string canvasGuid, string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType)
{
- return await currentFlowEnvironment.RemoveConnectInvokeAsync(fromNodeGuid, toNodeGuid, connectionType);
+ return await currentFlowEnvironment.RemoveConnectInvokeAsync(canvasGuid, fromNodeGuid, toNodeGuid, connectionType);
}
///
@@ -420,14 +456,14 @@ namespace Serein.NodeFlow.Env
/// 目标节点Guid
/// 连接到第几个参数
/// 参数来源类型
- public async Task RemoveConnectArgSourceAsync(string fromNodeGuid, string toNodeGuid, int argIndex)
+ public async Task RemoveConnectArgSourceAsync(string canvasGuid, string fromNodeGuid, string toNodeGuid, int argIndex)
{
- return await currentFlowEnvironment.RemoveConnectArgSourceAsync(fromNodeGuid, toNodeGuid, argIndex);
+ return await currentFlowEnvironment.RemoveConnectArgSourceAsync(canvasGuid, fromNodeGuid, toNodeGuid, argIndex);
}
- public async Task RemoveNodeAsync(string nodeGuid)
+ public async Task RemoveNodeAsync(string canvasGuid, string nodeGuid)
{
- return await currentFlowEnvironment.RemoveNodeAsync(nodeGuid);
+ return await currentFlowEnvironment.RemoveNodeAsync(canvasGuid, nodeGuid);
}
@@ -477,9 +513,9 @@ namespace Serein.NodeFlow.Env
#endif
#endregion
- public async Task SetStartNodeAsync(string nodeGuid)
+ public async Task SetStartNodeAsync(string canvasGuid, string nodeGuid)
{
- return await currentFlowEnvironment.SetStartNodeAsync(nodeGuid);
+ return await currentFlowEnvironment.SetStartNodeAsync(canvasGuid, nodeGuid);
}
public async Task StartFlowAsync()
diff --git a/NodeFlow/Env/MsgControllerOfClient.cs b/NodeFlow/Env/MsgControllerOfClient.cs
index 8943f43..767cd8c 100644
--- a/NodeFlow/Env/MsgControllerOfClient.cs
+++ b/NodeFlow/Env/MsgControllerOfClient.cs
@@ -132,7 +132,6 @@ namespace Serein.NodeFlow.Env
-
///
/// 从某个节点开始运行
///
@@ -164,6 +163,18 @@ namespace Serein.NodeFlow.Env
_ = remoteFlowEnvironment.InvokeTriggerAsync
///
///
- public async Task RemoveNodeAsync(string nodeGuid)
+ public async Task RemoveNodeAsync(string canvasGuid, string nodeGuid)
{
var result = await msgClient.SendAndWaitDataAsync(EnvMsgTheme.RemoveNode, new
{
@@ -879,7 +954,7 @@ namespace Serein.NodeFlow.Env
{
UIContextOperation.Invoke(() =>
{
- OnNodeRemove?.Invoke(new NodeRemoveEventArgs(nodeGuid));
+ OnNodeRemove?.Invoke(new NodeRemoveEventArgs(canvasGuid, nodeGuid));
});
}
else
@@ -1077,6 +1152,7 @@ namespace Serein.NodeFlow.Env
#region 从NodeInfo创建NodeModel
foreach (NodeInfo? nodeInfo in nodeInfos)
{
+ var canvasGuid = nodeInfo.CanvasGuid;
if (!EnumHelper.TryConvertEnum(nodeInfo.Type, out var controlType))
{
continue;
@@ -1108,7 +1184,7 @@ namespace Serein.NodeFlow.Env
TryAddNode(nodeModel); // 加载项目时将节点加载到环境中
UIContextOperation?.Invoke(() =>
- OnNodeCreate?.Invoke(new NodeCreateEventArgs(nodeModel, nodeInfo.Position))); // 添加到UI上
+ OnNodeCreate?.Invoke(new NodeCreateEventArgs(canvasGuid, nodeModel, nodeInfo.Position))); // 添加到UI上
}
#endregion
@@ -1127,10 +1203,11 @@ namespace Serein.NodeFlow.Env
if (NodeModels.TryGetValue(nodeInfo.Guid, out var childNode) &&
NodeModels.TryGetValue(nodeInfo.ParentNodeGuid, out var parentNode))
{
+ var canvasGuid = nodeInfo.CanvasGuid;
childNode.ContainerNode = parentNode;
parentNode.ChildrenNode.Add(childNode);
UIContextOperation?.Invoke(() =>
- OnNodePlace?.Invoke(new NodePlaceEventArgs(nodeInfo.Guid, nodeInfo.ParentNodeGuid)) // 通知UI更改节点放置位置
+ OnNodePlace?.Invoke(new NodePlaceEventArgs(canvasGuid,nodeInfo.Guid, nodeInfo.ParentNodeGuid)) // 通知UI更改节点放置位置
);
}
@@ -1148,6 +1225,7 @@ namespace Serein.NodeFlow.Env
// 不存在对应的起始节点
continue;
}
+ var canvasGuid = nodeInfo.CanvasGuid;
List<(ConnectionInvokeType connectionType, string[] guids)> allToNodes = [(ConnectionInvokeType.IsSucceed,nodeInfo.TrueNodes),
(ConnectionInvokeType.IsFail, nodeInfo.FalseNodes),
(ConnectionInvokeType.IsError, nodeInfo.ErrorNodes),
@@ -1164,7 +1242,8 @@ namespace Serein.NodeFlow.Env
// 遍历当前类型分支的节点(确认连接关系)
foreach (var toNode in item.toNodes)
{
- UIContextOperation?.Invoke(() => OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNode.Guid,
+ UIContextOperation?.Invoke(() => OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(canvasGuid,
+ fromNode.Guid,
toNode.Guid,
JunctionOfConnectionType.Invoke,
item.connectionType,
@@ -1187,10 +1266,11 @@ namespace Serein.NodeFlow.Env
if (!string.IsNullOrEmpty(pd.ArgDataSourceNodeGuid)
&& NodeModels.TryGetValue(pd.ArgDataSourceNodeGuid, out var fromNode))
{
-
+ var canvasGuid = toNode.CanvasGuid;
UIContextOperation?.Invoke(() =>
OnNodeConnectChange?.Invoke(
new NodeConnectChangeEventArgs(
+ canvasGuid,
fromNode.Guid, // 从哪个节点开始
toNode.Guid, // 连接到那个节点
JunctionOfConnectionType.Arg,
diff --git a/NodeFlow/Model/SingleGlobalDataNode.cs b/NodeFlow/Model/SingleGlobalDataNode.cs
index aff7795..be3a5ba 100644
--- a/NodeFlow/Model/SingleGlobalDataNode.cs
+++ b/NodeFlow/Model/SingleGlobalDataNode.cs
@@ -96,7 +96,7 @@ namespace Serein.NodeFlow.Model
{
foreach (var nodeModel in ChildrenNode)
{
- await nodeModel.Env.TakeOutNodeToContainerAsync(nodeModel.Guid);
+ await nodeModel.Env.TakeOutNodeToContainerAsync(nodeModel.CanvasGuid, nodeModel.Guid);
}
DataNode = null;
}
@@ -174,8 +174,11 @@ namespace Serein.NodeFlow.Model
///
public override void Remove()
{
+ if (DataNode is null) {
+ return;
+ }
// 移除数据节点
- _ = this.Env.RemoveNodeAsync(DataNode?.Guid);
+ _ = this.Env.RemoveNodeAsync(DataNode.CanvasGuid, DataNode.Guid);
}
}
diff --git a/Workbench/App.xaml b/Workbench/App.xaml
index 44bc631..99644e4 100644
--- a/Workbench/App.xaml
+++ b/Workbench/App.xaml
@@ -3,9 +3,10 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Serein.Workbench"
xmlns:view="clr-namespace:Serein.Workbench.Views"
- StartupUri="MainWindow.xaml"
+ StartupUri="Views/FlowWorkbenchView.xaml"
Startup="Application_Startup">
+
diff --git a/Workbench/App.xaml.cs b/Workbench/App.xaml.cs
index 2b6f435..44d9b68 100644
--- a/Workbench/App.xaml.cs
+++ b/Workbench/App.xaml.cs
@@ -39,7 +39,7 @@ namespace Serein.Workbench
{
collection.AddSingleton(); // 流程事件管理
collection.AddSingleton(); // 流程事件管理
- collection.AddSingleton(); // 节点操作管理
+ collection.AddSingleton(); // 节点操作管理
// collection.AddSingleton(); // 按键事件管理
//collection.AddSingleton(); // 流程节点控件管理
}
@@ -90,19 +90,20 @@ namespace Serein.Workbench
public App()
{
- _ = Task.Run(async () =>
- {
- await Task.Delay(500);
- await this.LoadLocalProjectAsync();
- });
- return;
+
var collection = new ServiceCollection();
collection.AddWorkbenchServices();
collection.AddFlowServices();
collection.AddViewModelServices();
var services = collection.BuildServiceProvider(); // 绑定并返回获取实例的服务接口
App.ServiceProvider = services;
-
+ _ = Task.Run(async () =>
+ {
+ await Task.Delay(500);
+ await this.LoadLocalProjectAsync();
+ App.GetService().LoadProject(new FlowEnvInfo { Project = App.FlowProjectData }, App.FileDataPath);
+
+ });
}
@@ -124,7 +125,6 @@ namespace Serein.Workbench
App.FileDataPath = System.IO.Path.GetDirectoryName(filePath)!; // filePath;//
var dir = Path.GetDirectoryName(filePath);
- //App.GetService().LoadProject(new FlowEnvInfo { Project = App.FlowProjectData },App.FileDataPath);
}
#endif
}
diff --git a/Workbench/MainWindow.xaml.cs b/Workbench/MainWindow.xaml.cs
index 9c63b62..91a0a20 100644
--- a/Workbench/MainWindow.xaml.cs
+++ b/Workbench/MainWindow.xaml.cs
@@ -356,7 +356,7 @@ namespace Serein.Workbench
projectData.Basic = new Basic
{
- Canvas = new FlowCanvas
+ Canvas = new FlowCanvasInfo
{
Height = FlowChartCanvas.Height,
Width = FlowChartCanvas.Width,
@@ -763,9 +763,11 @@ namespace Serein.Workbench
NodeControls.TryAdd(nodeModel.Guid, nodeControl); // 添加到
if (TryPlaceNodeInRegion(nodeControl, position, out var regionControl)) // 判断添加到区域容器
{
+ var canvasGuid = nodeControl.ViewModel.NodeModel.CanvasGuid;
// 通知运行环境调用加载节点子项的方法
- _ = EnvDecorator.PlaceNodeToContainerAsync(nodeControl.ViewModel.NodeModel.Guid, // 待移动的节点
- regionControl.ViewModel.NodeModel.Guid); // 目标的容器节点
+ _ = EnvDecorator.PlaceNodeToContainerAsync(canvasGuid,
+ nodeControl.ViewModel.NodeModel.Guid, // 待移动的节点
+ regionControl.ViewModel.NodeModel.Guid); // 目标的容器节点
}
else
{
@@ -1148,7 +1150,7 @@ namespace Serein.Workbench
///
private void ConfigureContextMenu(NodeControlBase nodeControl)
{
-
+ var canvasGuid = nodeControl.ViewModel.NodeModel.CanvasGuid;
var contextMenu = new ContextMenu();
var nodeGuid = nodeControl.ViewModel?.NodeModel?.Guid;
#region 触发器节点
@@ -1187,10 +1189,10 @@ namespace Serein.Workbench
- contextMenu.Items.Add(CreateMenuItem("设为起点", (s, e) => EnvDecorator.SetStartNodeAsync(nodeGuid)));
+ contextMenu.Items.Add(CreateMenuItem("设为起点", (s, e) => EnvDecorator.SetStartNodeAsync(canvasGuid, nodeGuid)));
contextMenu.Items.Add(CreateMenuItem("删除", async (s, e) =>
{
- var result = await EnvDecorator.RemoveNodeAsync(nodeGuid);
+ var result = await EnvDecorator.RemoveNodeAsync(canvasGuid, nodeGuid);
}));
#region 右键菜单功能 - 控件对齐
@@ -1407,7 +1409,8 @@ namespace Serein.Workbench
{
Task.Run(async () =>
{
- await EnvDecorator.CreateNodeAsync(nodeData.NodeControlType, position, nodeData.MethodDetailsInfo); // 创建DLL文件的节点对象
+
+ await EnvDecorator.CreateNodeAsync("MainCanvas", nodeData.NodeControlType, position, nodeData.MethodDetailsInfo); // 创建DLL文件的节点对象
});
}
}
@@ -1429,7 +1432,7 @@ namespace Serein.Workbench
{
Task.Run(async () =>
{
- await EnvDecorator.CreateNodeAsync(nodeControlType, position); // 创建基础节点对象
+ await EnvDecorator.CreateNodeAsync("MainCanvas", nodeControlType, position); // 创建基础节点对象
});
}
}
@@ -1580,7 +1583,7 @@ namespace Serein.Workbench
var newLeft = oldLeft + deltaX;
var newTop = oldTop + deltaY;
- this.EnvDecorator.MoveNode(nodeControlMain.ViewModel.NodeModel.Guid, newLeft, newTop); // 移动节点
+ this.EnvDecorator.MoveNode("MainCanvas", nodeControlMain.ViewModel.NodeModel.Guid, newLeft, newTop); // 移动节点
// 计算控件实际移动的距离
var actualDeltaX = newLeft - oldLeft;
@@ -1593,7 +1596,7 @@ namespace Serein.Workbench
{
var otherNewLeft = Canvas.GetLeft(nodeControl) + actualDeltaX;
var otherNewTop = Canvas.GetTop(nodeControl) + actualDeltaY;
- this.EnvDecorator.MoveNode(nodeControl.ViewModel.NodeModel.Guid, otherNewLeft, otherNewTop); // 移动节点
+ this.EnvDecorator.MoveNode("MainCanvas", nodeControl.ViewModel.NodeModel.Guid, otherNewLeft, otherNewTop); // 移动节点
}
}
@@ -1613,7 +1616,7 @@ namespace Serein.Workbench
double deltaY = currentPosition.Y - startControlDragPoint.Y; // 计算Y轴方向的偏移量
double newLeft = Canvas.GetLeft(nodeControl) + deltaX; // 新的左边距
double newTop = Canvas.GetTop(nodeControl) + deltaY; // 新的上边距
- this.EnvDecorator.MoveNode(nodeControl.ViewModel.NodeModel.Guid, newLeft, newTop); // 移动节点
+ this.EnvDecorator.MoveNode("MainCanvas", nodeControl.ViewModel.NodeModel.Guid, newLeft, newTop); // 移动节点
nodeControl.UpdateLocationConnections();
}
startControlDragPoint = currentPosition; // 更新起始点位置
@@ -1975,7 +1978,9 @@ namespace Serein.Workbench
#region 方法调用关系创建
if (myData.Type == JunctionOfConnectionType.Invoke)
{
- await EnvDecorator.ConnectInvokeNodeAsync(myData.StartJunction.MyNode.Guid, myData.CurrentJunction.MyNode.Guid,
+ await EnvDecorator.ConnectInvokeNodeAsync(
+ "MainCanvas",
+ myData.StartJunction.MyNode.Guid, myData.CurrentJunction.MyNode.Guid,
myData.StartJunction.JunctionType,
myData.CurrentJunction.JunctionType,
myData.ConnectionInvokeType);
@@ -1995,7 +2000,9 @@ namespace Serein.Workbench
argIndex = argJunction2.ArgIndex;
}
- await EnvDecorator.ConnectArgSourceNodeAsync(myData.StartJunction.MyNode.Guid, myData.CurrentJunction.MyNode.Guid,
+ await EnvDecorator.ConnectArgSourceNodeAsync(
+ "MainCanvas",
+ myData.StartJunction.MyNode.Guid, myData.CurrentJunction.MyNode.Guid,
myData.StartJunction.JunctionType,
myData.CurrentJunction.JunctionType,
myData.ConnectionArgSourceType,
@@ -2060,7 +2067,7 @@ namespace Serein.Workbench
var guid = node?.ViewModel?.NodeModel?.Guid;
if (!string.IsNullOrEmpty(guid))
{
- EnvDecorator.RemoveNodeAsync(guid);
+ EnvDecorator.RemoveNodeAsync("MainCanvas", guid);
}
}
}
diff --git a/Workbench/Models/TabModel.cs b/Workbench/Models/TabModel.cs
new file mode 100644
index 0000000..3f67122
--- /dev/null
+++ b/Workbench/Models/TabModel.cs
@@ -0,0 +1,50 @@
+using CommunityToolkit.Mvvm.ComponentModel;
+using Newtonsoft.Json.Linq;
+using Serein.Workbench.ViewModels;
+using Serein.Workbench.Views;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Text;
+using System.Threading.Tasks;
+using System.Xml.Linq;
+
+namespace Serein.Workbench.Models
+{
+ public partial class FlowCanvasModel : ObservableObject
+ {
+ public string Name
+ {
+ get
+ {
+
+ var vm = (FlowCanvasViewModel)content.DataContext;
+ return vm.Name;
+ }
+ set
+ {
+ var vm = (FlowCanvasViewModel)content.DataContext;
+ vm.Name = value;
+ OnPropertyChanged(nameof(Name));
+ }
+ }
+
+ [ObservableProperty]
+ private bool _isSelected;
+ [ObservableProperty]
+ private bool _isEditing;
+ [ObservableProperty]
+ private FlowCanvasView content;
+
+
+ public FlowCanvasModel()
+ {
+
+ }
+
+ }
+
+
+}
diff --git a/Workbench/Node/View/ConnectionControl.cs b/Workbench/Node/View/ConnectionControl.cs
index e41637d..2d130e2 100644
--- a/Workbench/Node/View/ConnectionControl.cs
+++ b/Workbench/Node/View/ConnectionControl.cs
@@ -237,13 +237,14 @@ namespace Serein.Workbench.Node.View
{
Canvas.Children.Remove(BezierLine);
var env = Start.MyNode.Env;
+ var canvasGuid = Start.MyNode.CanvasGuid;
if (Start.JunctionType.ToConnectyionType() == JunctionOfConnectionType.Invoke)
{
- env.RemoveConnectInvokeAsync(Start.MyNode.Guid, End.MyNode.Guid, InvokeType);
+ env.RemoveConnectInvokeAsync(canvasGuid, Start.MyNode.Guid, End.MyNode.Guid, InvokeType);
}
else if (Start.JunctionType.ToConnectyionType() == JunctionOfConnectionType.Arg)
{
- env.RemoveConnectArgSourceAsync(Start.MyNode.Guid, End.MyNode.Guid, ArgIndex) ;
+ env.RemoveConnectArgSourceAsync(canvasGuid,Start.MyNode.Guid, End.MyNode.Guid, ArgIndex) ;
}
}
diff --git a/Workbench/Services/FlowEEForwardingService.cs b/Workbench/Services/FlowEEForwardingService.cs
index 280c218..697bacc 100644
--- a/Workbench/Services/FlowEEForwardingService.cs
+++ b/Workbench/Services/FlowEEForwardingService.cs
@@ -109,6 +109,14 @@ namespace Serein.Workbench.Services
/// 运行环境输出事件
///
public event EnvOutHandler? OnEnvOut;
+ ///
+ /// 添加画布事件
+ ///
+ public event CanvasCreateHandler OnCanvasCreate;
+ ///
+ /// 移除了画布事件
+ ///
+ public event CanvasRemoveHandler OnCanvasRemove;
#endregion
@@ -119,6 +127,8 @@ namespace Serein.Workbench.Services
flowEnvironmentEvent.OnDllLoad += FlowEnvironment_DllLoadEvent;
flowEnvironmentEvent.OnProjectSaving += EnvDecorator_OnProjectSaving;
flowEnvironmentEvent.OnProjectLoaded += FlowEnvironment_OnProjectLoaded;
+ flowEnvironmentEvent.OnCanvasCreate += FlowEnvironmentEvent_OnCanvasCreate;
+ flowEnvironmentEvent.OnCanvasRemove += FlowEnvironmentEvent_OnCanvasRemove;
flowEnvironmentEvent.OnStartNodeChange += FlowEnvironment_StartNodeChangeEvent;
flowEnvironmentEvent.OnNodeConnectChange += FlowEnvironment_NodeConnectChangeEvemt;
flowEnvironmentEvent.OnNodeCreate += FlowEnvironment_NodeCreateEvent;
@@ -139,6 +149,7 @@ namespace Serein.Workbench.Services
flowEnvironmentEvent.OnEnvOut += FlowEnvironment_OnEnvOutEvent;
}
+
private void ResetFlowEnvironmentEvent()
{
flowEnvironmentEvent.OnDllLoad -= FlowEnvironment_DllLoadEvent;
@@ -224,6 +235,28 @@ namespace Serein.Workbench.Services
OnNodeConnectChange?.Invoke(eventArgs);
}
+
+ ///
+ /// 添加了画布
+ ///
+ ///
+ ///
+ private void FlowEnvironmentEvent_OnCanvasCreate(CanvasCreateEventArgs eventArgs)
+ {
+ OnCanvasCreate?.Invoke(eventArgs);
+ }
+
+ ///
+ /// 移除了画布
+ ///
+ ///
+ ///
+ private void FlowEnvironmentEvent_OnCanvasRemove(CanvasRemoveEventArgs eventArgs)
+ {
+ OnCanvasRemove?.Invoke(eventArgs);
+
+ }
+
///
/// 节点移除事件
///
diff --git a/Workbench/Services/NodeControlService.cs b/Workbench/Services/NodeControlService.cs
new file mode 100644
index 0000000..23064ad
--- /dev/null
+++ b/Workbench/Services/NodeControlService.cs
@@ -0,0 +1,63 @@
+
+using Newtonsoft.Json;
+using Serein.Library;
+using Serein.Library.Api;
+using Serein.Library.Utils;
+using Serein.NodeFlow;
+using Serein.NodeFlow.Env;
+using Serein.Workbench.Api;
+using Serein.Workbench.Avalonia.Api;
+using Serein.Workbench.Node;
+using Serein.Workbench.Node.View;
+using Serein.Workbench.Node.ViewModel;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows.Controls;
+
+
+
+
+
+namespace Serein.Workbench.Api
+{
+
+}
+
+namespace Serein.Workbench.Services
+{
+ ///
+ /// 节点操作相关服务
+ ///
+ internal class NodeControlService
+ {
+
+ public NodeControlService(IFlowEnvironment flowEnvironment,
+ IFlowEEForwardingService feefService)
+ {
+ /* this.flowEnvironment = flowEnvironment;
+ this.feefService = feefService;
+ feefService.OnNodeCreate += FeefService_OnNodeCreate; // 订阅运行环境创建节点事件
+ feefService.OnNodeConnectChange += FeefService_OnNodeConnectChange; // 订阅运行环境连接了节点事件
+ // 手动加载项目
+ _ = Task.Run(async delegate
+ {
+ await Task.Delay(1000);
+ var flowEnvironment = new FlowEnvironment();// App.GetService();
+ var filePath = @"C:\Users\Az\source\repos\CLBanyunqiState\CLBanyunqiState\bin\debug\net8.0\project.dnf";
+ string content = System.IO.File.ReadAllText(filePath); // 读取整个文件内容
+ var projectData = JsonConvert.DeserializeObject(content);
+ var projectDfilePath = System.IO.Path.GetDirectoryName(filePath)!;
+ flowEnvironment.LoadProject(new FlowEnvInfo { Project = projectData }, projectDfilePath);
+ }, CancellationToken.None);*/
+ }
+
+
+
+
+
+ }
+
+}
diff --git a/Workbench/Services/NodeOperationService.cs b/Workbench/Services/NodeOperationService.cs
deleted file mode 100644
index 2a9117f..0000000
--- a/Workbench/Services/NodeOperationService.cs
+++ /dev/null
@@ -1,406 +0,0 @@
-
-using Newtonsoft.Json;
-using Serein.Library;
-using Serein.Library.Api;
-using Serein.Library.Utils;
-using Serein.NodeFlow;
-using Serein.NodeFlow.Env;
-using Serein.Workbench.Api;
-using Serein.Workbench.Avalonia.Api;
-using Serein.Workbench.Node;
-using Serein.Workbench.Node.View;
-using Serein.Workbench.Node.ViewModel;
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Windows.Controls;
-
-
-
-
-
-namespace Serein.Workbench.Api
-{
-
- ///
- /// 提供节点操作的接口
- ///
- internal interface INodeOperationService
- {
- ///
- /// 连接数据
- ///
- // ConnectingManage ConnectingManage { get; }
-
- ///
- /// 主画布
- ///
- Canvas MainCanvas { get; set; }
-
- ///
- /// 节点创建事件
- ///
-
- event NodeViewCreateHandle OnNodeViewCreate;
-
- ///
- /// 创建节点控件
- ///
- /// 控件类型
- /// 创建坐标
- /// 节点方法信息
- public void CreateNodeView(MethodDetailsInfo methodDetailsInfo, PositionOfUI position);
-
- ///
- /// 尝试从连接控制点创建连接
- ///
- ///
- //void TryCreateConnectionOnJunction(NodeJunctionView startJunction);
-
- }
-
-
-
-
- #region 事件与事件参数
- ///
- /// 创建节点控件事件
- ///
- ///
-
- internal delegate bool NodeViewCreateHandle(NodeViewCreateEventArgs eventArgs);
-
- ///
- /// 创建节点控件事件参数
- ///
-
-
-
- internal class NodeViewCreateEventArgs : EventArgs
- {
- internal NodeViewCreateEventArgs(NodeControlBase nodeControl, PositionOfUI position)
- {
- this.NodeControl = nodeControl;
- this.Position = position;
- }
- public NodeControlBase NodeControl { get; private set; }
- public PositionOfUI Position { get; private set; }
- }
-
-
- #endregion
-
-
-
-
-
-}
-
-namespace Serein.Workbench.Services
-{
- ///
- /// 节点操作相关服务
- ///
- internal class NodeOperationService : INodeOperationService
- {
-
- public NodeOperationService(IFlowEnvironment flowEnvironment,
- IFlowEEForwardingService feefService)
- {
- this.flowEnvironment = flowEnvironment;
- this.feefService = feefService;
- feefService.OnNodeCreate += FeefService_OnNodeCreate; // 订阅运行环境创建节点事件
- feefService.OnNodeConnectChange += FeefService_OnNodeConnectChange; // 订阅运行环境连接了节点事件
- // 手动加载项目
- _ = Task.Run(async delegate
- {
- await Task.Delay(1000);
- var flowEnvironment = new FlowEnvironment();// App.GetService();
- var filePath = @"C:\Users\Az\source\repos\CLBanyunqiState\CLBanyunqiState\bin\debug\net8.0\project.dnf";
- string content = System.IO.File.ReadAllText(filePath); // 读取整个文件内容
- var projectData = JsonConvert.DeserializeObject(content);
- var projectDfilePath = System.IO.Path.GetDirectoryName(filePath)!;
- flowEnvironment.LoadProject(new FlowEnvInfo { Project = projectData }, projectDfilePath);
- }, CancellationToken.None);
- }
-
-
- #region 接口属性
- //public ConnectingManage ConnectingManage { get; private set; } = new ConnectingManage();
- public Canvas MainCanvas { get; set; }
-
- #endregion
-
- #region 私有变量
-
- ///
- /// 存储所有与节点有关的控件
- ///
- private Dictionary NodeControls { get; } = [];
-
- ///
- /// 存储所有连接
- ///
- //private List Connections { get; } = [];
-
-
-
- ///
- /// 流程运行环境
- ///
- private readonly IFlowEnvironment flowEnvironment;
-
- ///
- /// 流程运行环境事件转发
- ///
- private readonly IFlowEEForwardingService feefService;
- #endregion
-
- #region 节点操作事件
-
- ///
- /// 创建了节点控件
- ///
- public event NodeViewCreateHandle OnNodeViewCreate;
-
- #endregion
-
- #region 转发事件的处理
-
- ///
- /// 从工作台事件转发器监听节点创建事件
- ///
- ///
- private void FeefService_OnNodeCreate(NodeCreateEventArgs eventArgs)
- {
- var nodeModel = eventArgs.NodeModel;
- if (NodeControls.ContainsKey(nodeModel.Guid))
- {
- SereinEnv.WriteLine(InfoType.WARN, $"OnNodeCreate 事件意外触发,节点Guid重复 - {nodeModel.Guid}");
- return;
- }
- if (!flowEnvironment.NodeMVVMManagement.TryGetType(nodeModel.ControlType, out var nodeMVVM))
- {
- SereinEnv.WriteLine(InfoType.INFO, $"无法创建{nodeModel.ControlType}节点,节点类型尚未注册。");
- return;
- }
- if (nodeMVVM.ControlType == null
- || nodeMVVM.ViewModelType == null)
- {
- SereinEnv.WriteLine(InfoType.INFO, $"无法创建{nodeModel.ControlType}节点,UI类型尚未注册(请通过 NodeMVVMManagement.RegisterUI() 方法进行注册)。");
- return;
- }
-
- var isSuccessful = TryCreateNodeView(nodeMVVM.ControlType, // 控件UI类型
- nodeMVVM.ViewModelType, // 控件VIewModel类型
- nodeModel, // 控件数据实体
- out var nodeControl); // 成功创建后传出的节点控件实体
- if (!isSuccessful || nodeControl is null)
- {
- SereinEnv.WriteLine(InfoType.INFO, $"无法创建{nodeModel.ControlType}节点,节点创建失败。");
- return;
- }
-
-
- var e = new NodeViewCreateEventArgs(nodeControl, eventArgs.Position);
- if (OnNodeViewCreate?.Invoke(e) == true)
- {
- // 成功创建
- NodeControls.TryAdd(nodeModel.Guid, nodeControl); // 缓存起来,通知其它地方拿取这个控件
- }
-
- }
-
-
- ///
- /// 运行环境连接了节点事件
- ///
- ///
- ///
- private void FeefService_OnNodeConnectChange(NodeConnectChangeEventArgs eventArgs)
- {
- string fromNodeGuid = eventArgs.FromNodeGuid;
- string toNodeGuid = eventArgs.ToNodeGuid;
- if (!TryGetControl(fromNodeGuid, out var fromNodeControl)
- || !TryGetControl(toNodeGuid, out var toNodeControl))
- {
- return;
- }
-
-
- if (eventArgs.JunctionOfConnectionType == JunctionOfConnectionType.Invoke)
- {
- ConnectionInvokeType connectionType = eventArgs.ConnectionInvokeType;
- #region 创建/删除节点之间的调用关系
- #region 创建连接
- if (eventArgs.ChangeType == NodeConnectChangeEventArgs.ConnectChangeType.Create) // 添加连接
- {
- if (fromNodeControl is not INodeJunction IFormJunction || toNodeControl is not INodeJunction IToJunction)
- {
- SereinEnv.WriteLine(InfoType.INFO, "非预期的连接");
- return;
- }
- var startJunction = IFormJunction.NextStepJunction;
- var endJunction = IToJunction.ExecuteJunction;
-
- // NodeConnectionLineControl nodeConnectionLineControl = new NodeConnectionLineControl(MainCanvas, startJunction, endJunction);
-
- //startJunction.TransformToVisual(MainCanvas);
-
- //// 添加连接
- //var shape = new ConnectionLineShape(
- // FlowChartCanvas,
- // connectionType,
- // startJunction,
- // endJunction
- //);
-
-
- //NodeConnectionLine nodeConnectionLine = new NodeConnectionLine(MainCanvas, shape);
-
- //if (toNodeControl is FlipflopNodeControl flipflopControl
- // && flipflopControl?.ViewModel?.NodeModel is NodeModelBase nodeModel) // 某个节点连接到了触发器,尝试从全局触发器视图中移除该触发器
- //{
- // NodeTreeViewer.RemoveGlobalFlipFlop(nodeModel); // 从全局触发器树树视图中移除
- //}
-
- //Connections.Add(nodeConnectionLineControl);
- //fromNodeControl.AddConnection(nodeConnectionLineControl);
- //toNodeControl.AddConnection(nodeConnectionLineControl);
- }
- #endregion
-
-
- #region 移除连接
- /* else if (eventArgs.ChangeType == NodeConnectChangeEventArgs.ConnectChangeType.Remove) // 移除连接
- {
- // 需要移除连接
- var removeConnections = Connections.Where(c =>
- c.Start.MyNode.Guid.Equals(fromNodeGuid)
- && c.End.MyNode.Guid.Equals(toNodeGuid)
- && (c.Start.JunctionType.ToConnectyionType() == JunctionOfConnectionType.Invoke
- || c.End.JunctionType.ToConnectyionType() == JunctionOfConnectionType.Invoke))
- .ToList();
-
-
- foreach (var connection in removeConnections)
- {
- Connections.Remove(connection);
- fromNodeControl.RemoveConnection(connection); // 移除连接
- toNodeControl.RemoveConnection(connection); // 移除连接
- if (NodeControls.TryGetValue(connection.End.MyNode.Guid, out var control))
- {
- JudgmentFlipFlopNode(control); // 连接关系变更时判断
- }
- }
- }*/
- #endregion
-
-
- #endregion
- }
-
- }
- #endregion
-
- #region 私有方法
-
- ///
- /// 创建节点控件
- ///
- /// 节点控件视图控件类型
- /// 节点控件ViewModel类型
- /// 节点Model实例
- /// 返回的节点对象
- /// 是否创建成功
- /// 无法创建节点控件
- private bool TryCreateNodeView(Type viewType, Type viewModelType, NodeModelBase nodeModel, out NodeControlBase? nodeView)
- {
- if (string.IsNullOrEmpty(nodeModel.Guid))
- {
- nodeModel.Guid = Guid.NewGuid().ToString();
- }
- var t_ViewModel = Activator.CreateInstance(viewModelType, nodeModel);
- if (t_ViewModel is not NodeControlViewModelBase viewModelBase)
- {
- nodeView = null;
- return false;
- }
- var controlObj = Activator.CreateInstance(viewType);
- if (controlObj is NodeControlBase nodeControl)
- {
- nodeControl.DataContext = viewModelBase;
- nodeView = nodeControl;
- return true;
- }
- else
- {
- nodeView = null;
- return false;
- }
-
- // 在其它地方验证过了,所以注释
- //if ((viewType is null)
- // || viewModelType is null
- // || nodeModel is null)
- //{
- // nodeView = null;
- // return false;
- //}
- //if (typeof(INodeControl).IsSubclassOf(viewType)
- // || typeof(NodeViewModelBase).IsSubclassOf(viewModelType))
- //{
- // nodeView = null;
- // return false;
- //}
- }
-
- private bool TryGetControl(string nodeGuid, out NodeControlBase nodeControl)
- {
- if (string.IsNullOrEmpty(nodeGuid))
- {
- nodeControl = null;
- return false;
- }
- if (!NodeControls.TryGetValue(nodeGuid, out nodeControl))
- {
- nodeControl = null;
- return false;
- }
- if (nodeControl is null)
- {
- return false;
- }
- return true;
- }
-
- #endregion
-
- #region 操作接口对外暴露的接口
-
- ///
- /// 创建节点控件
- ///
- /// 控件类型
- /// 创建坐标
- /// 节点方法信息(基础节点传null)
- public void CreateNodeView(MethodDetailsInfo methodDetailsInfo, PositionOfUI position)
- {
- Task.Run(async () =>
- {
- if (EnumHelper.TryConvertEnum(methodDetailsInfo.NodeType, out var nodeType))
- {
- await flowEnvironment.CreateNodeAsync(nodeType, position, methodDetailsInfo);
- }
- });
- }
-
-
-
-
- #endregion
- }
-
-}
diff --git a/Workbench/Tool/Converters/BoolToVisibilityConverter.cs b/Workbench/Tool/Converters/BoolToVisibilityConverter.cs
new file mode 100644
index 0000000..ab07dc0
--- /dev/null
+++ b/Workbench/Tool/Converters/BoolToVisibilityConverter.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Data;
+using System.Windows;
+
+namespace Serein.Workbench.Tool.Converters
+{
+ public class BoolToVisibilityConverter : IValueConverter
+ {
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ if (value is bool b)
+ {
+ return b ? Visibility.Visible : Visibility.Collapsed;
+ }
+ return Visibility.Collapsed;
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ return value is Visibility v && v == Visibility.Visible;
+ }
+ }
+}
diff --git a/Workbench/ViewModels/FlowCanvasViewModel.cs b/Workbench/ViewModels/FlowCanvasViewModel.cs
index 11058ad..df16e0a 100644
--- a/Workbench/ViewModels/FlowCanvasViewModel.cs
+++ b/Workbench/ViewModels/FlowCanvasViewModel.cs
@@ -9,11 +9,35 @@ namespace Serein.Workbench.ViewModels
{
public partial class FlowCanvasViewModel : ObservableObject
{
-
+ ///
+ /// 正在创建节点方法调用关系
+ ///
[ObservableProperty]
private bool _isConnectionInvokeNode;
+ ///
+ /// 正在创建节点参数连接关系
+ ///
[ObservableProperty]
private bool _isConnectionArgSourceNode;
+
+ ///
+ /// 画布显示名称
+ ///
+ [ObservableProperty]
+ private string _name;
+
+ ///
+ /// 画布ID
+ ///
+ [ObservableProperty]
+ private string _canvasGuid;
+
+
+
+ public FlowCanvasViewModel()
+ {
+
+ }
}
}
diff --git a/Workbench/ViewModels/FlowEditViewModel.cs b/Workbench/ViewModels/FlowEditViewModel.cs
index 40f0cb3..24b0609 100644
--- a/Workbench/ViewModels/FlowEditViewModel.cs
+++ b/Workbench/ViewModels/FlowEditViewModel.cs
@@ -1,9 +1,15 @@
using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.Input;
+using Serein.Workbench.Models;
+using Serein.Workbench.Views;
using System;
using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
+using System.Windows.Input;
namespace Serein.Workbench.ViewModels
{
@@ -12,5 +18,80 @@ namespace Serein.Workbench.ViewModels
///
public partial class FlowEditViewModel : ObservableObject
{
+ public ObservableCollection Tabs { get; set; }
+ public ICommand AddTabCommand { get; set; }
+ public ICommand RemoveTabCommand { get; set; }
+ public ICommand RenameTabCommand { get; set; }
+
+ [ObservableProperty]
+ private FlowCanvasModel _selectedTab;
+
+ private int _addCount = 0;
+
+ public FlowEditViewModel()
+ {
+ Tabs = new ObservableCollection();
+ AddTabCommand = new RelayCommand(AddTab);
+ RemoveTabCommand = new RelayCommand(RemoveTab, CanRemoveTab);
+
+ // 初始化时添加一个默认的Tab
+ AddTab(); // 添加一个默认选项卡
+ }
+
+ private void AddTab()
+ {
+ var flowCanvasView = new FlowCanvasView(); // 创建FlowCanvasView实例
+ Tabs.Add(new FlowCanvasModel { Content = flowCanvasView ,Name = $"New Tab {_addCount++}"});
+ SelectedTab = Tabs[Tabs.Count - 1]; // 选择刚添加的Tab
+ }
+
+ private void RemoveTab()
+ {
+ if (Tabs.Count > 0 && SelectedTab != null)
+ {
+ Tabs.Remove(SelectedTab);
+ SelectedTab = Tabs.Count > 0 ? Tabs[Tabs.Count - 1] : null;
+ }
+ }
+
+ private bool CanRemoveTab()
+ {
+ return SelectedTab != null;
+ }
+
+
+
+ ///
+ /// 进入编辑模式
+ ///
+ ///
+ public void StartEditingTab(FlowCanvasModel tab)
+ {
+ if (tab != null)
+ {
+ tab.IsEditing = true;
+ OnPropertyChanged(nameof(Tabs)); // 刷新Tabs集合,以便更新UI
+ }
+ }
+
+ ///
+ /// 结束编辑,重命名
+ ///
+ ///
+ ///
+ public void EndEditingTab(FlowCanvasModel tab, string newName)
+ {
+ if (tab != null)
+ {
+ tab.IsEditing = false;
+ tab.Name = newName; // 设置新名称
+ OnPropertyChanged(nameof(Tabs)); // 刷新Tabs集合
+ }
+ }
+
+
+
+
+
}
}
diff --git a/Workbench/Views/FlowCanvasView.xaml b/Workbench/Views/FlowCanvasView.xaml
index cd975dc..152f67a 100644
--- a/Workbench/Views/FlowCanvasView.xaml
+++ b/Workbench/Views/FlowCanvasView.xaml
@@ -15,17 +15,14 @@
-
-
-
-
-