mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-03 00:00:49 +08:00
LocalFlowEnvironment文件丢失,需要重写
This commit is contained in:
@@ -260,8 +260,8 @@ namespace Serein.Library.Api
|
|||||||
public NodeConnectChangeEventArgs(string canvasGuid,
|
public NodeConnectChangeEventArgs(string canvasGuid,
|
||||||
string fromNodeGuid,
|
string fromNodeGuid,
|
||||||
string toNodeGuid,
|
string toNodeGuid,
|
||||||
JunctionOfConnectionType junctionOfConnectionType, // 指示需要创建什么类型的连接线
|
|
||||||
int argIndex,
|
int argIndex,
|
||||||
|
JunctionOfConnectionType junctionOfConnectionType, // 指示需要创建什么类型的连接线
|
||||||
ConnectionArgSourceType connectionArgSourceType, // 节点对应的方法入参所需参数来源
|
ConnectionArgSourceType connectionArgSourceType, // 节点对应的方法入参所需参数来源
|
||||||
ConnectChangeType changeType) // 需要创建连接线还是删除连接线
|
ConnectChangeType changeType) // 需要创建连接线还是删除连接线
|
||||||
{
|
{
|
||||||
@@ -296,15 +296,15 @@ namespace Serein.Library.Api
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 指示需要创建什么类型的连接线
|
/// 指示需要创建什么类型的连接线
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public JunctionOfConnectionType JunctionOfConnectionType { get;}
|
public JunctionOfConnectionType JunctionOfConnectionType { get; } = JunctionOfConnectionType.None;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 节点对应的方法入参所需参数来源
|
/// 节点对应的方法入参所需参数来源
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ConnectionArgSourceType ConnectionArgSourceType { get;}
|
public ConnectionArgSourceType ConnectionArgSourceType { get;}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 第几个参数
|
/// 第几个参数
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int ArgIndex { get;}
|
public int ArgIndex { get; } = -1;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -814,7 +814,7 @@ namespace Serein.Library.Api
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 节点视图模型管理类
|
/// 节点视图模型管理类
|
||||||
/// </summary>
|
/// </summary>
|
||||||
NodeMVVMManagement NodeMVVMManagement { get; }
|
NodeMVVMService NodeMVVMManagement { get; }
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 基本接口
|
#region 基本接口
|
||||||
@@ -904,23 +904,17 @@ namespace Serein.Library.Api
|
|||||||
/// <param name="width">宽度</param>
|
/// <param name="width">宽度</param>
|
||||||
/// <param name="height">高度</param>
|
/// <param name="height">高度</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<FlowCanvasDetailsInfo> CreateCanvasAsync(string canvasName, int width , int height);
|
void CreateCanvas(string canvasName, int width , int height);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 删除画布
|
/// 删除画布
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="canvasGuid">画布Guid</param>
|
/// <param name="canvasGuid">画布Guid</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<bool> RemoveCanvasAsync(string canvasGuid);
|
void RemoveCanvas(string canvasGuid);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置流程起点节点
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="canvasGuid">所在画布</param>
|
|
||||||
/// <param name="nodeGuid">尝试设置为起始节点的节点Guid</param>
|
|
||||||
/// <returns>被设置为起始节点的Guid</returns>
|
|
||||||
Task<string> SetStartNodeAsync(string canvasGuid, string nodeGuid);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 在两个节点之间创建连接关系
|
/// 在两个节点之间创建连接关系
|
||||||
@@ -931,7 +925,7 @@ namespace Serein.Library.Api
|
|||||||
/// <param name="fromNodeJunctionType">起始节点控制点</param>
|
/// <param name="fromNodeJunctionType">起始节点控制点</param>
|
||||||
/// <param name="toNodeJunctionType">目标节点控制点</param>
|
/// <param name="toNodeJunctionType">目标节点控制点</param>
|
||||||
/// <param name="invokeType">决定了方法执行后的后继行为</param>
|
/// <param name="invokeType">决定了方法执行后的后继行为</param>
|
||||||
Task<bool> ConnectInvokeNodeAsync(string canvasGuid,
|
void ConnectInvokeNode(string canvasGuid,
|
||||||
string fromNodeGuid,
|
string fromNodeGuid,
|
||||||
string toNodeGuid,
|
string toNodeGuid,
|
||||||
JunctionType fromNodeJunctionType,
|
JunctionType fromNodeJunctionType,
|
||||||
@@ -948,7 +942,7 @@ namespace Serein.Library.Api
|
|||||||
/// <param name="toNodeJunctionType">目标节点控制点</param>
|
/// <param name="toNodeJunctionType">目标节点控制点</param>
|
||||||
/// <param name="argSourceType">决定了方法参数来源</param>
|
/// <param name="argSourceType">决定了方法参数来源</param>
|
||||||
/// <param name="argIndex">设置第几个参数</param>
|
/// <param name="argIndex">设置第几个参数</param>
|
||||||
Task<bool> ConnectArgSourceNodeAsync(string canvasGuid,
|
void ConnectArgSourceNode(string canvasGuid,
|
||||||
string fromNodeGuid,
|
string fromNodeGuid,
|
||||||
string toNodeGuid,
|
string toNodeGuid,
|
||||||
JunctionType fromNodeJunctionType,
|
JunctionType fromNodeJunctionType,
|
||||||
@@ -956,6 +950,23 @@ namespace Serein.Library.Api
|
|||||||
ConnectionArgSourceType argSourceType,
|
ConnectionArgSourceType argSourceType,
|
||||||
int argIndex);
|
int argIndex);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 移除两个节点之间的方法调用关系
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="canvasGuid">所在画布</param>
|
||||||
|
/// <param name="fromNodeGuid">起始节点</param>
|
||||||
|
/// <param name="toNodeGuid">目标节点</param>
|
||||||
|
/// <param name="connectionType">连接类型</param>
|
||||||
|
void RemoveInvokeConnect(string canvasGuid, string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 移除连接节点之间参数传递的关系
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="canvasGuid">所在画布</param>
|
||||||
|
/// <param name="fromNodeGuid">起始节点Guid</param>
|
||||||
|
/// <param name="toNodeGuid">目标节点Guid</param>
|
||||||
|
/// <param name="argIndex">连接到第几个参数</param>
|
||||||
|
void RemoveArgSourceConnect(string canvasGuid, string fromNodeGuid, string toNodeGuid, int argIndex);
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -965,8 +976,14 @@ namespace Serein.Library.Api
|
|||||||
/// <param name="nodeType">控件类型</param>
|
/// <param name="nodeType">控件类型</param>
|
||||||
/// <param name="position">节点在画布上的位置(</param>
|
/// <param name="position">节点在画布上的位置(</param>
|
||||||
/// <param name="methodDetailsInfo">节点绑定的方法说明</param>
|
/// <param name="methodDetailsInfo">节点绑定的方法说明</param>
|
||||||
Task<NodeInfo> CreateNodeAsync(string canvasGuid, NodeControlType nodeType, PositionOfUI position, MethodDetailsInfo methodDetailsInfo = null);
|
void CreateNode(string canvasGuid, NodeControlType nodeType, PositionOfUI position, MethodDetailsInfo methodDetailsInfo = null);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 移除节点
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="canvasGuid">所在画布</param>
|
||||||
|
/// <param name="nodeGuid">待移除的节点Guid</param>
|
||||||
|
void RemoveNode(string canvasGuid, string nodeGuid);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 将节点放置在容器中
|
/// 将节点放置在容器中
|
||||||
@@ -975,15 +992,22 @@ namespace Serein.Library.Api
|
|||||||
/// <param name="nodeGuid">需要放置的节点Guid</param>
|
/// <param name="nodeGuid">需要放置的节点Guid</param>
|
||||||
/// <param name="containerNodeGuid">存放节点的容器Guid</param>
|
/// <param name="containerNodeGuid">存放节点的容器Guid</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<bool> PlaceNodeToContainerAsync(string canvasGuid, string nodeGuid, string containerNodeGuid);
|
void PlaceNodeToContainer(string canvasGuid, string nodeGuid, string containerNodeGuid);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 将节点放置在容器中
|
/// 将节点放置在容器中
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="canvasGuid">所在画布</param>
|
/// <param name="canvasGuid">所在画布</param>
|
||||||
/// <param name="nodeGuid">需要取出的节点Guid</param>
|
/// <param name="nodeGuid">需要取出的节点Guid</param>
|
||||||
Task<bool> TakeOutNodeToContainerAsync(string canvasGuid, string nodeGuid);
|
void TakeOutNodeToContainer(string canvasGuid, string nodeGuid);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置流程起点节点
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="canvasGuid">所在画布</param>
|
||||||
|
/// <param name="nodeGuid">尝试设置为起始节点的节点Guid</param>
|
||||||
|
/// <returns>被设置为起始节点的Guid</returns>
|
||||||
|
void SetStartNode(string canvasGuid, string nodeGuid);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 设置两个节点某个类型的方法调用关系为优先调用
|
/// 设置两个节点某个类型的方法调用关系为优先调用
|
||||||
@@ -992,32 +1016,8 @@ namespace Serein.Library.Api
|
|||||||
/// <param name="toNodeGuid">目标节点</param>
|
/// <param name="toNodeGuid">目标节点</param>
|
||||||
/// <param name="connectionType">连接关系</param>
|
/// <param name="connectionType">连接关系</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<bool> SetConnectPriorityInvoke(string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType);
|
void SetConnectPriorityInvoke(string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 移除两个节点之间的方法调用关系
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="canvasGuid">所在画布</param>
|
|
||||||
/// <param name="fromNodeGuid">起始节点</param>
|
|
||||||
/// <param name="toNodeGuid">目标节点</param>
|
|
||||||
/// <param name="connectionType">连接类型</param>
|
|
||||||
Task<bool> RemoveConnectInvokeAsync(string canvasGuid, string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 移除连接节点之间参数传递的关系
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="canvasGuid">所在画布</param>
|
|
||||||
/// <param name="fromNodeGuid">起始节点Guid</param>
|
|
||||||
/// <param name="toNodeGuid">目标节点Guid</param>
|
|
||||||
/// <param name="argIndex">连接到第几个参数</param>
|
|
||||||
Task<bool> RemoveConnectArgSourceAsync(string canvasGuid, string fromNodeGuid, string toNodeGuid, int argIndex);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 移除节点/区域/基础控件
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="canvasGuid">所在画布</param>
|
|
||||||
/// <param name="nodeGuid">待移除的节点Guid</param>
|
|
||||||
Task<bool> RemoveNodeAsync(string canvasGuid, string nodeGuid);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 改变可选参数的数目
|
/// 改变可选参数的数目
|
||||||
@@ -1026,8 +1026,7 @@ namespace Serein.Library.Api
|
|||||||
/// <param name="isAdd">true,增加参数;false,减少参数</param>
|
/// <param name="isAdd">true,增加参数;false,减少参数</param>
|
||||||
/// <param name="paramIndex">以哪个参数为模板进行拷贝,或删去某个参数(该参数必须为可选参数)</param>
|
/// <param name="paramIndex">以哪个参数为模板进行拷贝,或删去某个参数(该参数必须为可选参数)</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<bool> ChangeParameter(string nodeGuid, bool isAdd, int paramIndex);
|
void ChangeParameter(string nodeGuid, bool isAdd, int paramIndex);
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@@ -1114,6 +1113,7 @@ namespace Serein.Library.Api
|
|||||||
/// <para>需要你提供一个由你实现的ISereinIOC接口实现类</para>
|
/// <para>需要你提供一个由你实现的ISereinIOC接口实现类</para>
|
||||||
/// <para>当你将流程运行环境集成在你的项目时,并希望流程运行时使用你提供的对象,而非自动创建</para>
|
/// <para>当你将流程运行环境集成在你的项目时,并希望流程运行时使用你提供的对象,而非自动创建</para>
|
||||||
/// <para>就需要你调用这个方法,用来替换运行环境的IOC容器</para>
|
/// <para>就需要你调用这个方法,用来替换运行环境的IOC容器</para>
|
||||||
|
/// <para>注意,是流程运行时,而非运行环境</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="ioc"></param>
|
/// <param name="ioc"></param>
|
||||||
void UseExternalIOC(ISereinIOC ioc);
|
void UseExternalIOC(ISereinIOC ioc);
|
||||||
|
|||||||
@@ -72,14 +72,19 @@ namespace Serein.Library.Api
|
|||||||
MethodDetails MethodDetails { get; set; }
|
MethodDetails MethodDetails { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 父节点
|
/// 父节点集合
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Dictionary<ConnectionInvokeType, List<IFlowNode>> PreviousNodes { get;}
|
Dictionary<ConnectionInvokeType, List<IFlowNode>> PreviousNodes { get;}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 子节点
|
/// 子节点集合
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Dictionary<ConnectionInvokeType, List<IFlowNode>> SuccessorNodes { get; set; }
|
Dictionary<ConnectionInvokeType, List<IFlowNode>> SuccessorNodes { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 需要该节点返回结果作为入参参数的节点集合
|
||||||
|
/// </summary>
|
||||||
|
Dictionary<ConnectionArgSourceType, List<IFlowNode>> NeedResultNodes { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 当该节点放置在某个具有容器行为的节点时,该值指示其容器节点
|
/// 当该节点放置在某个具有容器行为的节点时,该值指示其容器节点
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -94,10 +99,10 @@ namespace Serein.Library.Api
|
|||||||
/// 节点创建时的行为
|
/// 节点创建时的行为
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void OnCreating();
|
void OnCreating();
|
||||||
/// <summary>
|
/*/// <summary>
|
||||||
/// 节点移除时的行为
|
/// 节点移除时的行为
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void Remove();
|
void Remove();*/
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 节点保存时如若需要保存自定义数据,可通过该方法进行控制保存逻辑
|
/// 节点保存时如若需要保存自定义数据,可通过该方法进行控制保存逻辑
|
||||||
|
|||||||
@@ -18,14 +18,14 @@ namespace Serein.Library.Api
|
|||||||
ISereinIOC Reset();
|
ISereinIOC Reset();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 通过指定类型的方式注册实例
|
/// 通过指定类型的方式注册实例,该类型的实例由你提供
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="type">实例类型</param>
|
/// <param name="type">实例类型</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
ISereinIOC Register(Type type);
|
ISereinIOC Register(Type type);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 通过指定类型的方式注册实例
|
/// 通过指定类型的方式注册实例,该类型将由IOC容器自动创建
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="type">实例类型</param>
|
/// <param name="type">实例类型</param>
|
||||||
/// <param name="getInstance">获取实例的回调函数</param>
|
/// <param name="getInstance">获取实例的回调函数</param>
|
||||||
@@ -33,14 +33,14 @@ namespace Serein.Library.Api
|
|||||||
ISereinIOC Register(Type type, Func<object> getInstance);
|
ISereinIOC Register(Type type, Func<object> getInstance);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 通过泛型的方式注册实例
|
/// 通过泛型的方式注册类型,该类型将由IOC容器自动创建
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">实例类型</typeparam>
|
/// <typeparam name="T">实例类型</typeparam>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
ISereinIOC Register<T>();
|
ISereinIOC Register<T>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 通过泛型的方式注册实例
|
/// 通过泛型的方式注册类型,该类型的实例由你提供
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">实例类型</typeparam>
|
/// <typeparam name="T">实例类型</typeparam>
|
||||||
/// <param name="getInstance">获取实例的回调函数</param>
|
/// <param name="getInstance">获取实例的回调函数</param>
|
||||||
@@ -48,7 +48,7 @@ namespace Serein.Library.Api
|
|||||||
ISereinIOC Register<T>(Func<T> getInstance);
|
ISereinIOC Register<T>(Func<T> getInstance);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 注册接口的实例
|
/// 注册接口的实例,该接口类型的实现类实例由你提供
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TService">接口类型</typeparam>
|
/// <typeparam name="TService">接口类型</typeparam>
|
||||||
/// <typeparam name="TImplementation">实例类型</typeparam>
|
/// <typeparam name="TImplementation">实例类型</typeparam>
|
||||||
@@ -78,13 +78,21 @@ namespace Serein.Library.Api
|
|||||||
/// <para>给定一个类型,由IOC容器负责创建实例,如果存在多个构造函数,将由参数最多的构造函数开始尝试创建。</para>
|
/// <para>给定一个类型,由IOC容器负责创建实例,如果存在多个构造函数,将由参数最多的构造函数开始尝试创建。</para>
|
||||||
/// <para></para>
|
/// <para></para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
object CreateTempObject(Type type);
|
object CreateObject(Type type);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>给定一个类型,由IOC容器负责创建实例,如果存在多个构造函数,将由参数最多的构造函数开始尝试创建。</para>
|
/// <para>给定一个类型,由IOC容器负责创建实例,如果存在多个构造函数,将由参数最多的构造函数开始尝试创建。</para>
|
||||||
/// <para></para>
|
/// <para></para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
T CreateTempObject<T>();
|
T CreateObject<T>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 给定一个实例,尽可能地在该实例中具有[AutoInjection]特性的属性上,设置为IOC容器中已有的对应类型的对象。
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">对应的类型</typeparam>
|
||||||
|
/// <param name="instance">传入的实例</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
T InjectDependenciesProperty<T>(T instance);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 搜寻已注册的类型生成依赖关系,依次实例化并注入依赖项,缓存在由IOC容器维护的Map中,直到手动调用Reset()方法。
|
/// 搜寻已注册的类型生成依赖关系,依次实例化并注入依赖项,缓存在由IOC容器维护的Map中,直到手动调用Reset()方法。
|
||||||
|
|||||||
@@ -103,51 +103,101 @@ namespace Serein.Library
|
|||||||
/// 新增可变参数
|
/// 新增可变参数
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="index"></param>
|
/// <param name="index"></param>
|
||||||
public bool AddParamsArg(int index = 0)
|
public bool AddParamsArg(int index)
|
||||||
{
|
{
|
||||||
if (ParamsArgIndex >= 0 // 方法是否包含可变参数
|
if (ParamsArgIndex < 0 // 方法是否包含可变参数
|
||||||
&& index >= 0 // 如果包含,则判断从哪个参数赋值
|
|| index < 0 // 如果包含,则判断从哪个参数赋值
|
||||||
&& index >= ParamsArgIndex // 需要判断是否为可选参数的部分
|
|| index < ParamsArgIndex // 需要判断是否为可选参数的部分
|
||||||
&& index < ParameterDetailss.Length) // 防止下标越界
|
|| index >= ParameterDetailss.Length) // 防止下标越界
|
||||||
{
|
|
||||||
var newPd = ParameterDetailss[index].CloneOfModel(this.NodeModel); // 复制出属于本身节点的参数描述
|
|
||||||
newPd.Index = ParameterDetailss.Length; // 更新索引
|
|
||||||
newPd.IsParams = true;
|
|
||||||
ParameterDetailss = ArrayHelper.AddToArray(ParameterDetailss, newPd); // 新增
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var newPd = ParameterDetailss[index].CloneOfModel(this.NodeModel); // 复制出属于本身节点的参数描述
|
||||||
|
newPd.Index = ParameterDetailss.Length; // 更新索引
|
||||||
|
newPd.IsParams = true;
|
||||||
|
ParameterDetailss = ArrayHelper.AddToArray(ParameterDetailss, newPd); // 新增
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public bool AddParamsArg(ParameterDetails parameterDetails)
|
||||||
|
{
|
||||||
|
if (ParamsArgIndex < 0) // 方法是否包含可变参数
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (parameterDetails is null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
parameterDetails.Index = ParameterDetailss.Length; // 更新索引
|
||||||
|
parameterDetails.IsParams = true;
|
||||||
|
ParameterDetailss = ArrayHelper.AddToArray(ParameterDetailss, parameterDetails); // 新增
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 移除可变参数
|
/// 移除可变参数
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="index"></param>
|
/// <param name="index"></param>
|
||||||
public bool RemoveParamsArg(int index = 0)
|
public bool RemoveParamsArg(int index)
|
||||||
{
|
{
|
||||||
if (ParamsArgIndex >= 0 // 方法是否包含可变参数
|
|
||||||
&& index >= 0 // 如果包含,则判断从哪个参数赋值
|
|
||||||
&& index > ParamsArgIndex // 需要判断是否为可选参数的部分,并且不能删除原始的可变参数描述
|
|
||||||
&& index < ParameterDetailss.Length) // 防止下标越界
|
|
||||||
{
|
|
||||||
ParameterDetailss[index] = null; // 释放对象引用
|
|
||||||
|
|
||||||
|
if (ParamsArgIndex < 0 // 方法是否包含可变参数
|
||||||
|
|| index < 0 // 如果包含,则判断从哪个参数赋值
|
||||||
var tmp = ArrayHelper.RemoteToArray<ParameterDetails>(ParameterDetailss, index); // 新增;
|
|| index <= ParamsArgIndex // 需要判断是否为可选参数的部分,并且不能删除原始的可变参数描述
|
||||||
UpdateParamIndex(ref tmp);
|
|| index >= ParameterDetailss.Length) // 防止下标越界
|
||||||
ParameterDetailss = tmp; // 新增
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ParameterDetailss[index] = null; // 释放对象引用
|
||||||
|
var tmp = ArrayHelper.RemoteToArray<ParameterDetails>(ParameterDetailss, index); // 新增;
|
||||||
|
UpdateParamIndex(ref tmp);
|
||||||
|
ParameterDetailss = tmp; // 新增
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 移除可变参数
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="parameterDetails"></param>
|
||||||
|
public bool RemoveParamsArg(ParameterDetails parameterDetails)
|
||||||
|
{
|
||||||
|
if (ParamsArgIndex < 0) // 方法是否包含可变参数
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (parameterDetails is null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int index = -1;
|
||||||
|
for (int i = 0; i < ParameterDetailss.Length; i++)
|
||||||
|
{
|
||||||
|
var pd = ParameterDetailss[i];
|
||||||
|
if (pd.Equals(parameterDetails))
|
||||||
|
{
|
||||||
|
index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (index == -1)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ParameterDetailss[index] = null; // 释放对象引用
|
||||||
|
var tmp = ArrayHelper.RemoteToArray<ParameterDetails>(ParameterDetailss, index); // 新增;
|
||||||
|
UpdateParamIndex(ref tmp);
|
||||||
|
ParameterDetailss = tmp; // 新增
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 更新参数的索引
|
/// 更新参数的索引
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ namespace Serein.Library
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 节点 数据、视图、VM 管理
|
/// 节点 数据、视图、VM 管理
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class NodeMVVMManagement
|
public class NodeMVVMService
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 节点对应的控件类型
|
/// 节点对应的控件类型
|
||||||
@@ -246,7 +246,7 @@ namespace Serein.Library
|
|||||||
var type = EnumHelper.GetBoundValue(ExplicitType, resultEnum, attr => attr.Value);
|
var type = EnumHelper.GetBoundValue(ExplicitType, resultEnum, attr => attr.Value);
|
||||||
if (type is Type enumBindType && !(enumBindType is null))
|
if (type is Type enumBindType && !(enumBindType is null))
|
||||||
{
|
{
|
||||||
var value = nodeModel.Env.IOC.CreateTempObject(enumBindType);
|
var value = nodeModel.Env.IOC.CreateObject(enumBindType);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ namespace Serein.Library.Web
|
|||||||
return false; // 没有对应的处理配置
|
return false; // 没有对应的处理配置
|
||||||
}
|
}
|
||||||
|
|
||||||
ControllerBase controllerInstance = (ControllerBase)SereinIOC.CreateTempObject(controllerType);
|
ControllerBase controllerInstance = (ControllerBase)SereinIOC.CreateObject(controllerType);
|
||||||
|
|
||||||
if (controllerInstance is null)
|
if (controllerInstance is null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace Serein.Library
|
|||||||
/// <para>这种情况会导致流程启动时,IOC容器无法注入构造函数并创建类型,导致启动失败。</para>
|
/// <para>这种情况会导致流程启动时,IOC容器无法注入构造函数并创建类型,导致启动失败。</para>
|
||||||
/// <para>解决方法:从ServiceA类的构造函数中移除ServiceB类型的入参,将该类型更改为公开可见的可写属性成员ServiceB serviceB{get;set;},并在该属性上标记[AutoInjection]特性</para>
|
/// <para>解决方法:从ServiceA类的构造函数中移除ServiceB类型的入参,将该类型更改为公开可见的可写属性成员ServiceB serviceB{get;set;},并在该属性上标记[AutoInjection]特性</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[AttributeUsage(AttributeTargets.Property)]
|
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
|
||||||
public sealed class AutoInjectionAttribute : Attribute
|
public sealed class AutoInjectionAttribute : Attribute
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,10 +21,19 @@ namespace Serein.Library
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly ConnectionInvokeType[] ConnectionTypes = new ConnectionInvokeType[]
|
public static readonly ConnectionInvokeType[] ConnectionTypes = new ConnectionInvokeType[]
|
||||||
{
|
{
|
||||||
ConnectionInvokeType.Upstream,
|
ConnectionInvokeType.Upstream,
|
||||||
ConnectionInvokeType.IsSucceed,
|
ConnectionInvokeType.IsSucceed,
|
||||||
ConnectionInvokeType.IsFail,
|
ConnectionInvokeType.IsFail,
|
||||||
ConnectionInvokeType.IsError,
|
ConnectionInvokeType.IsError,
|
||||||
};
|
};
|
||||||
|
/// <summary>
|
||||||
|
/// 节点连接关系种类
|
||||||
|
/// </summary>
|
||||||
|
public static readonly ConnectionArgSourceType[] ConnectionArgSourceTypes = new ConnectionArgSourceType[]
|
||||||
|
{
|
||||||
|
ConnectionArgSourceType.GetPreviousNodeData,
|
||||||
|
ConnectionArgSourceType.GetOtherNodeData,
|
||||||
|
ConnectionArgSourceType.GetOtherNodeDataOfInvoke,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using System;
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Diagnostics.Contracts;
|
using System.Diagnostics.Contracts;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@@ -122,7 +123,8 @@ namespace Serein.Library
|
|||||||
/// <param name="class">级别</param>
|
/// <param name="class">级别</param>
|
||||||
public static void WriteLine(InfoType type, string message, InfoClass @class = InfoClass.General)
|
public static void WriteLine(InfoType type, string message, InfoClass @class = InfoClass.General)
|
||||||
{
|
{
|
||||||
SereinEnv.environment.WriteLine(type,message,@class);
|
Debug.WriteLine($"{type} : {message}");
|
||||||
|
SereinEnv.environment?.WriteLine(type,message,@class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -137,13 +137,13 @@ namespace Serein.Library.Utils
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 示例的获取
|
#region 示例的创建
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 用于临时实例的创建,不登记到IOC容器中,依赖项注入失败时也不记录。
|
/// 用于临时实例的创建,不登记到IOC容器中,依赖项注入失败时也不记录。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="type"></param>
|
/// <param name="type"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public object CreateTempObject(Type type)
|
public object CreateObject(Type type)
|
||||||
{
|
{
|
||||||
var ctors = GetConstructor(type); // 获取构造函数
|
var ctors = GetConstructor(type); // 获取构造函数
|
||||||
object instance = null;
|
object instance = null;
|
||||||
@@ -180,10 +180,55 @@ namespace Serein.Library.Utils
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T"></typeparam>
|
/// <typeparam name="T"></typeparam>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public T CreateTempObject<T>()
|
public T CreateObject<T>()
|
||||||
{
|
{
|
||||||
return (T)CreateTempObject(typeof(T));
|
return (T)CreateObject(typeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 给定一个实例,尽可能地在该实例中具有[AutoInjection]特性的属性/字段上,设置为IOC容器中已有的对应类型的对象。
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="instance"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public T InjectDependenciesProperty<T>(T instance)
|
||||||
|
{
|
||||||
|
var type = instance.GetType();
|
||||||
|
var properties = type.GetType()
|
||||||
|
.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).ToArray()
|
||||||
|
.Where(p => p.CanWrite // 可写属性
|
||||||
|
&& p.GetCustomAttribute<AutoInjectionAttribute>() != null // 有特性标注需要注入
|
||||||
|
&& p.GetValue(instance) == null); // 属性为空
|
||||||
|
|
||||||
|
// 属性注入
|
||||||
|
foreach (var property in properties)
|
||||||
|
{
|
||||||
|
var propertyType = property.PropertyType;
|
||||||
|
if (_dependencies.TryGetValue(propertyType.FullName, out var dependencyInstance))
|
||||||
|
{
|
||||||
|
property.SetValue(instance, dependencyInstance); // 尝试写入到目标实例的属性中
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 字段注入
|
||||||
|
var fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic )
|
||||||
|
.Where(f => f.GetCustomAttribute<AutoInjectionAttribute>() != null
|
||||||
|
&& f.GetValue(instance) == null);
|
||||||
|
|
||||||
|
foreach (var field in fields)
|
||||||
|
{
|
||||||
|
var fieldType = field.FieldType;
|
||||||
|
if (_dependencies.TryGetValue(fieldType.FullName, out var dependencyInstance))
|
||||||
|
{
|
||||||
|
field.SetValue(instance, dependencyInstance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 通过名称记录或获取一个实例
|
#region 通过名称记录或获取一个实例
|
||||||
@@ -257,56 +302,62 @@ namespace Serein.Library.Utils
|
|||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public Type Type { get; set; }
|
public Type Type { get; set; }
|
||||||
}
|
}
|
||||||
private const string FlowBaseClassName = "@LibraryRootNode";
|
|
||||||
|
|
||||||
|
private const string IOC_MAIN = "*Priority Instantiation*";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构建依赖关系树
|
/// <para>遍历所有需要注册的类型,获取到它们所有构造函数,并统计每个构造函数的入参类型,构建依赖关系树</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns>“ID-PID”关系的树形结构</returns>
|
||||||
private Dictionary<string, List<string>> BuildDependencyTree()
|
private Dictionary<string, List<string>> BuildDependencyTree()
|
||||||
{
|
{
|
||||||
var dependencyMap = new Dictionary<string, HashSet<string>>();
|
var dependencyMap = new Dictionary<string, HashSet<string>>();
|
||||||
dependencyMap[FlowBaseClassName] = new HashSet<string>();
|
dependencyMap[IOC_MAIN] = new HashSet<string>(); // 优先实例化
|
||||||
foreach (var typeMapping in _typeMappings)
|
foreach (var typeMapping in _typeMappings)
|
||||||
{
|
{
|
||||||
var constructors = GetConstructor(typeMapping.Value); // 获取构造函数
|
var typeFullName = typeMapping.Key; // 注册的类型 FullName
|
||||||
|
var type = typeMapping.Value; // 对应的Type。如果是以接口形式注册,typeFullName将是接口类的FullName,而type将是接口实现类。
|
||||||
|
var constructors = GetConstructor(type); // 获取构造函数
|
||||||
|
|
||||||
foreach (var constructor in constructors)
|
foreach (var constructor in constructors)
|
||||||
{
|
{
|
||||||
if (constructor != null)
|
if (constructor is null)
|
||||||
{
|
{
|
||||||
var parameters = constructor.GetParameters()
|
continue;
|
||||||
.Select(p => p.ParameterType)
|
}
|
||||||
.ToList();
|
var parameters = constructor.GetParameters().Select(p => p.ParameterType);
|
||||||
if (parameters.Count == 0) // 无参的构造函数
|
var ctorCount = constructors.Length;
|
||||||
|
var ctorParamCount = parameters.Count();
|
||||||
|
|
||||||
|
// 类型仅有一个构造函数,并且无参,将优先实例化
|
||||||
|
if (ctorCount == 1 && ctorParamCount == 0)
|
||||||
|
{
|
||||||
|
if (!dependencyMap[IOC_MAIN].Contains(type.FullName))
|
||||||
{
|
{
|
||||||
var type = typeMapping.Value;
|
dependencyMap[IOC_MAIN].Add(type.FullName);
|
||||||
if (!dependencyMap[FlowBaseClassName].Contains(type.FullName))
|
}
|
||||||
{
|
continue;
|
||||||
dependencyMap[FlowBaseClassName].Add(type.FullName);
|
}
|
||||||
}
|
|
||||||
|
// 从类型的有参构造函数中提取类型
|
||||||
|
foreach (var param in parameters)
|
||||||
|
{
|
||||||
|
if (!dependencyMap.TryGetValue(param.FullName, out var hashSet))
|
||||||
|
{
|
||||||
|
hashSet = new HashSet<string>();
|
||||||
|
hashSet.Add(typeMapping.Key);
|
||||||
|
dependencyMap.Add(param.FullName, hashSet);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// 从类型的有参构造函数中提取类型
|
if (!hashSet.Contains(typeMapping.Key))
|
||||||
foreach (var param in parameters)
|
|
||||||
{
|
{
|
||||||
if (!dependencyMap.TryGetValue(param.FullName, out var hashSet))
|
hashSet.Add(typeMapping.Key);
|
||||||
{
|
|
||||||
hashSet = new HashSet<string>();
|
|
||||||
hashSet.Add(typeMapping.Key);
|
|
||||||
dependencyMap.Add(param.FullName, hashSet);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!hashSet.Contains(typeMapping.Key))
|
|
||||||
{
|
|
||||||
hashSet.Add(typeMapping.Key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -315,7 +366,7 @@ namespace Serein.Library.Utils
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取类型的获取所有构造函数
|
/// 获取类型的所有构造函数,根据入参数量,由多到少排列
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="type"></param>
|
/// <param name="type"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
@@ -325,42 +376,46 @@ namespace Serein.Library.Utils
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建示例的生成顺序
|
/// 创建实例的生成顺序
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="dependencyMap"></param>
|
/// <param name="dependencyMap">依赖关系树</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public List<string> GetCreationOrder(Dictionary<string, List<string>> dependencyMap)
|
public List<string> GetCreationOrder(Dictionary<string, List<string>> dependencyMap)
|
||||||
{
|
{
|
||||||
var graph = new Dictionary<string, List<string>>();
|
var graph = new Dictionary<string, List<string>>(); // 另一种依赖关系树
|
||||||
var indegree = new Dictionary<string, int>();
|
var indegree = new Dictionary<string, int>(); // 表示出现次数
|
||||||
|
|
||||||
foreach (var entry in dependencyMap)
|
foreach (var entry in dependencyMap)
|
||||||
{
|
{
|
||||||
var key = entry.Key;
|
|
||||||
if (!graph.ContainsKey(key))
|
// “rootNode”是注册类的类型FullName属性
|
||||||
|
var rootNode = entry.Key; // 根节点
|
||||||
|
|
||||||
|
if (!graph.ContainsKey(rootNode))
|
||||||
{
|
{
|
||||||
graph[key] = new List<string>();
|
graph[rootNode] = new List<string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var dependent in entry.Value)
|
// “childNode”是注册类构造函数中出现过的参数的类型FullName属性
|
||||||
|
foreach (var childNode in entry.Value)
|
||||||
{
|
{
|
||||||
if (!graph.ContainsKey(dependent))
|
if (!graph.ContainsKey(childNode))
|
||||||
{
|
{
|
||||||
graph[dependent] = new List<string>();
|
graph[childNode] = new List<string>();
|
||||||
}
|
}
|
||||||
graph[key].Add(dependent);
|
graph[rootNode].Add(childNode);
|
||||||
|
|
||||||
// 更新入度
|
// 更新入度
|
||||||
if (!indegree.ContainsKey(dependent))
|
if (!indegree.ContainsKey(childNode))
|
||||||
{
|
{
|
||||||
indegree[dependent] = 0;
|
indegree[childNode] = 0;
|
||||||
}
|
}
|
||||||
indegree[dependent]++;
|
indegree[childNode]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!indegree.ContainsKey(key))
|
if (!indegree.ContainsKey(rootNode))
|
||||||
{
|
{
|
||||||
indegree[key] = 0;
|
indegree[rootNode] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -386,10 +441,10 @@ namespace Serein.Library.Utils
|
|||||||
if (tmpList.Count > 0)
|
if (tmpList.Count > 0)
|
||||||
{
|
{
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.Append("以下类型可能产生循环依赖,请避免循环依赖,如果确实需要循环引用,请使用 [AutoInjection] 特性注入属性");
|
sb.Append("以下类型存在循环依赖,请避免循环依赖,如果确实需要循环引用,请使用 [AutoInjection] 特性注入属性");
|
||||||
foreach (var kv in tmpList)
|
foreach (var kv in tmpList)
|
||||||
{
|
{
|
||||||
sb.AppendLine($"Class Name : {kv}");
|
sb.AppendLine($"类名 : {kv}");
|
||||||
}
|
}
|
||||||
SereinEnv.WriteLine(InfoType.ERROR, sb.ToString());
|
SereinEnv.WriteLine(InfoType.ERROR, sb.ToString());
|
||||||
}
|
}
|
||||||
@@ -412,9 +467,9 @@ namespace Serein.Library.Utils
|
|||||||
{
|
{
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
if (_registerCallback.TryGetValue(typeName,out var obj))
|
if (_registerCallback.TryGetValue(typeName,out var getInstance))
|
||||||
{
|
{
|
||||||
instance = obj;
|
return getInstance.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 字符串、值类型,抽象类型,暂时不支持自动创建
|
// 字符串、值类型,抽象类型,暂时不支持自动创建
|
||||||
@@ -427,7 +482,7 @@ namespace Serein.Library.Utils
|
|||||||
{
|
{
|
||||||
// 没有显示指定构造函数入参,选择参数最多的构造函数
|
// 没有显示指定构造函数入参,选择参数最多的构造函数
|
||||||
//var constructor = GetConstructorWithMostParameters(type);
|
//var constructor = GetConstructorWithMostParameters(type);
|
||||||
var constructors = GetConstructor(type); // 获取参数最多的构造函数
|
var constructors = GetConstructor(type); // 获取构造函数
|
||||||
|
|
||||||
foreach(var constructor in constructors)
|
foreach(var constructor in constructors)
|
||||||
{
|
{
|
||||||
@@ -480,15 +535,16 @@ namespace Serein.Library.Utils
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public ISereinIOC Build()
|
public ISereinIOC Build()
|
||||||
{
|
{
|
||||||
var dependencyTree = BuildDependencyTree();
|
var dependencyTree = BuildDependencyTree(); // 生成类型依赖关系
|
||||||
var creationOrder = GetCreationOrder(dependencyTree);
|
var creationOrder = GetCreationOrder(dependencyTree); // 生成创建顺序
|
||||||
|
|
||||||
// 输出创建顺序
|
// 输出创建顺序
|
||||||
Debug.WriteLine("创建顺序: " + string.Join(" → ", creationOrder));
|
Debug.WriteLine("创建顺序: " + string.Join($"{Environment.NewLine}↓ {Environment.NewLine}", creationOrder));
|
||||||
|
|
||||||
// 创建对象
|
// 创建对象
|
||||||
foreach (var typeName in creationOrder)
|
foreach (var typeName in creationOrder)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (_dependencies.ContainsKey(typeName))
|
if (_dependencies.ContainsKey(typeName))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@@ -496,6 +552,7 @@ namespace Serein.Library.Utils
|
|||||||
var value = CreateInstance(typeName);
|
var value = CreateInstance(typeName);
|
||||||
if(value is null)
|
if(value is null)
|
||||||
{
|
{
|
||||||
|
SereinEnv.WriteLine(InfoType.ERROR, $"IOC容器无法创建对象:{typeName}");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
_dependencies[typeName] = value;
|
_dependencies[typeName] = value;
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ namespace Net462DllTest
|
|||||||
if (ViewModel is null)
|
if (ViewModel is null)
|
||||||
{
|
{
|
||||||
SereinEnv.WriteLine(InfoType.INFO, "创建对象并注入依赖项");
|
SereinEnv.WriteLine(InfoType.INFO, "创建对象并注入依赖项");
|
||||||
ViewModel = env.IOC.CreateTempObject<FromWorkBenchViewModel>();
|
ViewModel = env.IOC.CreateObject<FromWorkBenchViewModel>();
|
||||||
}
|
}
|
||||||
BindData();
|
BindData();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
using Serein.Library.Api;
|
using Serein.Library.Api;
|
||||||
using Serein.Library.FlowNode;
|
using Serein.Library.FlowNode;
|
||||||
using Serein.Library.Utils;
|
using Serein.Library.Utils;
|
||||||
|
using Serein.NodeFlow.Services;
|
||||||
using Serein.NodeFlow.Tool;
|
using Serein.NodeFlow.Tool;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
@@ -14,15 +15,26 @@ namespace Serein.NodeFlow.Env
|
|||||||
{
|
{
|
||||||
public FlowEnvironment()
|
public FlowEnvironment()
|
||||||
{
|
{
|
||||||
flowEnvironmentEvent = new FlowEnvironmentEvent();
|
ISereinIOC sereinIOC = new SereinIOC();
|
||||||
flowEnvironment = new LocalFlowEnvironment(flowEnvironmentEvent);
|
sereinIOC.Reset();
|
||||||
|
sereinIOC.Register<ISereinIOC>(()=> sereinIOC); // 注册IOC
|
||||||
|
sereinIOC.Register<IFlowEnvironment>(() => this);
|
||||||
|
sereinIOC.Register<IFlowEnvironmentEvent, FlowEnvironmentEvent>();
|
||||||
|
sereinIOC.Register<LocalFlowEnvironment>();
|
||||||
|
sereinIOC.Register<FlowModelService>();
|
||||||
|
sereinIOC.Register<FlowOperationService>();
|
||||||
|
sereinIOC.Register<NodeMVVMService>();
|
||||||
|
sereinIOC.Register<FlowLibraryManagement>();
|
||||||
|
sereinIOC.Build();
|
||||||
|
this.IOC = sereinIOC;
|
||||||
|
|
||||||
// 默认使用本地环境
|
// 默认使用本地环境
|
||||||
currentFlowEnvironment = flowEnvironment;
|
currentFlowEnvironment = sereinIOC.Get<LocalFlowEnvironment>();
|
||||||
currentFlowEnvironmentEvent = flowEnvironmentEvent;
|
currentFlowEnvironmentEvent = sereinIOC.Get<IFlowEnvironmentEvent>();
|
||||||
SereinEnv.SetEnv(currentFlowEnvironment);
|
SereinEnv.SetEnv(currentFlowEnvironment);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/* /// <summary>
|
||||||
/// 本地环境
|
/// 本地环境
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly LocalFlowEnvironment flowEnvironment;
|
private readonly LocalFlowEnvironment flowEnvironment;
|
||||||
@@ -30,7 +42,7 @@ namespace Serein.NodeFlow.Env
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 远程环境
|
/// 远程环境
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private RemoteFlowEnvironment remoteFlowEnvironment;
|
private RemoteFlowEnvironment remoteFlowEnvironment;*/
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 本地环境事件
|
/// 本地环境事件
|
||||||
@@ -79,9 +91,10 @@ namespace Serein.NodeFlow.Env
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public UIContextOperation UIContextOperation => currentFlowEnvironment.UIContextOperation;
|
public UIContextOperation UIContextOperation => currentFlowEnvironment.UIContextOperation;
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public NodeMVVMManagement NodeMVVMManagement => currentFlowEnvironment.NodeMVVMManagement;
|
public NodeMVVMService NodeMVVMManagement => currentFlowEnvironment.NodeMVVMManagement;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ISereinIOC IOC => currentFlowEnvironment.IOC;
|
public ISereinIOC IOC { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public IFlowEnvironmentEvent Event => currentFlowEnvironment.Event;
|
public IFlowEnvironmentEvent Event => currentFlowEnvironment.Event;
|
||||||
@@ -239,30 +252,30 @@ namespace Serein.NodeFlow.Env
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async Task<FlowCanvasDetailsInfo> CreateCanvasAsync(string canvasName, int width, int height)
|
public void CreateCanvas(string canvasName, int width, int height)
|
||||||
{
|
{
|
||||||
return await currentFlowEnvironment.CreateCanvasAsync(canvasName, width, height);
|
currentFlowEnvironment.CreateCanvas(canvasName, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async Task<bool> RemoveCanvasAsync(string canvasGuid)
|
public void RemoveCanvas(string canvasGuid)
|
||||||
{
|
{
|
||||||
return await currentFlowEnvironment.RemoveCanvasAsync(canvasGuid);
|
currentFlowEnvironment.RemoveCanvas(canvasGuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async Task<bool> ConnectInvokeNodeAsync(string canvasGuid,
|
public void ConnectInvokeNode(string canvasGuid,
|
||||||
string fromNodeGuid,
|
string fromNodeGuid,
|
||||||
string toNodeGuid,
|
string toNodeGuid,
|
||||||
JunctionType fromNodeJunctionType,
|
JunctionType fromNodeJunctionType,
|
||||||
JunctionType toNodeJunctionType,
|
JunctionType toNodeJunctionType,
|
||||||
ConnectionInvokeType invokeType)
|
ConnectionInvokeType invokeType)
|
||||||
{
|
{
|
||||||
return await currentFlowEnvironment.ConnectInvokeNodeAsync(canvasGuid, fromNodeGuid, toNodeGuid, fromNodeJunctionType, toNodeJunctionType, invokeType);
|
currentFlowEnvironment.ConnectInvokeNode(canvasGuid, fromNodeGuid, toNodeGuid, fromNodeJunctionType, toNodeJunctionType, invokeType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async Task<bool> ConnectArgSourceNodeAsync(string canvasGuid,
|
public void ConnectArgSourceNode(string canvasGuid,
|
||||||
string fromNodeGuid,
|
string fromNodeGuid,
|
||||||
string toNodeGuid,
|
string toNodeGuid,
|
||||||
JunctionType fromNodeJunctionType,
|
JunctionType fromNodeJunctionType,
|
||||||
@@ -270,7 +283,7 @@ namespace Serein.NodeFlow.Env
|
|||||||
ConnectionArgSourceType argSourceType,
|
ConnectionArgSourceType argSourceType,
|
||||||
int argIndex)
|
int argIndex)
|
||||||
{
|
{
|
||||||
return await currentFlowEnvironment.ConnectArgSourceNodeAsync(canvasGuid, fromNodeGuid, toNodeGuid, fromNodeJunctionType, toNodeJunctionType, argSourceType, argIndex);
|
currentFlowEnvironment.ConnectArgSourceNode(canvasGuid, fromNodeGuid, toNodeGuid, fromNodeJunctionType, toNodeJunctionType, argSourceType, argIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
@@ -281,8 +294,8 @@ namespace Serein.NodeFlow.Env
|
|||||||
if (isConnect)
|
if (isConnect)
|
||||||
{
|
{
|
||||||
|
|
||||||
remoteFlowEnvironment ??= new RemoteFlowEnvironment(remoteMsgUtil, this.Event, this.UIContextOperation);
|
/* remoteFlowEnvironment ??= new RemoteFlowEnvironment(remoteMsgUtil, this.Event, this.UIContextOperation);
|
||||||
currentFlowEnvironment = remoteFlowEnvironment;
|
currentFlowEnvironment = remoteFlowEnvironment;*/
|
||||||
}
|
}
|
||||||
return (isConnect, remoteMsgUtil);
|
return (isConnect, remoteMsgUtil);
|
||||||
}
|
}
|
||||||
@@ -296,30 +309,27 @@ namespace Serein.NodeFlow.Env
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async Task<NodeInfo> CreateNodeAsync(string canvasGuid, NodeControlType nodeBase, PositionOfUI position, MethodDetailsInfo methodDetailsInfo = null)
|
public void CreateNode(string canvasGuid, NodeControlType nodeBase, PositionOfUI position, MethodDetailsInfo methodDetailsInfo = null)
|
||||||
{
|
{
|
||||||
SetProjectLoadingFlag(false);
|
SetProjectLoadingFlag(false);
|
||||||
var result = await currentFlowEnvironment.CreateNodeAsync(canvasGuid, nodeBase, position, methodDetailsInfo); // 装饰器调用
|
currentFlowEnvironment.CreateNode(canvasGuid, nodeBase, position, methodDetailsInfo); // 装饰器调用
|
||||||
SetProjectLoadingFlag(true);
|
SetProjectLoadingFlag(true);
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async Task<bool> PlaceNodeToContainerAsync(string canvasGuid, string nodeGuid, string containerNodeGuid)
|
public void PlaceNodeToContainer(string canvasGuid, string nodeGuid, string containerNodeGuid)
|
||||||
{
|
{
|
||||||
SetProjectLoadingFlag(false);
|
SetProjectLoadingFlag(false);
|
||||||
var result = await currentFlowEnvironment.PlaceNodeToContainerAsync(canvasGuid, nodeGuid, containerNodeGuid); // 装饰器调用
|
currentFlowEnvironment.PlaceNodeToContainer(canvasGuid, nodeGuid, containerNodeGuid); // 装饰器调用
|
||||||
SetProjectLoadingFlag(true);
|
SetProjectLoadingFlag(true);
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async Task<bool> TakeOutNodeToContainerAsync(string canvasGuid, string nodeGuid)
|
public void TakeOutNodeToContainer(string canvasGuid, string nodeGuid)
|
||||||
{
|
{
|
||||||
SetProjectLoadingFlag(false);
|
SetProjectLoadingFlag(false);
|
||||||
var result = await currentFlowEnvironment.TakeOutNodeToContainerAsync(canvasGuid,nodeGuid); // 装饰器调用
|
currentFlowEnvironment.TakeOutNodeToContainer(canvasGuid,nodeGuid); // 装饰器调用
|
||||||
SetProjectLoadingFlag(true);
|
SetProjectLoadingFlag(true);
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
@@ -393,27 +403,27 @@ namespace Serein.NodeFlow.Env
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async Task<bool> SetConnectPriorityInvoke(string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType)
|
public void SetConnectPriorityInvoke(string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType)
|
||||||
{
|
{
|
||||||
return await currentFlowEnvironment.SetConnectPriorityInvoke(fromNodeGuid, toNodeGuid, connectionType);
|
currentFlowEnvironment.SetConnectPriorityInvoke(fromNodeGuid, toNodeGuid, connectionType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async Task<bool> RemoveConnectInvokeAsync(string canvasGuid, string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType)
|
public void RemoveInvokeConnect(string canvasGuid, string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType)
|
||||||
{
|
{
|
||||||
return await currentFlowEnvironment.RemoveConnectInvokeAsync(canvasGuid, fromNodeGuid, toNodeGuid, connectionType);
|
currentFlowEnvironment.RemoveInvokeConnect(canvasGuid, fromNodeGuid, toNodeGuid, connectionType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async Task<bool> RemoveConnectArgSourceAsync(string canvasGuid, string fromNodeGuid, string toNodeGuid, int argIndex)
|
public void RemoveArgSourceConnect(string canvasGuid, string fromNodeGuid, string toNodeGuid, int argIndex)
|
||||||
{
|
{
|
||||||
return await currentFlowEnvironment.RemoveConnectArgSourceAsync(canvasGuid, fromNodeGuid, toNodeGuid, argIndex);
|
currentFlowEnvironment.RemoveArgSourceConnect(canvasGuid, fromNodeGuid, toNodeGuid, argIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async Task<bool> RemoveNodeAsync(string canvasGuid, string nodeGuid)
|
public void RemoveNode(string canvasGuid, string nodeGuid)
|
||||||
{
|
{
|
||||||
return await currentFlowEnvironment.RemoveNodeAsync(canvasGuid, nodeGuid);
|
currentFlowEnvironment.RemoveNode(canvasGuid, nodeGuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -460,9 +470,9 @@ namespace Serein.NodeFlow.Env
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async Task<string> SetStartNodeAsync(string canvasGuid, string nodeGuid)
|
public void SetStartNode(string canvasGuid, string nodeGuid)
|
||||||
{
|
{
|
||||||
return await currentFlowEnvironment.SetStartNodeAsync(canvasGuid, nodeGuid);
|
currentFlowEnvironment.SetStartNode(canvasGuid, nodeGuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
@@ -504,6 +514,11 @@ namespace Serein.NodeFlow.Env
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void SetUIContextOperation(UIContextOperation uiContextOperation)
|
public void SetUIContextOperation(UIContextOperation uiContextOperation)
|
||||||
{
|
{
|
||||||
|
if(uiContextOperation is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
IOC.Register<UIContextOperation>(() => uiContextOperation).Build();
|
||||||
currentFlowEnvironment.SetUIContextOperation(uiContextOperation);
|
currentFlowEnvironment.SetUIContextOperation(uiContextOperation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -545,9 +560,9 @@ namespace Serein.NodeFlow.Env
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async Task<bool> ChangeParameter(string nodeGuid, bool isAdd, int paramIndex)
|
public void ChangeParameter(string nodeGuid, bool isAdd, int paramIndex)
|
||||||
{
|
{
|
||||||
return await currentFlowEnvironment.ChangeParameter(nodeGuid, isAdd, paramIndex);
|
currentFlowEnvironment.ChangeParameter(nodeGuid, isAdd, paramIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
#region 流程依赖类库的接口
|
#region 流程依赖类库的接口
|
||||||
|
|||||||
@@ -26,92 +26,92 @@ namespace Serein.NodeFlow.Env
|
|||||||
|
|
||||||
public void OnDllLoad(LoadDllEventArgs eventArgs)
|
public void OnDllLoad(LoadDllEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
DllLoad.Invoke(eventArgs);
|
DllLoad?.Invoke(eventArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnProjectLoaded(ProjectLoadedEventArgs eventArgs)
|
public void OnProjectLoaded(ProjectLoadedEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
ProjectLoaded.Invoke(eventArgs);
|
ProjectLoaded?.Invoke(eventArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnProjectSaving(ProjectSavingEventArgs eventArgs)
|
public void OnProjectSaving(ProjectSavingEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
ProjectSaving.Invoke(eventArgs);
|
ProjectSaving?.Invoke(eventArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnNodeConnectChanged(NodeConnectChangeEventArgs eventArgs)
|
public void OnNodeConnectChanged(NodeConnectChangeEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
NodeConnectChanged.Invoke(eventArgs);
|
NodeConnectChanged?.Invoke(eventArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnCanvasCreated(CanvasCreateEventArgs eventArgs)
|
public void OnCanvasCreated(CanvasCreateEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
CanvasCreated.Invoke(eventArgs);
|
CanvasCreated?.Invoke(eventArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnCanvasRemoved(CanvasRemoveEventArgs eventArgs)
|
public void OnCanvasRemoved(CanvasRemoveEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
CanvasRemoved.Invoke(eventArgs);
|
CanvasRemoved?.Invoke(eventArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnNodeCreated(NodeCreateEventArgs eventArgs)
|
public void OnNodeCreated(NodeCreateEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
NodeCreated.Invoke(eventArgs);
|
NodeCreated?.Invoke(eventArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnNodeRemoved(NodeRemoveEventArgs eventArgs)
|
public void OnNodeRemoved(NodeRemoveEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
NodeRemoved.Invoke(eventArgs);
|
NodeRemoved?.Invoke(eventArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnNodePlace(NodePlaceEventArgs eventArgs)
|
public void OnNodePlace(NodePlaceEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
NodePlace.Invoke(eventArgs);
|
NodePlace?.Invoke(eventArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnNodeTakeOut(NodeTakeOutEventArgs eventArgs)
|
public void OnNodeTakeOut(NodeTakeOutEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
NodeTakeOut.Invoke(eventArgs);
|
NodeTakeOut?.Invoke(eventArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnStartNodeChanged(StartNodeChangeEventArgs eventArgs)
|
public void OnStartNodeChanged(StartNodeChangeEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
StartNodeChanged.Invoke(eventArgs);
|
StartNodeChanged?.Invoke(eventArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnFlowRunComplete(FlowEventArgs eventArgs)
|
public void OnFlowRunComplete(FlowEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
FlowRunComplete.Invoke(eventArgs);
|
FlowRunComplete?.Invoke(eventArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnMonitorObjectChanged(MonitorObjectEventArgs eventArgs)
|
public void OnMonitorObjectChanged(MonitorObjectEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
MonitorObjectChanged.Invoke(eventArgs);
|
MonitorObjectChanged?.Invoke(eventArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnNodeInterruptStateChanged(NodeInterruptStateChangeEventArgs eventArgs)
|
public void OnNodeInterruptStateChanged(NodeInterruptStateChangeEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
NodeInterruptStateChanged.Invoke(eventArgs);
|
NodeInterruptStateChanged?.Invoke(eventArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnInterruptTriggered(InterruptTriggerEventArgs eventArgs)
|
public void OnInterruptTriggered(InterruptTriggerEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
InterruptTriggered.Invoke(eventArgs);
|
InterruptTriggered?.Invoke(eventArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnIOCMembersChanged(IOCMembersChangedEventArgs eventArgs)
|
public void OnIOCMembersChanged(IOCMembersChangedEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
IOCMembersChanged.Invoke(eventArgs);
|
IOCMembersChanged?.Invoke(eventArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnNodeLocated(NodeLocatedEventArgs eventArgs)
|
public void OnNodeLocated(NodeLocatedEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
NodeLocated.Invoke(eventArgs);
|
NodeLocated?.Invoke(eventArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnEnvOutput(InfoType type, string value)
|
public void OnEnvOutput(InfoType type, string value)
|
||||||
{
|
{
|
||||||
EnvOutput.Invoke(type, value);
|
EnvOutput?.Invoke(type, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -89,6 +89,9 @@ namespace Serein.NodeFlow.Env
|
|||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#region 远程管理
|
#region 远程管理
|
||||||
|
|
||||||
private MsgControllerOfServer clientMsgManage;
|
private MsgControllerOfServer clientMsgManage;
|
||||||
|
|||||||
2170
NodeFlow/Env/LocalFlowEnvironment_T.cs
Normal file
2170
NodeFlow/Env/LocalFlowEnvironment_T.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -46,7 +46,6 @@ namespace Serein.NodeFlow.Env
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private Dictionary<string, IFlowNode> NodeModels { get; } = [];
|
private Dictionary<string, IFlowNode> NodeModels { get; } = [];
|
||||||
|
|
||||||
|
|
||||||
public ISereinIOC IOC => throw new NotImplementedException();
|
public ISereinIOC IOC => throw new NotImplementedException();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -73,7 +72,7 @@ namespace Serein.NodeFlow.Env
|
|||||||
|
|
||||||
public IFlowEnvironment CurrentEnv => this;
|
public IFlowEnvironment CurrentEnv => this;
|
||||||
public UIContextOperation UIContextOperation { get; }
|
public UIContextOperation UIContextOperation { get; }
|
||||||
public NodeMVVMManagement NodeMVVMManagement { get; }
|
public NodeMVVMService NodeMVVMManagement { get; }
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -658,8 +657,8 @@ namespace Serein.NodeFlow.Env
|
|||||||
Event.OnNodeConnectChanged(new NodeConnectChangeEventArgs(canvasGuid,
|
Event.OnNodeConnectChanged(new NodeConnectChangeEventArgs(canvasGuid,
|
||||||
fromNodeGuid,
|
fromNodeGuid,
|
||||||
toNodeGuid,
|
toNodeGuid,
|
||||||
JunctionOfConnectionType.Arg,
|
|
||||||
argIndex,
|
argIndex,
|
||||||
|
JunctionOfConnectionType.Arg,
|
||||||
argSourceType,
|
argSourceType,
|
||||||
NodeConnectChangeEventArgs.ConnectChangeType.Create)); // 通知UI
|
NodeConnectChangeEventArgs.ConnectChangeType.Create)); // 通知UI
|
||||||
}
|
}
|
||||||
@@ -729,8 +728,8 @@ namespace Serein.NodeFlow.Env
|
|||||||
Event.OnNodeConnectChanged(new NodeConnectChangeEventArgs(canvasGuid,
|
Event.OnNodeConnectChanged(new NodeConnectChangeEventArgs(canvasGuid,
|
||||||
fromNodeGuid,
|
fromNodeGuid,
|
||||||
toNodeGuid,
|
toNodeGuid,
|
||||||
JunctionOfConnectionType.Arg,
|
|
||||||
argIndex,
|
argIndex,
|
||||||
|
JunctionOfConnectionType.Arg,
|
||||||
ConnectionArgSourceType.GetPreviousNodeData,
|
ConnectionArgSourceType.GetPreviousNodeData,
|
||||||
NodeConnectChangeEventArgs.ConnectChangeType.Remove)); // 通知UI
|
NodeConnectChangeEventArgs.ConnectChangeType.Remove)); // 通知UI
|
||||||
});
|
});
|
||||||
@@ -1283,8 +1282,8 @@ namespace Serein.NodeFlow.Env
|
|||||||
canvasGuid,
|
canvasGuid,
|
||||||
fromNode.Guid, // 从哪个节点开始
|
fromNode.Guid, // 从哪个节点开始
|
||||||
toNode.Guid, // 连接到那个节点
|
toNode.Guid, // 连接到那个节点
|
||||||
|
pd.Index, // 连接线的样式类型
|
||||||
JunctionOfConnectionType.Arg,
|
JunctionOfConnectionType.Arg,
|
||||||
(int)pd.Index, // 连接线的样式类型
|
|
||||||
pd.ArgDataSourceType,
|
pd.ArgDataSourceType,
|
||||||
NodeConnectChangeEventArgs.ConnectChangeType.Create // 是创建连接还是删除连接
|
NodeConnectChangeEventArgs.ConnectChangeType.Create // 是创建连接还是删除连接
|
||||||
))); // 通知UI
|
))); // 通知UI
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
using Serein.Library;
|
using Serein.Library;
|
||||||
using Serein.Library.Api;
|
using Serein.Library.Api;
|
||||||
using Serein.Library.Utils;
|
using Serein.Library.Utils;
|
||||||
using Serein.NodeFlow.Model;
|
using Serein.NodeFlow.Model.Node;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|||||||
@@ -96,11 +96,19 @@ namespace Serein.NodeFlow.Model
|
|||||||
{
|
{
|
||||||
PreviousNodes = new Dictionary<ConnectionInvokeType, List<IFlowNode>>();
|
PreviousNodes = new Dictionary<ConnectionInvokeType, List<IFlowNode>>();
|
||||||
SuccessorNodes = new Dictionary<ConnectionInvokeType, List<IFlowNode>>();
|
SuccessorNodes = new Dictionary<ConnectionInvokeType, List<IFlowNode>>();
|
||||||
|
NeedResultNodes = new Dictionary<ConnectionArgSourceType, List<IFlowNode>>();
|
||||||
|
|
||||||
foreach (ConnectionInvokeType ctType in NodeStaticConfig.ConnectionTypes)
|
foreach (ConnectionInvokeType ctType in NodeStaticConfig.ConnectionTypes)
|
||||||
{
|
{
|
||||||
PreviousNodes[ctType] = new List<IFlowNode>();
|
PreviousNodes[ctType] = new List<IFlowNode>();
|
||||||
SuccessorNodes[ctType] = new List<IFlowNode>();
|
SuccessorNodes[ctType] = new List<IFlowNode>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (ConnectionArgSourceType ctType in NodeStaticConfig.ConnectionArgSourceTypes)
|
||||||
|
{
|
||||||
|
NeedResultNodes[ctType] = new List<IFlowNode>();
|
||||||
|
}
|
||||||
|
|
||||||
ChildrenNode = new List<IFlowNode>();
|
ChildrenNode = new List<IFlowNode>();
|
||||||
DebugSetting = new NodeDebugSetting(this);
|
DebugSetting = new NodeDebugSetting(this);
|
||||||
this.Env = environment;
|
this.Env = environment;
|
||||||
@@ -116,6 +124,11 @@ namespace Serein.NodeFlow.Model
|
|||||||
/// 不同分支的子节点(流程调用)
|
/// 不同分支的子节点(流程调用)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Dictionary<ConnectionInvokeType, List<IFlowNode>> SuccessorNodes { get; set; }
|
public Dictionary<ConnectionInvokeType, List<IFlowNode>> SuccessorNodes { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 需要该节点返回值作为入参参数的节点集合
|
||||||
|
/// </summary>
|
||||||
|
public Dictionary<ConnectionArgSourceType, List<IFlowNode>> NeedResultNodes { get;}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 该节点的容器节点
|
/// 该节点的容器节点
|
||||||
@@ -57,7 +57,7 @@ namespace Serein.NodeFlow.Model
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/* /// <summary>
|
||||||
/// 移除该节点
|
/// 移除该节点
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual void Remove()
|
public virtual void Remove()
|
||||||
@@ -101,7 +101,7 @@ namespace Serein.NodeFlow.Model
|
|||||||
this.DisplayName = null;
|
this.DisplayName = null;
|
||||||
|
|
||||||
this.Env = null;
|
this.Env = null;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 执行节点对应的方法
|
/// 执行节点对应的方法
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
using Serein.Library;
|
using Serein.Library;
|
||||||
using System.Security.AccessControl;
|
using System.Security.AccessControl;
|
||||||
|
|
||||||
namespace Serein.NodeFlow.Model
|
namespace Serein.NodeFlow.Model.Node
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 单动作节点(用于动作控件)
|
/// 单动作节点(用于动作控件)
|
||||||
@@ -3,7 +3,7 @@ using Serein.Library;
|
|||||||
using Serein.Library.Utils;
|
using Serein.Library.Utils;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Serein.NodeFlow.Model
|
namespace Serein.NodeFlow.Model.Node
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 触发器节点
|
/// 触发器节点
|
||||||
@@ -27,9 +27,9 @@ namespace Serein.NodeFlow.Model
|
|||||||
#region 执行前中断
|
#region 执行前中断
|
||||||
if (DebugSetting.IsInterrupt) // 执行触发前
|
if (DebugSetting.IsInterrupt) // 执行触发前
|
||||||
{
|
{
|
||||||
string guid = this.Guid.ToString();
|
string guid = Guid.ToString();
|
||||||
await this.DebugSetting.GetInterruptTask.Invoke();
|
await DebugSetting.GetInterruptTask.Invoke();
|
||||||
await Console.Out.WriteLineAsync($"[{this.MethodDetails.MethodName}]中断已取消,开始执行后继分支");
|
await Console.Out.WriteLineAsync($"[{MethodDetails.MethodName}]中断已取消,开始执行后继分支");
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@@ -61,7 +61,7 @@ namespace Serein.NodeFlow.Model
|
|||||||
|
|
||||||
if (dynamicFlipflopContext.Type == TriggerDescription.Overtime)
|
if (dynamicFlipflopContext.Type == TriggerDescription.Overtime)
|
||||||
{
|
{
|
||||||
throw new FlipflopException(base.MethodDetails.MethodName + "触发器超时触发。Guid" + base.Guid);
|
throw new FlipflopException(MethodDetails.MethodName + "触发器超时触发。Guid" + Guid);
|
||||||
}
|
}
|
||||||
object result = dynamicFlipflopContext.Value;
|
object result = dynamicFlipflopContext.Value;
|
||||||
var flowReslt = new FlowResult(this, context, result);
|
var flowReslt = new FlowResult(this, context, result);
|
||||||
@@ -119,7 +119,7 @@ namespace Serein.NodeFlow.Model
|
|||||||
|
|
||||||
partial void OnIsShareParamChanged(bool value)
|
partial void OnIsShareParamChanged(bool value)
|
||||||
{
|
{
|
||||||
if (targetNode is null)
|
if (targetNode is null || targetNode.MethodDetails is null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -219,14 +219,13 @@ namespace Serein.NodeFlow.Model
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public override void Remove()
|
/*public override void Remove()
|
||||||
{
|
{
|
||||||
var tmp = this;
|
var tmp = this;
|
||||||
targetNode = null;
|
targetNode = null;
|
||||||
CacheMethodDetails = null;
|
CacheMethodDetails = null;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -96,7 +96,7 @@ namespace Serein.NodeFlow.Model
|
|||||||
{
|
{
|
||||||
foreach (var nodeModel in ChildrenNode)
|
foreach (var nodeModel in ChildrenNode)
|
||||||
{
|
{
|
||||||
await nodeModel.Env.TakeOutNodeToContainerAsync(nodeModel.CanvasDetails.Guid, nodeModel.Guid);
|
nodeModel.Env.TakeOutNodeToContainer(nodeModel.CanvasDetails.Guid, nodeModel.Guid);
|
||||||
}
|
}
|
||||||
DataNode = null;
|
DataNode = null;
|
||||||
}
|
}
|
||||||
@@ -162,7 +162,7 @@ namespace Serein.NodeFlow.Model
|
|||||||
KeyName = nodeInfo.CustomData?.KeyName;
|
KeyName = nodeInfo.CustomData?.KeyName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/* /// <summary>
|
||||||
/// 需要移除数据节点
|
/// 需要移除数据节点
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public override void Remove()
|
public override void Remove()
|
||||||
@@ -172,7 +172,7 @@ namespace Serein.NodeFlow.Model
|
|||||||
}
|
}
|
||||||
// 移除数据节点
|
// 移除数据节点
|
||||||
_ = this.Env.RemoveNodeAsync(DataNode.CanvasDetails.Guid, DataNode.Guid);
|
_ = this.Env.RemoveNodeAsync(DataNode.CanvasDetails.Guid, DataNode.Guid);
|
||||||
}
|
}*/
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -226,7 +226,7 @@ namespace Serein.NodeFlow.Model
|
|||||||
scriptContext.OnExit();
|
scriptContext.OnExit();
|
||||||
};
|
};
|
||||||
|
|
||||||
var envEvent = (IFlowEnvironmentEvent)context.Env;
|
var envEvent = context.Env.Event;
|
||||||
envEvent.FlowRunComplete += onFlowStop; // 防止运行后台流程
|
envEvent.FlowRunComplete += onFlowStop; // 防止运行后台流程
|
||||||
|
|
||||||
if (token.IsCancellationRequested) return null;
|
if (token.IsCancellationRequested) return null;
|
||||||
@@ -6,7 +6,7 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Serein.NodeFlow.Model
|
namespace Serein.NodeFlow.Model.Node
|
||||||
{
|
{
|
||||||
public class SingleUINode : NodeModelBase
|
public class SingleUINode : NodeModelBase
|
||||||
{
|
{
|
||||||
@@ -24,7 +24,7 @@ namespace Serein.NodeFlow.Model
|
|||||||
var result = await base.ExecutingAsync(context, token);
|
var result = await base.ExecutingAsync(context, token);
|
||||||
if (result.Value is IEmbeddedContent adapter)
|
if (result.Value is IEmbeddedContent adapter)
|
||||||
{
|
{
|
||||||
this.Adapter = adapter;
|
Adapter = adapter;
|
||||||
context.NextOrientation = ConnectionInvokeType.IsSucceed;
|
context.NextOrientation = ConnectionInvokeType.IsSucceed;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
451
NodeFlow/Model/Operation/ChangeNodeConnectionOperation.cs
Normal file
451
NodeFlow/Model/Operation/ChangeNodeConnectionOperation.cs
Normal file
@@ -0,0 +1,451 @@
|
|||||||
|
using Serein.Library;
|
||||||
|
using Serein.Library.Api;
|
||||||
|
using Serein.NodeFlow.Env;
|
||||||
|
using Serein.NodeFlow.Model.Node;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using static Serein.Library.Api.NodeConnectChangeEventArgs;
|
||||||
|
|
||||||
|
namespace Serein.NodeFlow.Model.Operation
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 节点连接状态发生改变
|
||||||
|
/// </summary>
|
||||||
|
internal class ChangeNodeConnectionOperation : OperationBase
|
||||||
|
{
|
||||||
|
public override string Theme => nameof(ChangeNodeConnectionOperation);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 所在画布
|
||||||
|
/// </summary>
|
||||||
|
public required string CanvasGuid { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 连接关系中始节点的Guid
|
||||||
|
/// </summary>
|
||||||
|
public required string FromNodeGuid { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 连接关系中目标节点的Guid
|
||||||
|
/// </summary>
|
||||||
|
public required string ToNodeGuid { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 起始节点连接控制点类型
|
||||||
|
/// </summary>
|
||||||
|
public JunctionType FromNodeJunctionType { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 目标节点连接控制点类型
|
||||||
|
/// </summary>
|
||||||
|
public JunctionType ToNodeJunctionType { get; set; }
|
||||||
|
|
||||||
|
/// 连接类型
|
||||||
|
/// </summary>
|
||||||
|
public ConnectionInvokeType ConnectionInvokeType { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 表示此次需要在两个节点之间创建连接关系,或是移除连接关系
|
||||||
|
/// </summary>
|
||||||
|
public ConnectChangeType ChangeType { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 指示需要创建什么类型的连接线
|
||||||
|
/// </summary>
|
||||||
|
public JunctionOfConnectionType JunctionOfConnectionType { get; set; } = JunctionOfConnectionType.None;
|
||||||
|
/// <summary>
|
||||||
|
/// 节点对应的方法入参所需参数来源
|
||||||
|
/// </summary>
|
||||||
|
public ConnectionArgSourceType ConnectionArgSourceType { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 第几个参数
|
||||||
|
/// </summary>
|
||||||
|
public int ArgIndex { get; set; } = -1;
|
||||||
|
|
||||||
|
public override bool IsCanUndo => false;
|
||||||
|
|
||||||
|
#region 私有参数
|
||||||
|
private FlowCanvasDetails FlowCanvas;
|
||||||
|
private IFlowNode FromNode;
|
||||||
|
private IFlowNode ToNode;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public override bool ValidationParameter()
|
||||||
|
{
|
||||||
|
if (JunctionOfConnectionType == JunctionOfConnectionType.None)
|
||||||
|
return false;
|
||||||
|
if (JunctionOfConnectionType == JunctionOfConnectionType.Arg && ArgIndex == -1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!flowModelService.ContainsCanvasModel(CanvasGuid) // 不存在画布
|
||||||
|
|| !flowModelService.ContainsNodeModel(FromNodeGuid) // 不存在节点
|
||||||
|
|| !flowModelService.ContainsNodeModel(ToNodeGuid)) // 不存在节点
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Execute()
|
||||||
|
{
|
||||||
|
if (!ValidationParameter()) return false;
|
||||||
|
if (!flowModelService.TryGetCanvasModel(CanvasGuid, out FlowCanvas) // 不存在画布
|
||||||
|
|| !flowModelService.TryGetNodeModel(FromNodeGuid, out FromNode) // 不存在节点
|
||||||
|
|| !flowModelService.TryGetNodeModel(ToNodeGuid, out ToNode)) // 不存在节点
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ChangeType == ConnectChangeType.Create) // 创建连线时需要检查
|
||||||
|
{
|
||||||
|
(var jcType, var isCanConnection) = CheckConnect(FromNode, ToNode, FromNodeJunctionType, ToNodeJunctionType);
|
||||||
|
if (!isCanConnection)
|
||||||
|
{
|
||||||
|
SereinEnv.WriteLine(InfoType.WARN, "出现非预期的连接行为");
|
||||||
|
return false; // 出现不符预期的连接行为,忽略此次连接行为
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果起始控制点是“方法执行”,目标控制点是“方法调用”,需要反转 from to 节点
|
||||||
|
if (jcType == JunctionOfConnectionType.Invoke
|
||||||
|
&& FromNodeJunctionType == JunctionType.Execute
|
||||||
|
&& ToNodeJunctionType == JunctionType.NextStep)
|
||||||
|
{
|
||||||
|
// 如果 起始控制点 是“方法调用”,需要反转 from to 节点
|
||||||
|
(FromNode, ToNode) = (ToNode, FromNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果起始控制点是“方法入参”,目标控制点是“返回值”,需要反转 from to 节点
|
||||||
|
if (jcType == JunctionOfConnectionType.Arg
|
||||||
|
&& FromNodeJunctionType == JunctionType.ArgData
|
||||||
|
&& ToNodeJunctionType == JunctionType.ReturnData)
|
||||||
|
{
|
||||||
|
(FromNode, ToNode) = (ToNode, FromNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//if (toNode is SingleFlipflopNode flipflopNode)
|
||||||
|
//{
|
||||||
|
// flowTaskManagement?.TerminateGlobalFlipflopRuning(flipflopNode); // 假设被连接的是全局触发器,尝试移除
|
||||||
|
//}
|
||||||
|
|
||||||
|
var state = (JunctionOfConnectionType, ChangeType) switch
|
||||||
|
{
|
||||||
|
(JunctionOfConnectionType.Invoke, NodeConnectChangeEventArgs.ConnectChangeType.Create) => CreateInvokeConnection(), // 创建节点之间的调用关系
|
||||||
|
(JunctionOfConnectionType.Invoke, NodeConnectChangeEventArgs.ConnectChangeType.Remove) => RemoveInvokeConnection(), // 移除节点之间的调用关系
|
||||||
|
(JunctionOfConnectionType.Arg, NodeConnectChangeEventArgs.ConnectChangeType.Create) => CreateArgConnection(), // 创建节点之间的参数传递关系
|
||||||
|
(JunctionOfConnectionType.Arg, NodeConnectChangeEventArgs.ConnectChangeType.Remove) => RemoveArgConnection(), // 移除节点之间的参数传递关系
|
||||||
|
_ => false
|
||||||
|
};
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ToInfo()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建方法调用关系
|
||||||
|
/// </summary>
|
||||||
|
private bool CreateInvokeConnection()
|
||||||
|
{
|
||||||
|
IFlowNode fromNode = FromNode ;
|
||||||
|
IFlowNode toNode = ToNode;
|
||||||
|
ConnectionInvokeType invokeType = ConnectionInvokeType;
|
||||||
|
if (fromNode.ControlType == NodeControlType.FlowCall)
|
||||||
|
{
|
||||||
|
SereinEnv.WriteLine(InfoType.ERROR, $"流程接口节点不可调用下一个节点。" +
|
||||||
|
$"{Environment.NewLine}流程节点:{fromNode.Guid}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var isOverwriting = false;
|
||||||
|
ConnectionInvokeType overwritingCt = ConnectionInvokeType.None;
|
||||||
|
var isPass = false;
|
||||||
|
|
||||||
|
#region 检查是否存在对应的连接
|
||||||
|
foreach (ConnectionInvokeType ctType in NodeStaticConfig.ConnectionTypes)
|
||||||
|
{
|
||||||
|
var count1 = fromNode.SuccessorNodes[ctType].Count(it => it.Guid.Equals(toNode.Guid));
|
||||||
|
var count2 = toNode.PreviousNodes[ctType].Count(it => it.Guid.Equals(fromNode.Guid));
|
||||||
|
var hasError1 = count1 > 0;
|
||||||
|
var hasError2 = count2 > 0;
|
||||||
|
if (hasError1 && hasError2)
|
||||||
|
{
|
||||||
|
if (ctType == invokeType)
|
||||||
|
{
|
||||||
|
SereinEnv.WriteLine(InfoType.WARN, $"起始节点已与目标节点存在连接。" +
|
||||||
|
$"{Environment.NewLine}起始节点:{fromNode.Guid}" +
|
||||||
|
$"{Environment.NewLine}目标节点:{toNode.Guid}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
isOverwriting = true; // 需要移除连接再创建连接
|
||||||
|
overwritingCt = ctType;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 检查是否可能存在异常
|
||||||
|
if (!hasError1 && hasError2)
|
||||||
|
{
|
||||||
|
SereinEnv.WriteLine(InfoType.ERROR, $"起始节点不是目标节点的父节点,目标节点却是起始节点的子节点。" +
|
||||||
|
$"{Environment.NewLine}起始节点:{fromNode.Guid}" +
|
||||||
|
$"{Environment.NewLine}目标节点:{toNode.Guid}");
|
||||||
|
isPass = false;
|
||||||
|
}
|
||||||
|
else if (hasError1 && !hasError2)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
SereinEnv.WriteLine(InfoType.ERROR, $"起始节点不是目标节点的父节点,目标节点却是起始节点的子节点。" +
|
||||||
|
$"{Environment.NewLine}起始节点:{fromNode.Guid}" +
|
||||||
|
$"{Environment.NewLine}目标节点:{toNode.Guid}" +
|
||||||
|
$"");
|
||||||
|
isPass = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
isPass = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
if (isPass)
|
||||||
|
{
|
||||||
|
if (isOverwriting) // 需要替换
|
||||||
|
{
|
||||||
|
fromNode.SuccessorNodes[overwritingCt].Remove(toNode); // 从起始节点原有类别的子分支中移除
|
||||||
|
toNode.PreviousNodes[overwritingCt].Remove(fromNode); // 从目标节点原有类别的父分支中移除
|
||||||
|
}
|
||||||
|
fromNode.SuccessorNodes[invokeType].Add(toNode); // 添加到起始节点新类别的子分支
|
||||||
|
toNode.PreviousNodes[invokeType].Add(fromNode); // 添加到目标节点新类别的父分支
|
||||||
|
flowEnvironmentEvent.OnNodeConnectChanged(
|
||||||
|
new NodeConnectChangeEventArgs(
|
||||||
|
FlowCanvas.Guid,
|
||||||
|
fromNode.Guid, // 从哪个节点开始
|
||||||
|
toNode.Guid, // 连接到那个节点
|
||||||
|
JunctionOfConnectionType.Invoke,
|
||||||
|
invokeType, // 连接线的样式类型
|
||||||
|
NodeConnectChangeEventArgs.ConnectChangeType.Create // 是创建连接还是删除连接
|
||||||
|
));
|
||||||
|
// Invoke
|
||||||
|
// GetResult
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 移除方法调用关系
|
||||||
|
/// </summary>
|
||||||
|
private bool RemoveInvokeConnection()
|
||||||
|
{
|
||||||
|
FromNode.SuccessorNodes[ConnectionInvokeType].Remove(ToNode);
|
||||||
|
ToNode.PreviousNodes[ConnectionInvokeType].Remove(FromNode);
|
||||||
|
|
||||||
|
flowEnvironmentEvent.OnNodeConnectChanged(
|
||||||
|
new NodeConnectChangeEventArgs(
|
||||||
|
FlowCanvas.Guid,
|
||||||
|
FromNode.Guid,
|
||||||
|
ToNode.Guid,
|
||||||
|
JunctionOfConnectionType.Invoke,
|
||||||
|
ConnectionInvokeType,
|
||||||
|
NodeConnectChangeEventArgs.ConnectChangeType.Remove));
|
||||||
|
|
||||||
|
|
||||||
|
/* if (string.IsNullOrEmpty(ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceNodeGuid))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
toNode.MethodDetails.ParameterDetailss[argIndex].ArgDataSourceNodeGuid = null;
|
||||||
|
toNode.MethodDetails.ParameterDetailss[argIndex].ArgDataSourceType = ConnectionArgSourceType.GetPreviousNodeData; // 恢复默认值
|
||||||
|
|
||||||
|
if (OperatingSystem.IsWindows())
|
||||||
|
{
|
||||||
|
UIContextOperation?.Invoke(() => Event.OnNodeConnectChanged(
|
||||||
|
new NodeConnectChangeEventArgs(
|
||||||
|
canvasGuid,
|
||||||
|
fromNode.Guid,
|
||||||
|
toNode.Guid,
|
||||||
|
argIndex,
|
||||||
|
JunctionOfConnectionType.Arg,
|
||||||
|
ConnectionArgSourceType.GetPreviousNodeData,
|
||||||
|
NodeConnectChangeEventArgs.ConnectChangeType.Remove)));
|
||||||
|
}*/
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建参数连接关系
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="Exception"></exception>
|
||||||
|
private bool CreateArgConnection()
|
||||||
|
{
|
||||||
|
IFlowNode fromNodeControl = ToNode;
|
||||||
|
IFlowNode toNodeControl = ToNode;
|
||||||
|
ConnectionArgSourceType type = ConnectionArgSourceType;
|
||||||
|
int index = ArgIndex;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var toNodeArgSourceGuid = ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceNodeGuid; // 目标节点对应参数可能已经有其它连接
|
||||||
|
var toNodeArgSourceType = ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceType;
|
||||||
|
|
||||||
|
if (FromNode.Guid == toNodeArgSourceGuid
|
||||||
|
&& toNodeArgSourceType == ConnectionArgSourceType)
|
||||||
|
{
|
||||||
|
SereinEnv.WriteLine(InfoType.INFO, $"节点之间已建立过连接关系,此次操作将不会执行" +
|
||||||
|
$"起始节点:{FromNode.Guid}" +
|
||||||
|
$"目标节点:{ToNode.Guid}" +
|
||||||
|
$"参数索引:{ArgIndex}" +
|
||||||
|
$"参数类型:{ConnectionArgSourceType}");
|
||||||
|
/*flowEnvironmentEvent.OnNodeConnectChanged(
|
||||||
|
new NodeConnectChangeEventArgs(
|
||||||
|
FlowCanvas.Guid,
|
||||||
|
FromNode.Guid, // 从哪个节点开始
|
||||||
|
ToNode.Guid, // 连接到那个节点
|
||||||
|
ArgIndex, // 连接线的样式类型
|
||||||
|
JunctionOfConnectionType.Arg,
|
||||||
|
ConnectionArgSourceType,
|
||||||
|
NodeConnectChangeEventArgs.ConnectChangeType.Create // 是创建连接还是删除连接
|
||||||
|
)); // 通知UI */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(toNodeArgSourceGuid)) // 更改关系获取
|
||||||
|
{
|
||||||
|
ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceNodeGuid = null;
|
||||||
|
ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceType = ConnectionArgSourceType.GetPreviousNodeData; // 恢复默认值
|
||||||
|
flowEnvironmentEvent.OnNodeConnectChanged(
|
||||||
|
new NodeConnectChangeEventArgs(
|
||||||
|
FlowCanvas.Guid,
|
||||||
|
FromNode.Guid,
|
||||||
|
ToNode.Guid,
|
||||||
|
ArgIndex,
|
||||||
|
JunctionOfConnectionType.Arg,
|
||||||
|
ConnectionArgSourceType.GetPreviousNodeData,
|
||||||
|
NodeConnectChangeEventArgs.ConnectChangeType.Remove));
|
||||||
|
}
|
||||||
|
|
||||||
|
ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceNodeGuid = FromNode.Guid; // 设置
|
||||||
|
ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceType = ConnectionArgSourceType;
|
||||||
|
|
||||||
|
flowEnvironmentEvent.OnNodeConnectChanged(
|
||||||
|
new NodeConnectChangeEventArgs(
|
||||||
|
FlowCanvas.Guid,
|
||||||
|
FromNode.Guid, // 从哪个节点开始
|
||||||
|
ToNode.Guid, // 连接到那个节点
|
||||||
|
ArgIndex, // 连接线的样式类型
|
||||||
|
JunctionOfConnectionType.Arg,
|
||||||
|
ConnectionArgSourceType,
|
||||||
|
NodeConnectChangeEventArgs.ConnectChangeType.Create // 是创建连接还是删除连接
|
||||||
|
)); // 通知UI
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 移除参数连接关系
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fromNodeControl"></param>
|
||||||
|
/// <param name="toNodeControl"></param>
|
||||||
|
/// <param name="index"></param>
|
||||||
|
private bool RemoveArgConnection()
|
||||||
|
{
|
||||||
|
ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceNodeGuid = null;
|
||||||
|
ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceType = ConnectionArgSourceType.GetPreviousNodeData; // 恢复默认值
|
||||||
|
|
||||||
|
if (OperatingSystem.IsWindows())
|
||||||
|
{
|
||||||
|
flowEnvironmentEvent.OnNodeConnectChanged(
|
||||||
|
new NodeConnectChangeEventArgs(
|
||||||
|
FlowCanvas.Guid,
|
||||||
|
FromNode.Guid,
|
||||||
|
ToNode.Guid,
|
||||||
|
ArgIndex,
|
||||||
|
JunctionOfConnectionType.Arg,
|
||||||
|
ConnectionArgSourceType.GetPreviousNodeData,
|
||||||
|
NodeConnectChangeEventArgs.ConnectChangeType.Remove));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 检查连接是否合法
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fromNode">发起连接的起始节点</param>
|
||||||
|
/// <param name="toNode">要连接的目标节点</param>
|
||||||
|
/// <param name="fromNodeJunctionType">发起连接节点的控制点类型</param>
|
||||||
|
/// <param name="toNodeJunctionType">被连接节点的控制点类型</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
90
NodeFlow/Model/Operation/ChangeParameterOperation.cs
Normal file
90
NodeFlow/Model/Operation/ChangeParameterOperation.cs
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
using Microsoft.CodeAnalysis;
|
||||||
|
using Serein.Library.Api;
|
||||||
|
using Serein.NodeFlow.Services;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Serein.NodeFlow.Model.Operation
|
||||||
|
{
|
||||||
|
internal class ChangeParameterOperation : OperationBase
|
||||||
|
{
|
||||||
|
public override string Theme => nameof(ChangeParameterOperation);
|
||||||
|
|
||||||
|
public string NodeGuid { get; set; }
|
||||||
|
public bool IsAdd{ get; set; }
|
||||||
|
|
||||||
|
public int ParamIndex { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
private IFlowNode nodeModel;
|
||||||
|
|
||||||
|
|
||||||
|
public override bool ValidationParameter()
|
||||||
|
{
|
||||||
|
if (!flowModelService.TryGetNodeModel(NodeGuid, out var nodeModel))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.nodeModel = nodeModel;
|
||||||
|
|
||||||
|
var pds = nodeModel.MethodDetails.ParameterDetailss;
|
||||||
|
var parameterCount = pds.Length;
|
||||||
|
if (ParamIndex >= parameterCount)
|
||||||
|
{
|
||||||
|
return false; // 需要被添加的下标索引大于入参数组的长度
|
||||||
|
}
|
||||||
|
if (IsAdd)
|
||||||
|
{
|
||||||
|
if (pds[ParamIndex].IsParams == false)
|
||||||
|
{
|
||||||
|
return false; // 对应的入参并非可选参数中的一部分
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override bool Execute()
|
||||||
|
{
|
||||||
|
if (!ValidationParameter()) return false;
|
||||||
|
|
||||||
|
if (IsAdd)
|
||||||
|
{
|
||||||
|
if (nodeModel.MethodDetails.AddParamsArg(ParamIndex))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (nodeModel.MethodDetails.RemoveParamsArg(ParamIndex))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ToInfo()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
98
NodeFlow/Model/Operation/ContainerPlaceNodeOperation.cs
Normal file
98
NodeFlow/Model/Operation/ContainerPlaceNodeOperation.cs
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
using Serein.Library.Api;
|
||||||
|
using Serein.NodeFlow.Services;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Serein.NodeFlow.Model.Operation
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 放置节点操作
|
||||||
|
/// </summary>
|
||||||
|
internal class ContainerPlaceNodeOperation : OperationBase
|
||||||
|
{
|
||||||
|
public override string Theme => nameof(ContainerPlaceNodeOperation);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 所在画布
|
||||||
|
/// </summary>
|
||||||
|
public string CanvasGuid { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 子节点,该数据为此次事件的主节点
|
||||||
|
/// </summary>
|
||||||
|
public string NodeGuid { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 父节点
|
||||||
|
/// </summary>
|
||||||
|
public string ContainerNodeGuid { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 父节点
|
||||||
|
/// </summary>
|
||||||
|
private INodeContainer ContainerNode;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 子节点,该数据为此次事件的主节点
|
||||||
|
/// </summary>
|
||||||
|
private IFlowNode Node;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public override bool ValidationParameter()
|
||||||
|
{
|
||||||
|
if (!flowModelService.ContainsCanvasModel(CanvasGuid))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 获取目标节点与容器节点
|
||||||
|
if (!flowModelService.TryGetNodeModel(NodeGuid, out var nodeModel))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!flowModelService.TryGetNodeModel(ContainerNodeGuid, out var containerNode))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (nodeModel.ContainerNode is INodeContainer tmpContainer)
|
||||||
|
{
|
||||||
|
//SereinEnv.WriteLine(InfoType.WARN, $"节点放置失败,节点[{nodeGuid}]已经放置于容器节点[{((IFlowNode)tmpContainer).Guid}]");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(containerNode is not INodeContainer containerNode2)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node = nodeModel;
|
||||||
|
ContainerNode = containerNode2;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Execute()
|
||||||
|
{
|
||||||
|
if (!ValidationParameter()) return false;
|
||||||
|
|
||||||
|
ContainerNode.PlaceNode(Node);
|
||||||
|
flowEnvironmentEvent.OnNodePlace(new NodePlaceEventArgs(CanvasGuid, NodeGuid, ContainerNodeGuid)); // 通知UI更改节点放置位置
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Undo()
|
||||||
|
{
|
||||||
|
ContainerNode.TakeOutNode(Node);
|
||||||
|
flowEnvironmentEvent.OnNodeTakeOut(new NodeTakeOutEventArgs(CanvasGuid, NodeGuid)); // 重新放置在画布上
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override void ToInfo()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
89
NodeFlow/Model/Operation/ContainerTakeOutNodeOperation.cs
Normal file
89
NodeFlow/Model/Operation/ContainerTakeOutNodeOperation.cs
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
using Serein.Library.Api;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Serein.NodeFlow.Model.Operation
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 取出节点操作
|
||||||
|
/// </summary>
|
||||||
|
internal class ContainerTakeOutNodeOperation : OperationBase
|
||||||
|
{
|
||||||
|
public override string Theme => nameof(ContainerTakeOutNodeOperation);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 所在画布
|
||||||
|
/// </summary>
|
||||||
|
public string CanvasGuid { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 子节点,该数据为此次事件的主节点
|
||||||
|
/// </summary>
|
||||||
|
public string NodeGuid { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 父节点
|
||||||
|
/// </summary>
|
||||||
|
private INodeContainer ContainerNode;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 子节点,该数据为此次事件的主节点
|
||||||
|
/// </summary>
|
||||||
|
private IFlowNode Node;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public override bool ValidationParameter()
|
||||||
|
{
|
||||||
|
if (!flowModelService.ContainsCanvasModel(CanvasGuid))
|
||||||
|
{
|
||||||
|
flowEnvironment.WriteLine(Library.InfoType.INFO, $"节点取出失败,目标画布不存在[{NodeGuid}]");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 获取目标节点与容器节点
|
||||||
|
if (!flowModelService.TryGetNodeModel(NodeGuid, out var nodeModel))
|
||||||
|
{
|
||||||
|
flowEnvironment.WriteLine(Library.InfoType.INFO, $"节点取出失败,目标节点不存在[{NodeGuid}]");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (nodeModel.ContainerNode is not INodeContainer containerNode)
|
||||||
|
{
|
||||||
|
flowEnvironment.WriteLine(Library.InfoType.INFO, $"节点取出失败,节点并非容器节点[{nodeModel.Guid}]");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Node = nodeModel;
|
||||||
|
ContainerNode = containerNode;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Execute()
|
||||||
|
{
|
||||||
|
if (!ValidationParameter()) return false;
|
||||||
|
|
||||||
|
ContainerNode.TakeOutNode(Node);
|
||||||
|
flowEnvironmentEvent.OnNodeTakeOut(new NodeTakeOutEventArgs(CanvasGuid, NodeGuid)); // 重新放置在画布上
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Undo()
|
||||||
|
{
|
||||||
|
ContainerNode.PlaceNode(Node);
|
||||||
|
if (ContainerNode is IFlowNode containerFlowNode)
|
||||||
|
{
|
||||||
|
flowEnvironmentEvent.OnNodePlace(new NodePlaceEventArgs(CanvasGuid, NodeGuid, containerFlowNode.Guid)); // 通知UI更改节点放置位置
|
||||||
|
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override void ToInfo()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
51
NodeFlow/Model/Operation/CreateCanvasOperation.cs
Normal file
51
NodeFlow/Model/Operation/CreateCanvasOperation.cs
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
using Serein.Library;
|
||||||
|
using Serein.Library.Api;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Serein.NodeFlow.Model.Operation
|
||||||
|
{
|
||||||
|
internal class CreateCanvasOperation : OperationBase
|
||||||
|
{
|
||||||
|
public override string Theme => nameof(CreateCanvasOperation);
|
||||||
|
public override bool IsCanUndo => false;
|
||||||
|
|
||||||
|
public required FlowCanvasDetailsInfo CanvasInfo { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private FlowCanvasDetails? flowCanvasDetails;
|
||||||
|
|
||||||
|
public override bool ValidationParameter()
|
||||||
|
{
|
||||||
|
if (CanvasInfo is null)
|
||||||
|
return false; // 没有必须的参数
|
||||||
|
if (string.IsNullOrEmpty(CanvasInfo.Guid))
|
||||||
|
return false; // 不能没有Guid
|
||||||
|
if(flowModelService.ContainsCanvasModel(CanvasInfo.Guid))
|
||||||
|
return false; // 画布已存在
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Execute()
|
||||||
|
{
|
||||||
|
if(!ValidationParameter()) return false;
|
||||||
|
|
||||||
|
var cavasnModel = new FlowCanvasDetails(flowEnvironment);
|
||||||
|
cavasnModel.LoadInfo(CanvasInfo);
|
||||||
|
flowModelService.AddCanvasModel(cavasnModel);
|
||||||
|
this.flowCanvasDetails = cavasnModel; ;
|
||||||
|
flowEnvironmentEvent.OnCanvasCreated(new CanvasCreateEventArgs(cavasnModel));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ToInfo()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
145
NodeFlow/Model/Operation/CreateNodeOperation.cs
Normal file
145
NodeFlow/Model/Operation/CreateNodeOperation.cs
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
using Serein.Library;
|
||||||
|
using Serein.Library.Api;
|
||||||
|
using Serein.NodeFlow.Model.Node;
|
||||||
|
using Serein.NodeFlow.Services;
|
||||||
|
using Serein.NodeFlow.Tool;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Serein.NodeFlow.Model.Operation
|
||||||
|
{
|
||||||
|
internal class CreateNodeOperation : OperationBase
|
||||||
|
{
|
||||||
|
public override string Theme => nameof(CreateNodeOperation);
|
||||||
|
|
||||||
|
|
||||||
|
public required string CanvasGuid { get; set; }
|
||||||
|
public required NodeControlType NodeControlType { get; set; }
|
||||||
|
public required PositionOfUI Position { get; set; }
|
||||||
|
public required MethodDetailsInfo? MethodDetailsInfo { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否为基础节点
|
||||||
|
/// </summary>
|
||||||
|
private bool IsBaseNode => NodeControlType.IsBaseNode();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 执行成功后所创建的节点
|
||||||
|
/// </summary>
|
||||||
|
private IFlowNode? flowNode;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 节点所在画布
|
||||||
|
/// </summary>
|
||||||
|
private FlowCanvasDetails flowCanvasDetails;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public override bool ValidationParameter()
|
||||||
|
{
|
||||||
|
// 检查是否存在画布
|
||||||
|
|
||||||
|
var canvasModel = flowModelService.GetCanvasModel(CanvasGuid);
|
||||||
|
if(canvasModel is null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 检查类型(防非预期的调用)
|
||||||
|
if (NodeControlType == NodeControlType.None)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 检查放置位置是否超限(防非预期的调用)
|
||||||
|
if (Position.X < 0 || Position.Y < 0
|
||||||
|
|| Position.X > canvasModel.Width
|
||||||
|
|| Position.Y > canvasModel.Height)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 所创建的节点并非基础节点,却没有传入方法信息,将会导致创建失败
|
||||||
|
if (!IsBaseNode && MethodDetailsInfo is null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 缓存画布model,提高性能
|
||||||
|
this.flowCanvasDetails = canvasModel;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Execute()
|
||||||
|
{
|
||||||
|
if (!ValidationParameter()) return false; // 执行时验证
|
||||||
|
|
||||||
|
IFlowNode? nodeModel;
|
||||||
|
if (IsBaseNode)
|
||||||
|
{
|
||||||
|
nodeModel = FlowNodeExtension.CreateNode(flowEnvironment, NodeControlType); // 加载基础节点
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(MethodDetailsInfo is null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
//throw new InvalidOperationException($"无法创建节点,因为MethodDetailsInfo属性为null");
|
||||||
|
}
|
||||||
|
if (!flowLibraryManagement.TryGetMethodDetails(MethodDetailsInfo.AssemblyName, // 创建节点
|
||||||
|
MethodDetailsInfo.MethodName,
|
||||||
|
out var methodDetails))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
//throw new InvalidOperationException($"无法创建节点,因为没有找到{MethodDetailsInfo.AssemblyName}.{MethodDetailsInfo.MethodName}方法,请检查是否已加载对应程序集");
|
||||||
|
}
|
||||||
|
nodeModel = FlowNodeExtension.CreateNode(flowEnvironment, NodeControlType, methodDetails); // 一般的加载节点方法
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeModel.Guid ??= Guid.NewGuid().ToString();
|
||||||
|
nodeModel.Position = Position; // 设置位置
|
||||||
|
|
||||||
|
// 节点与画布互相绑定
|
||||||
|
nodeModel.CanvasDetails = flowCanvasDetails;
|
||||||
|
flowCanvasDetails.Nodes.Add(nodeModel);
|
||||||
|
|
||||||
|
flowModelService.AddNodeModel(nodeModel);
|
||||||
|
this.flowNode = nodeModel;
|
||||||
|
flowEnvironmentEvent.OnNodeCreated(new NodeCreateEventArgs(flowCanvasDetails.Guid, nodeModel, Position));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override bool Undo()
|
||||||
|
{
|
||||||
|
if (!ValidationParameter()) return false; // 撤销时验证
|
||||||
|
if(flowNode is null) return false; // 没有创建过节点
|
||||||
|
var canvasGuid = flowCanvasDetails.Guid;
|
||||||
|
var nodeGuid = flowNode.Guid;
|
||||||
|
flowEnvironment.RemoveNode(canvasGuid, nodeGuid);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override void ToInfo()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*private bool TryAddNode(IFlowNode nodeModel)
|
||||||
|
{
|
||||||
|
nodeModel.Guid ??= Guid.NewGuid().ToString();
|
||||||
|
NodeModels.TryAdd(nodeModel.Guid, nodeModel);
|
||||||
|
|
||||||
|
|
||||||
|
// 如果是触发器,则需要添加到专属集合中
|
||||||
|
if (nodeModel is SingleFlipflopNode flipflopNode)
|
||||||
|
{
|
||||||
|
var guid = flipflopNode.Guid;
|
||||||
|
if (!FlipflopNodes.Exists(it => it.Guid.Equals(guid)))
|
||||||
|
{
|
||||||
|
FlipflopNodes.Add(flipflopNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,92 +1,118 @@
|
|||||||
using System;
|
using Serein.Library;
|
||||||
|
using Serein.Library.Api;
|
||||||
|
using Serein.NodeFlow.Services;
|
||||||
|
using Serein.NodeFlow.Tool;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Serein.NodeFlow.Model.Operation
|
namespace Serein.NodeFlow.Model.Operation
|
||||||
{
|
{
|
||||||
|
internal interface IOperation
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 用于判断是否可以撤销
|
||||||
|
/// </summary>
|
||||||
|
bool IsCanUndo { get; }
|
||||||
|
/// <summary>
|
||||||
|
/// 执行操作前验证数据
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
bool ValidationParameter();
|
||||||
|
/// <summary>
|
||||||
|
/// 执行操作
|
||||||
|
/// </summary>
|
||||||
|
bool Execute();
|
||||||
|
/// <summary>
|
||||||
|
/// 撤销操作
|
||||||
|
/// </summary>
|
||||||
|
bool Undo();
|
||||||
|
}
|
||||||
|
|
||||||
class Test {
|
internal abstract class OperationBase : IOperation
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 运行环境
|
||||||
|
/// </summary>
|
||||||
|
[AutoInjection]
|
||||||
|
protected IFlowEnvironment flowEnvironment;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 撤销栈
|
/// 节点管理服务
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private Stack<IOperation> undoStack = [];
|
[AutoInjection]
|
||||||
|
protected FlowModelService flowModelService;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 重做栈
|
/// 流程依赖服务
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private Stack<IOperation> redoStack = [];
|
[AutoInjection]
|
||||||
|
protected FlowLibraryManagement flowLibraryManagement;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 流程事件服务
|
||||||
|
/// </summary>
|
||||||
|
[AutoInjection]
|
||||||
|
protected IFlowEnvironmentEvent flowEnvironmentEvent;
|
||||||
|
|
||||||
|
public abstract string Theme { get;}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否支持特效
|
||||||
|
/// </summary>
|
||||||
|
public virtual bool IsCanUndo => true;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/// <summary>
|
||||||
// 执行新命令时,将命令推入撤销栈,并清空重做栈
|
/// 验证参数
|
||||||
undoStack.Push(operation);
|
/// </summary>
|
||||||
redoStack.Clear();
|
/// <returns></returns>
|
||||||
*/
|
public abstract bool ValidationParameter();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 执行
|
||||||
|
/// </summary>
|
||||||
|
public abstract bool Execute();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 撤销
|
/// 撤销
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Undo()
|
public virtual bool Undo()
|
||||||
{
|
{
|
||||||
if (undoStack.Count > 0)
|
if (!IsCanUndo)
|
||||||
{
|
{
|
||||||
var command = undoStack.Pop();
|
Debug.WriteLine($"该操作暂未提供撤销功能[{Theme}]");
|
||||||
command.Undo(); // 执行撤销
|
return false;
|
||||||
redoStack.Push(command); // 将撤销的命令推入重做栈
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 重做
|
/// 导出操作信息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Redo()
|
public abstract void ToInfo();
|
||||||
{
|
|
||||||
if (redoStack.Count > 0)
|
|
||||||
{
|
|
||||||
var command = redoStack.Pop();
|
|
||||||
command.Execute();
|
|
||||||
undoStack.Push(command); // 将重做的命令推入撤销栈
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
internal class OperationInfo
|
internal class OperationInfo
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal abstract class OperationBase : IOperation
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 操作的主题
|
|
||||||
/// </summary>
|
|
||||||
public required string Theme { get; set; }
|
|
||||||
|
|
||||||
public abstract void Execute();
|
class Test {
|
||||||
public abstract void Undo();
|
|
||||||
public abstract void ToInfo();
|
|
||||||
|
|
||||||
protected OperationBase()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
protected OperationBase(OperationInfo info)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal interface IOperation
|
|
||||||
{
|
|
||||||
void Execute(); // 执行操作
|
|
||||||
void Undo(); // 撤销操作
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
59
NodeFlow/Model/Operation/RemoveCanvasOperation.cs
Normal file
59
NodeFlow/Model/Operation/RemoveCanvasOperation.cs
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
using Serein.Library;
|
||||||
|
using Serein.Library.Api;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Serein.NodeFlow.Model.Operation
|
||||||
|
{
|
||||||
|
internal class RemoveCanvasOperation : OperationBase
|
||||||
|
{
|
||||||
|
public override string Theme => nameof(RemoveCanvasOperation);
|
||||||
|
public override bool IsCanUndo => false;
|
||||||
|
public required string CanvasGuid { get; set; }
|
||||||
|
|
||||||
|
private FlowCanvasDetailsInfo? flowCanvasDetailsInfo;
|
||||||
|
private FlowCanvasDetails? flowCanvasDetails;
|
||||||
|
|
||||||
|
public override bool ValidationParameter()
|
||||||
|
{
|
||||||
|
var canvasModel = flowModelService.GetCanvasModel(CanvasGuid);
|
||||||
|
if (canvasModel is null) return false; // 画布不存在
|
||||||
|
var nodeCount = canvasModel.Nodes.Count;
|
||||||
|
if (nodeCount > 0)
|
||||||
|
{
|
||||||
|
SereinEnv.WriteLine(InfoType.WARN, "无法删除具有节点的画布");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.flowCanvasDetails = canvasModel;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Execute()
|
||||||
|
{
|
||||||
|
if (!ValidationParameter()) return false;
|
||||||
|
|
||||||
|
if (flowCanvasDetails is null)
|
||||||
|
{
|
||||||
|
// 验证过画布存在,但这时画布不存在了
|
||||||
|
// 考虑到多线程操作影响,一般不会进入这个逻辑分支
|
||||||
|
var canvasModel = flowModelService.GetCanvasModel(CanvasGuid);
|
||||||
|
if (canvasModel is null) return false; // 画布不存在
|
||||||
|
flowCanvasDetails = canvasModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
flowModelService.RemoveCanvasModel(flowCanvasDetails);
|
||||||
|
flowCanvasDetailsInfo = flowCanvasDetails.ToInfo();
|
||||||
|
flowEnvironmentEvent.OnCanvasRemoved(new CanvasRemoveEventArgs(flowCanvasDetails.Guid));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ToInfo()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
216
NodeFlow/Model/Operation/RemoveNodeOperation.cs
Normal file
216
NodeFlow/Model/Operation/RemoveNodeOperation.cs
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
|
using Serein.Library;
|
||||||
|
using Serein.Library.Api;
|
||||||
|
using Serein.Script.Node;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data.Common;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection.Metadata;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Serein.NodeFlow.Model.Operation
|
||||||
|
{
|
||||||
|
internal class RemoveNodeOperation : OperationBase
|
||||||
|
{
|
||||||
|
public override string Theme => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public required string CanvasGuid { get; internal set; }
|
||||||
|
public required string NodeGuid { get; internal set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 节点所在画布
|
||||||
|
/// </summary>
|
||||||
|
private FlowCanvasDetails flowCanvasDetails;
|
||||||
|
/// <summary>
|
||||||
|
/// 被删除的节点
|
||||||
|
/// </summary>
|
||||||
|
private IFlowNode flowNode;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 移除节点时删除连线所触发的事件参数的缓存
|
||||||
|
/// </summary>
|
||||||
|
private List<NodeConnectChangeEventArgs> EventArgs { get; } = new List<NodeConnectChangeEventArgs>();
|
||||||
|
|
||||||
|
public override bool ValidationParameter()
|
||||||
|
{
|
||||||
|
var canvasModel = flowModelService.GetCanvasModel(CanvasGuid);
|
||||||
|
var nodeModel = flowModelService.GetNodeModel(NodeGuid);
|
||||||
|
if(canvasModel is null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(nodeModel is null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
flowCanvasDetails = canvasModel;
|
||||||
|
flowNode = nodeModel;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Execute()
|
||||||
|
{
|
||||||
|
if (!ValidationParameter()) return false;
|
||||||
|
|
||||||
|
// 需要移除对应的方法调用、以及参数获取调用
|
||||||
|
// 还需要记录移除的事件参数,用以撤销恢复
|
||||||
|
|
||||||
|
#region 移除方法调用关系
|
||||||
|
foreach (var item in flowNode.PreviousNodes)
|
||||||
|
{
|
||||||
|
|
||||||
|
var connectionType = item.Key; // 连接类型
|
||||||
|
var previousNodes = item.Value; // 对应类型的父节点集合
|
||||||
|
foreach (IFlowNode previousNode in previousNodes)
|
||||||
|
{
|
||||||
|
previousNode.SuccessorNodes[connectionType].Remove(flowNode);
|
||||||
|
var e = new NodeConnectChangeEventArgs(
|
||||||
|
CanvasGuid, // 画布
|
||||||
|
previousNode.Guid, // 父节点Guid
|
||||||
|
flowNode.Guid, // 被移除的节点Guid
|
||||||
|
JunctionOfConnectionType.Invoke, // 方法调用关系
|
||||||
|
connectionType, // 对应的连接关系
|
||||||
|
NodeConnectChangeEventArgs.ConnectChangeType.Remove); // 移除连线
|
||||||
|
EventArgs.Add(e); // 缓存事件参数
|
||||||
|
flowEnvironmentEvent.OnNodeConnectChanged(e);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flowNode.ControlType == NodeControlType.FlowCall)
|
||||||
|
{
|
||||||
|
// 根据流程接口节点目前的设计,暂未支持能连接下一个节点
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 遍历所有后继节点,从那些后继节点中的前置节点集合中移除该节点
|
||||||
|
foreach (var item in flowNode.SuccessorNodes)
|
||||||
|
{
|
||||||
|
|
||||||
|
var connectionType = item.Key; // 方法调用连接类型
|
||||||
|
var successorNodes = item.Value; // 对应类型的父节点集合
|
||||||
|
foreach (IFlowNode successorNode in successorNodes)
|
||||||
|
{
|
||||||
|
successorNode.SuccessorNodes[connectionType].Remove(flowNode);
|
||||||
|
var e = new NodeConnectChangeEventArgs(
|
||||||
|
CanvasGuid, // 画布
|
||||||
|
flowNode.Guid, // 被移除的节点Guid
|
||||||
|
successorNode.Guid, // 子节点Guid
|
||||||
|
JunctionOfConnectionType.Invoke, // 方法调用关系
|
||||||
|
connectionType, // 对应的连接关系
|
||||||
|
NodeConnectChangeEventArgs.ConnectChangeType.Remove); // 移除连线
|
||||||
|
EventArgs.Add(e); // 缓存事件参数
|
||||||
|
flowEnvironmentEvent.OnNodeConnectChanged(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 移除参数获取关系
|
||||||
|
// 需要找到有哪些节点的入参参数,被设置为了该节点,然后将其删除
|
||||||
|
// 因为节点自身没有记录哪些节点选取了自己作为参数来源节点,所以需要遍历所有节点
|
||||||
|
|
||||||
|
foreach (var item in flowNode.NeedResultNodes)
|
||||||
|
{
|
||||||
|
var connectionType = item.Key; // 参数来源连接类型
|
||||||
|
var argNodes = item.Value; // 对应类型的入参需求节点集合
|
||||||
|
foreach (var argNode in argNodes)
|
||||||
|
{
|
||||||
|
var md = argNode.MethodDetails;
|
||||||
|
if (md is null) continue;
|
||||||
|
var pds = md.ParameterDetailss;
|
||||||
|
if (pds is null || pds.Length == 0) continue;
|
||||||
|
foreach(var parameter in pds)
|
||||||
|
{
|
||||||
|
if (!parameter.ArgDataSourceNodeGuid.Equals(flowNode.Guid)) continue;
|
||||||
|
// 找到了对应的入参控制点了
|
||||||
|
var e = new NodeConnectChangeEventArgs(
|
||||||
|
CanvasGuid, // 画布
|
||||||
|
flowNode.Guid, // 被移除的节点Guid
|
||||||
|
argNode.Guid, // 子节点Guid
|
||||||
|
parameter.Index, // 作用在第几个参数上,用于指示移除第几个参数的连线
|
||||||
|
JunctionOfConnectionType.Arg, // 指示移除的是参数连接线
|
||||||
|
connectionType, // 对应的连接关系
|
||||||
|
NodeConnectChangeEventArgs.ConnectChangeType.Remove); // 移除连线
|
||||||
|
EventArgs.Add(e); // 缓存事件参数
|
||||||
|
flowEnvironmentEvent.OnNodeConnectChanged(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
flowModelService.RemoveNodeModel(flowNode); // 从记录中移除
|
||||||
|
//flowNode.Remove(); // 调用节点的移除方法
|
||||||
|
|
||||||
|
if(flowEnvironment.UIContextOperation is null)
|
||||||
|
{
|
||||||
|
flowCanvasDetails?.Nodes.Remove(flowNode);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 存在UI上下文操作,当前运行环境极有可能运行在有UI线程的平台上
|
||||||
|
// 为了避免直接修改 ObservableCollection 集合导致异常产生,故而使用UI线程上下文操作运行
|
||||||
|
flowEnvironment.UIContextOperation?.Invoke(() =>
|
||||||
|
{
|
||||||
|
flowCanvasDetails?.Nodes.Remove(flowNode);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
flowEnvironmentEvent.OnNodeRemoved(new NodeRemoveEventArgs(CanvasGuid, NodeGuid));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Undo()
|
||||||
|
{
|
||||||
|
// 先恢复被删除的节点
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 撤销删除节点时,还需要恢复连线状态
|
||||||
|
foreach (NodeConnectChangeEventArgs e in EventArgs)
|
||||||
|
{
|
||||||
|
NodeConnectChangeEventArgs? newEventArgs = null;
|
||||||
|
if (e.JunctionOfConnectionType == JunctionOfConnectionType.Invoke)
|
||||||
|
{
|
||||||
|
newEventArgs = new NodeConnectChangeEventArgs(
|
||||||
|
e.CanvasGuid, // 画布
|
||||||
|
e.FromNodeGuid, // 被移除的节点Guid
|
||||||
|
e.ToNodeGuid, // 子节点Guid
|
||||||
|
e.JunctionOfConnectionType, // 指示需要恢复的是方法调用线
|
||||||
|
e.ConnectionInvokeType, // 对应的连接关系
|
||||||
|
NodeConnectChangeEventArgs.ConnectChangeType.Create); // 创建连线
|
||||||
|
}
|
||||||
|
else if (e.JunctionOfConnectionType == JunctionOfConnectionType.Arg)
|
||||||
|
{
|
||||||
|
newEventArgs = new NodeConnectChangeEventArgs(
|
||||||
|
e.CanvasGuid, // 画布
|
||||||
|
e.FromNodeGuid, // 被移除的节点Guid
|
||||||
|
e.ToNodeGuid, // 子节点Guid
|
||||||
|
e.ArgIndex, // 作用在第几个参数上,用于指示移除第几个参数的连线
|
||||||
|
e.JunctionOfConnectionType, // 指示需要恢复的是参数连接线
|
||||||
|
e.ConnectionArgSourceType, // 对应的连接关系
|
||||||
|
NodeConnectChangeEventArgs.ConnectChangeType.Create); // 创建连线
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
newEventArgs = null;
|
||||||
|
}
|
||||||
|
if (newEventArgs != null)
|
||||||
|
{
|
||||||
|
// 使用反转了的事件参数进行触发
|
||||||
|
flowEnvironmentEvent.OnNodeConnectChanged(newEventArgs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override void ToInfo()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
using Serein.Library;
|
||||||
|
using Serein.Library.Api;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Serein.NodeFlow.Model.Operation
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将调用顺序置为优先
|
||||||
|
/// </summary>
|
||||||
|
internal class SetConnectPriorityInvokeOperation : OperationBase
|
||||||
|
{
|
||||||
|
public override string Theme => nameof(SetConnectPriorityInvokeOperation);
|
||||||
|
|
||||||
|
public string FromNodeGuid { get; set; }
|
||||||
|
public string ToNodeGuid { get; set; }
|
||||||
|
public ConnectionInvokeType ConnectionType { get; set; }
|
||||||
|
|
||||||
|
private IFlowNode FromNode;
|
||||||
|
private IFlowNode ToNode;
|
||||||
|
private int lastIdx = -1;
|
||||||
|
|
||||||
|
public override bool ValidationParameter()
|
||||||
|
{
|
||||||
|
if (ConnectionType == ConnectionInvokeType.None)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 获取起始节点与目标节点
|
||||||
|
if (!flowModelService.TryGetNodeModel(FromNodeGuid, out var fromNode) || !flowModelService.TryGetNodeModel(ToNodeGuid, out var toNode))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (fromNode is null || toNode is null) return false;
|
||||||
|
|
||||||
|
FromNode = fromNode;
|
||||||
|
ToNode = toNode;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 成为首项
|
||||||
|
/// </summary>
|
||||||
|
public override bool Execute()
|
||||||
|
{
|
||||||
|
if(!ValidationParameter()) return false;
|
||||||
|
|
||||||
|
if (FromNode.SuccessorNodes.TryGetValue(ConnectionType, out var nodes))
|
||||||
|
{
|
||||||
|
var idx = nodes.IndexOf(ToNode);
|
||||||
|
if (idx > -1)
|
||||||
|
{
|
||||||
|
lastIdx = idx;
|
||||||
|
nodes.RemoveAt(idx);
|
||||||
|
nodes.Insert(0, ToNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 恢复原来的位置
|
||||||
|
/// </summary>
|
||||||
|
public override bool Undo()
|
||||||
|
{
|
||||||
|
if (FromNode.SuccessorNodes.TryGetValue(ConnectionType, out var nodes))
|
||||||
|
{
|
||||||
|
var idx = nodes.IndexOf(ToNode);
|
||||||
|
if (idx > -1)
|
||||||
|
{
|
||||||
|
nodes.RemoveAt(idx);
|
||||||
|
nodes.Insert(lastIdx, ToNode);
|
||||||
|
lastIdx = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ToInfo()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
78
NodeFlow/Model/Operation/SetStartNodeOperation.cs
Normal file
78
NodeFlow/Model/Operation/SetStartNodeOperation.cs
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
using Serein.Library;
|
||||||
|
using Serein.Library.Api;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Serein.NodeFlow.Model.Operation
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 设置起始节点
|
||||||
|
/// </summary>
|
||||||
|
internal class SetStartNodeOperation : OperationBase
|
||||||
|
{
|
||||||
|
public override string Theme => nameof(SetStartNodeOperation);
|
||||||
|
|
||||||
|
|
||||||
|
public string CanvasGuid { get; set; }
|
||||||
|
public string NewNodeGuid { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
private FlowCanvasDetails CanvasModel;
|
||||||
|
private IFlowNode NewStartNodeModel;
|
||||||
|
private IFlowNode? OldStartNodeModel;
|
||||||
|
|
||||||
|
|
||||||
|
public override bool ValidationParameter()
|
||||||
|
{
|
||||||
|
if (!flowModelService.TryGetCanvasModel(CanvasGuid, out CanvasModel)
|
||||||
|
|| !flowModelService.TryGetNodeModel(NewNodeGuid, out NewStartNodeModel))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public override bool Execute()
|
||||||
|
{
|
||||||
|
if (!ValidationParameter()) return false;
|
||||||
|
|
||||||
|
if (CanvasModel.StartNode is not null
|
||||||
|
&& flowModelService.TryGetNodeModel(CanvasModel.StartNode.Guid, out var flowNode))
|
||||||
|
{
|
||||||
|
OldStartNodeModel = flowNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
CanvasModel.StartNode = NewStartNodeModel;
|
||||||
|
flowEnvironmentEvent.OnStartNodeChanged(new StartNodeChangeEventArgs(CanvasModel.Guid, OldStartNodeModel?.Guid, NewStartNodeModel.Guid));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Undo()
|
||||||
|
{
|
||||||
|
if(OldStartNodeModel is null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
var newStartNode = OldStartNodeModel;
|
||||||
|
var oldStartNode = NewStartNodeModel;
|
||||||
|
|
||||||
|
NewStartNodeModel = newStartNode;
|
||||||
|
OldStartNodeModel = oldStartNode;
|
||||||
|
CanvasModel.StartNode = oldStartNode;
|
||||||
|
|
||||||
|
flowEnvironmentEvent.OnStartNodeChanged(new StartNodeChangeEventArgs(CanvasModel.Guid, oldStartNode?.Guid, newStartNode.Guid));
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override void ToInfo()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -40,6 +40,12 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Remove="ConnectionType.cs" />
|
<Compile Remove="ConnectionType.cs" />
|
||||||
<Compile Remove="DynamicContext.cs" />
|
<Compile Remove="DynamicContext.cs" />
|
||||||
|
<Compile Remove="Env\EnvMsgTheme.cs" />
|
||||||
|
<Compile Remove="Env\LocalFlowEnvironment_2.cs" />
|
||||||
|
<Compile Remove="Env\LocalFlowEnvironment_T.cs" />
|
||||||
|
<Compile Remove="Env\MsgControllerOfClient.cs" />
|
||||||
|
<Compile Remove="Env\MsgControllerOfServer.cs" />
|
||||||
|
<Compile Remove="Env\RemoteFlowEnvironment.cs" />
|
||||||
<Compile Remove="MethodDetails.cs" />
|
<Compile Remove="MethodDetails.cs" />
|
||||||
<Compile Remove="Model\CompositeConditionNode.cs" />
|
<Compile Remove="Model\CompositeConditionNode.cs" />
|
||||||
<Compile Remove="NodeStaticConfig.cs" />
|
<Compile Remove="NodeStaticConfig.cs" />
|
||||||
|
|||||||
99
NodeFlow/Services/FlowModelService.cs
Normal file
99
NodeFlow/Services/FlowModelService.cs
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
using Serein.Library;
|
||||||
|
using Serein.Library.Api;
|
||||||
|
using Serein.NodeFlow.Model.Node;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Serein.NodeFlow.Services
|
||||||
|
{
|
||||||
|
public class FlowModelService
|
||||||
|
{
|
||||||
|
private readonly IFlowEnvironment environment;
|
||||||
|
|
||||||
|
public FlowModelService(IFlowEnvironment environment)
|
||||||
|
{
|
||||||
|
this.environment = environment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 环境加载的节点集合
|
||||||
|
/// Node Guid - Node Model
|
||||||
|
/// </summary>
|
||||||
|
private Dictionary<string, IFlowNode> NodeModels { get; } = [];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 运行环境加载的画布集合
|
||||||
|
/// </summary>
|
||||||
|
private Dictionary<string, FlowCanvasDetails> FlowCanvass { get; } = [];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 存放触发器节点(运行时全部调用)
|
||||||
|
/// </summary>
|
||||||
|
private List<SingleFlipflopNode> FlipflopNodes { get; } = [];
|
||||||
|
|
||||||
|
public IFlowNode? GetNodeModel(string guid)
|
||||||
|
{
|
||||||
|
NodeModels.TryGetValue(guid, out var nodeModel);
|
||||||
|
return nodeModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FlowCanvasDetails? GetCanvasModel(string guid)
|
||||||
|
{
|
||||||
|
FlowCanvass.TryGetValue(guid, out var nodeModel);
|
||||||
|
return nodeModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetNodeModel(string guid,out IFlowNode flowNode)
|
||||||
|
{
|
||||||
|
return NodeModels.TryGetValue(guid, out flowNode!);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetCanvasModel(string guid,out FlowCanvasDetails flowCanvas)
|
||||||
|
{
|
||||||
|
return FlowCanvass.TryGetValue(guid, out flowCanvas!);;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public bool ContainsNodeModel(string guid)
|
||||||
|
{
|
||||||
|
return NodeModels.ContainsKey(guid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ContainsCanvasModel(string guid)
|
||||||
|
{
|
||||||
|
return FlowCanvass.ContainsKey(guid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool AddNodeModel(IFlowNode flowNode)
|
||||||
|
{
|
||||||
|
ArgumentNullException.ThrowIfNull(flowNode);
|
||||||
|
ArgumentNullException.ThrowIfNull(flowNode.Guid);
|
||||||
|
return NodeModels.TryAdd(flowNode.Guid, flowNode);
|
||||||
|
}
|
||||||
|
public bool AddCanvasModel(FlowCanvasDetails flowCanvasDetails)
|
||||||
|
{
|
||||||
|
ArgumentNullException.ThrowIfNull(flowCanvasDetails);
|
||||||
|
ArgumentNullException.ThrowIfNull(flowCanvasDetails.Guid);
|
||||||
|
return FlowCanvass.TryAdd(flowCanvasDetails.Guid, flowCanvasDetails);
|
||||||
|
}
|
||||||
|
public bool RemoveNodeModel(IFlowNode flowNode)
|
||||||
|
{
|
||||||
|
ArgumentNullException.ThrowIfNull(flowNode.Guid);
|
||||||
|
return NodeModels.Remove(flowNode.Guid);
|
||||||
|
}
|
||||||
|
public bool RemoveCanvasModel(FlowCanvasDetails flowCanvasDetails)
|
||||||
|
{
|
||||||
|
ArgumentNullException.ThrowIfNull(flowCanvasDetails.Guid);
|
||||||
|
return FlowCanvass.Remove(flowCanvasDetails.Guid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<IFlowNode> GetAllNodeModel() => [.. NodeModels.Values];
|
||||||
|
public List<FlowCanvasDetails> GetAllCanvasModel() => [.. FlowCanvass.Values];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
81
NodeFlow/Services/FlowOperationService.cs
Normal file
81
NodeFlow/Services/FlowOperationService.cs
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
using Serein.Library.Api;
|
||||||
|
using Serein.NodeFlow.Model.Operation;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Serein.NodeFlow.Services
|
||||||
|
{
|
||||||
|
public class FlowOperationService
|
||||||
|
{
|
||||||
|
private readonly ISereinIOC sereinIOC;
|
||||||
|
|
||||||
|
public FlowOperationService(ISereinIOC sereinIOC)
|
||||||
|
{
|
||||||
|
this.sereinIOC = sereinIOC;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 撤销栈
|
||||||
|
/// </summary>
|
||||||
|
private Stack<IOperation> undoStack = [];
|
||||||
|
/// <summary>
|
||||||
|
/// 重做栈
|
||||||
|
/// </summary>
|
||||||
|
private Stack<IOperation> redoStack = [];
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
// 执行新命令时,将命令推入撤销栈,并清空重做栈
|
||||||
|
*/
|
||||||
|
/// <summary>
|
||||||
|
/// 撤销
|
||||||
|
/// </summary>
|
||||||
|
public void Undo()
|
||||||
|
{
|
||||||
|
if (undoStack.Count > 0)
|
||||||
|
{
|
||||||
|
var command = undoStack.Pop();
|
||||||
|
var state = command.Undo(); // 执行撤销
|
||||||
|
if (state)
|
||||||
|
{
|
||||||
|
redoStack.Push(command); // 将撤销的命令推入重做栈
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 重做
|
||||||
|
/// </summary>
|
||||||
|
public void Redo()
|
||||||
|
{
|
||||||
|
if (redoStack.Count > 0)
|
||||||
|
{
|
||||||
|
var command = redoStack.Pop();
|
||||||
|
var state = command.Execute();
|
||||||
|
if (state)
|
||||||
|
{
|
||||||
|
undoStack.Push(command); // 将重做的命令推入撤销栈
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
internal void Execute(IOperation operation)
|
||||||
|
{
|
||||||
|
sereinIOC.InjectDependenciesProperty(operation); // 注入所需要的依赖
|
||||||
|
var state = operation.Execute();
|
||||||
|
if (state)
|
||||||
|
{
|
||||||
|
// 执行后,推入撤销栈,并清空重做栈
|
||||||
|
undoStack.Push(operation);
|
||||||
|
redoStack.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,14 +2,14 @@
|
|||||||
using Serein.Library;
|
using Serein.Library;
|
||||||
using Serein.Library.Api;
|
using Serein.Library.Api;
|
||||||
using Serein.Library.Utils;
|
using Serein.Library.Utils;
|
||||||
using Serein.NodeFlow.Model;
|
using Serein.NodeFlow.Model.Node;
|
||||||
using Serein.NodeFlow.Tool;
|
using Serein.NodeFlow.Tool;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Threading.Tasks.Dataflow;
|
using System.Threading.Tasks.Dataflow;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
|
|
||||||
namespace Serein.NodeFlow
|
namespace Serein.NodeFlow.Services
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 流程任务管理
|
/// 流程任务管理
|
||||||
@@ -201,8 +201,8 @@ namespace Serein.NodeFlow
|
|||||||
var pool = WorkOptions.FlowContextPool;
|
var pool = WorkOptions.FlowContextPool;
|
||||||
var ioc = WorkOptions.Environment.IOC;
|
var ioc = WorkOptions.Environment.IOC;
|
||||||
|
|
||||||
var fit = ioc.Get<FlowInterruptTool>();
|
// var fit = ioc.Get<FlowInterruptTool>();
|
||||||
fit.CancelAllTrigger(); // 取消所有中断
|
// fit.CancelAllTrigger(); // 取消所有中断
|
||||||
foreach (var md in mds) // 结束时
|
foreach (var md in mds) // 结束时
|
||||||
{
|
{
|
||||||
if (!env.TryGetDelegateDetails(md.AssemblyName, md.MethodName, out var dd)) // 流程运行初始化
|
if (!env.TryGetDelegateDetails(md.AssemblyName, md.MethodName, out var dd)) // 流程运行初始化
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Serein.NodeFlow.Services
|
|
||||||
{
|
|
||||||
internal class NodeService
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -40,7 +40,7 @@ namespace Serein.Workbench.Customs
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// FlowMethodInfoListBox.xaml 的交互逻辑
|
/// FlowMethodInfoListBox.xaml 的交互逻辑
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class FlowMethodInfoListBox : UserControl,System.ComponentModel.INotifyPropertyChanged
|
public partial class FlowMethodInfoListBox : UserControl, System.ComponentModel.INotifyPropertyChanged
|
||||||
{
|
{
|
||||||
private object viewMethodInfo;
|
private object viewMethodInfo;
|
||||||
public object ViewMethodInfo
|
public object ViewMethodInfo
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ namespace Serein.Workbench.Node.View
|
|||||||
this.MouseDown += ParamsArg_OnMouseDown; // 增加或删除
|
this.MouseDown += ParamsArg_OnMouseDown; // 增加或删除
|
||||||
this.MouseMove += ParamsArgControl_MouseMove;
|
this.MouseMove += ParamsArgControl_MouseMove;
|
||||||
this.MouseLeave += ParamsArgControl_MouseLeave;
|
this.MouseLeave += ParamsArgControl_MouseLeave;
|
||||||
AddOrRemoveParamsTask = AddParamAsync;
|
AddOrRemoveParamsAction = AddParamAsync;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -112,11 +112,11 @@ namespace Serein.Workbench.Node.View
|
|||||||
|
|
||||||
private bool isMouseOver; // 鼠标悬停状态
|
private bool isMouseOver; // 鼠标悬停状态
|
||||||
|
|
||||||
private Func<Task> AddOrRemoveParamsTask; // 增加或删除参数
|
private Action AddOrRemoveParamsAction; // 增加或删除参数
|
||||||
|
|
||||||
public async void ParamsArg_OnMouseDown(object sender, MouseButtonEventArgs e)
|
public void ParamsArg_OnMouseDown(object sender, MouseButtonEventArgs e)
|
||||||
{
|
{
|
||||||
await AddOrRemoveParamsTask.Invoke();
|
AddOrRemoveParamsAction.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ParamsArgControl_MouseMove(object sender, MouseEventArgs e)
|
private void ParamsArgControl_MouseMove(object sender, MouseEventArgs e)
|
||||||
@@ -133,7 +133,7 @@ namespace Serein.Workbench.Node.View
|
|||||||
// 如果焦点仍在控件上时,则改变点击事件
|
// 如果焦点仍在控件上时,则改变点击事件
|
||||||
if (isMouseOver)
|
if (isMouseOver)
|
||||||
{
|
{
|
||||||
AddOrRemoveParamsTask = RemoveParamAsync;
|
AddOrRemoveParamsAction = RemoveParamAsync;
|
||||||
this.Dispatcher.Invoke(InvalidateVisual);// 触发一次重绘
|
this.Dispatcher.Invoke(InvalidateVisual);// 触发一次重绘
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -149,7 +149,7 @@ namespace Serein.Workbench.Node.View
|
|||||||
private void ParamsArgControl_MouseLeave(object sender, MouseEventArgs e)
|
private void ParamsArgControl_MouseLeave(object sender, MouseEventArgs e)
|
||||||
{
|
{
|
||||||
isMouseOver = false;
|
isMouseOver = false;
|
||||||
AddOrRemoveParamsTask = AddParamAsync; // 鼠标焦点离开时恢复点击事件
|
AddOrRemoveParamsAction = AddParamAsync; // 鼠标焦点离开时恢复点击事件
|
||||||
cts?.Cancel();
|
cts?.Cancel();
|
||||||
this.Dispatcher.Invoke(InvalidateVisual);// 触发一次重绘
|
this.Dispatcher.Invoke(InvalidateVisual);// 触发一次重绘
|
||||||
|
|
||||||
@@ -157,13 +157,13 @@ namespace Serein.Workbench.Node.View
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
private async Task AddParamAsync()
|
private void AddParamAsync()
|
||||||
{
|
{
|
||||||
await this.MyNode.Env.ChangeParameter(MyNode.Guid, true, ArgIndex);
|
this.MyNode.Env.ChangeParameter(MyNode.Guid, true, ArgIndex);
|
||||||
}
|
}
|
||||||
private async Task RemoveParamAsync()
|
private void RemoveParamAsync()
|
||||||
{
|
{
|
||||||
await this.MyNode.Env.ChangeParameter(MyNode.Guid, false, ArgIndex);
|
this.MyNode.Env.ChangeParameter(MyNode.Guid, false, ArgIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -243,11 +243,11 @@ namespace Serein.Workbench.Node.View
|
|||||||
var jctEnd = End.JunctionType.ToConnectyionType();
|
var jctEnd = End.JunctionType.ToConnectyionType();
|
||||||
if (jct == JunctionOfConnectionType.Invoke)
|
if (jct == JunctionOfConnectionType.Invoke)
|
||||||
{
|
{
|
||||||
env.RemoveConnectInvokeAsync(canvasGuid, Start.MyNode.Guid, End.MyNode.Guid, InvokeType);
|
env.RemoveInvokeConnect(canvasGuid, Start.MyNode.Guid, End.MyNode.Guid, InvokeType);
|
||||||
}
|
}
|
||||||
else if (jct == JunctionOfConnectionType.Arg)
|
else if (jct == JunctionOfConnectionType.Arg)
|
||||||
{
|
{
|
||||||
env.RemoveConnectArgSourceAsync(canvasGuid,Start.MyNode.Guid, End.MyNode.Guid, ArgIndex) ;
|
env.RemoveArgSourceConnect(canvasGuid,Start.MyNode.Guid, End.MyNode.Guid, ArgIndex) ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using Serein.NodeFlow.Model;
|
using Serein.NodeFlow.Model.Node;
|
||||||
using Serein.Workbench.Node.View;
|
using Serein.Workbench.Node.View;
|
||||||
|
|
||||||
namespace Serein.Workbench.Node.ViewModel
|
namespace Serein.Workbench.Node.ViewModel
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using Serein.NodeFlow.Model;
|
using Serein.NodeFlow.Model.Node;
|
||||||
using Serein.Workbench.Node.View;
|
using Serein.Workbench.Node.View;
|
||||||
|
|
||||||
namespace Serein.Workbench.Node.ViewModel
|
namespace Serein.Workbench.Node.ViewModel
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using Serein.Library;
|
using Serein.Library;
|
||||||
using Serein.Library.Api;
|
using Serein.Library.Api;
|
||||||
using Serein.NodeFlow.Model;
|
using Serein.NodeFlow.Model.Node;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ namespace Serein.Workbench.Services
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly IFlowEnvironment flowEnvironment;
|
private readonly IFlowEnvironment flowEnvironment;
|
||||||
private readonly IFlowEnvironmentEvent flowEnvironmentEvent;
|
private readonly IFlowEnvironmentEvent flowEnvironmentEvent;
|
||||||
private readonly UIContextOperation uIContextOperation;
|
private readonly UIContextOperation uiContextOperation;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 转发流程运行环境各个事件的实现类
|
/// 转发流程运行环境各个事件的实现类
|
||||||
@@ -41,7 +41,7 @@ namespace Serein.Workbench.Services
|
|||||||
{
|
{
|
||||||
this.flowEnvironment = flowEnvironment;
|
this.flowEnvironment = flowEnvironment;
|
||||||
this.flowEnvironmentEvent = flowEnvironmentEvent;
|
this.flowEnvironmentEvent = flowEnvironmentEvent;
|
||||||
this.uIContextOperation = uIContextOperation;
|
this.uiContextOperation = uIContextOperation;
|
||||||
InitFlowEnvironmentEvent();
|
InitFlowEnvironmentEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,7 +184,7 @@ namespace Serein.Workbench.Services
|
|||||||
/// <param name="value"></param>
|
/// <param name="value"></param>
|
||||||
private void FlowEnvironment_OnEnvOutEvent(InfoType type, string value)
|
private void FlowEnvironment_OnEnvOutEvent(InfoType type, string value)
|
||||||
{
|
{
|
||||||
uIContextOperation.Invoke(() =>
|
uiContextOperation.Invoke(() =>
|
||||||
{
|
{
|
||||||
EnvOutput?.Invoke(type, value);
|
EnvOutput?.Invoke(type, value);
|
||||||
});
|
});
|
||||||
@@ -245,7 +245,10 @@ namespace Serein.Workbench.Services
|
|||||||
/// <exception cref="NotImplementedException"></exception>
|
/// <exception cref="NotImplementedException"></exception>
|
||||||
private void FlowEnvironmentEvent_OnCanvasCreate(CanvasCreateEventArgs eventArgs)
|
private void FlowEnvironmentEvent_OnCanvasCreate(CanvasCreateEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
CanvasCreated?.Invoke(eventArgs);
|
uiContextOperation?.Invoke(() =>
|
||||||
|
{
|
||||||
|
CanvasCreated?.Invoke(eventArgs);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -656,11 +656,7 @@ namespace Serein.Workbench.Services
|
|||||||
{
|
{
|
||||||
int width = 1200;
|
int width = 1200;
|
||||||
int height = 780;
|
int height = 780;
|
||||||
_ = Task.Run(async () =>
|
flowEnvironment.CreateCanvas("", width, height);
|
||||||
{
|
|
||||||
var result = await flowEnvironment.CreateCanvasAsync("", width, height);
|
|
||||||
Console.WriteLine(result.Guid);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -673,7 +669,7 @@ namespace Serein.Workbench.Services
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var model = ((FlowCanvasViewModel)CurrentSelectCanvas.DataContext).Model;
|
var model = ((FlowCanvasViewModel)CurrentSelectCanvas.DataContext).Model;
|
||||||
_ = flowEnvironment.RemoveCanvasAsync(model.Guid);
|
flowEnvironment.RemoveCanvas(model.Guid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -692,7 +688,7 @@ namespace Serein.Workbench.Services
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_ = flowEnvironment.CreateNodeAsync(canvasGuid, nodeType, position, methodDetailsInfo);
|
flowEnvironment.CreateNode(canvasGuid, nodeType, position, methodDetailsInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -711,7 +707,7 @@ namespace Serein.Workbench.Services
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = flowEnvironment.RemoveNodeAsync(model.CanvasDetails.Guid, model.Guid);
|
flowEnvironment.RemoveNode(model.CanvasDetails.Guid, model.Guid);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@@ -23,6 +23,11 @@ namespace Serein.Workbench.Services
|
|||||||
this.flowEnvironment = flowEnvironment;
|
this.flowEnvironment = flowEnvironment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void StartProjectManagementServer()
|
||||||
|
{
|
||||||
|
// CollabrationSideManagement
|
||||||
|
}
|
||||||
|
|
||||||
public void LoadLocalProject(string filePath)
|
public void LoadLocalProject(string filePath)
|
||||||
{
|
{
|
||||||
if (File.Exists(filePath))
|
if (File.Exists(filePath))
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ namespace Serein.Workbench.Themes
|
|||||||
private void ExecuteAddParams(object parameter)
|
private void ExecuteAddParams(object parameter)
|
||||||
{
|
{
|
||||||
// 方法逻辑
|
// 方法逻辑
|
||||||
this.MethodDetails.AddParamsArg();
|
this.MethodDetails.AddParamsArg(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ namespace Serein.Workbench.ViewModels
|
|||||||
{
|
{
|
||||||
public class MainMenuBarViewModel : ObservableObject
|
public class MainMenuBarViewModel : ObservableObject
|
||||||
{
|
{
|
||||||
private readonly IFlowEnvironment environment;
|
private readonly IFlowEnvironment flowEnvironment;
|
||||||
private readonly FlowNodeService flowNodeService;
|
private readonly FlowNodeService flowNodeService;
|
||||||
private readonly FlowProjectService flowProjectService;
|
private readonly FlowProjectService flowProjectService;
|
||||||
|
|
||||||
@@ -61,12 +61,18 @@ namespace Serein.Workbench.ViewModels
|
|||||||
public ICommand OpenDynamicCompilerCommand { get; private set; }
|
public ICommand OpenDynamicCompilerCommand { get; private set; }
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 开启远程服务
|
||||||
|
/// </summary>
|
||||||
|
public ICommand OpenRemoteServerCommand { get; private set; }
|
||||||
|
|
||||||
public MainMenuBarViewModel(IFlowEnvironment environment,
|
|
||||||
|
|
||||||
|
public MainMenuBarViewModel(IFlowEnvironment flowEnvironment,
|
||||||
FlowNodeService flowNodeService,
|
FlowNodeService flowNodeService,
|
||||||
FlowProjectService flowProjectService)
|
FlowProjectService flowProjectService)
|
||||||
{
|
{
|
||||||
this.environment = environment;
|
this.flowEnvironment = flowEnvironment;
|
||||||
this.flowNodeService = flowNodeService;
|
this.flowNodeService = flowNodeService;
|
||||||
this.flowProjectService = flowProjectService;
|
this.flowProjectService = flowProjectService;
|
||||||
SaveProjectCommand = new RelayCommand(SaveProject); // 保存项目
|
SaveProjectCommand = new RelayCommand(SaveProject); // 保存项目
|
||||||
@@ -81,29 +87,51 @@ namespace Serein.Workbench.ViewModels
|
|||||||
StopCurrentCanvasFlowCommand = new RelayCommand(StopCurrentCanvasFlow); // 停止当前流程
|
StopCurrentCanvasFlowCommand = new RelayCommand(StopCurrentCanvasFlow); // 停止当前流程
|
||||||
|
|
||||||
OpenEnvOutWindowCommand = new RelayCommand(OpenEnvOutWindow); // 打开运行输出窗口
|
OpenEnvOutWindowCommand = new RelayCommand(OpenEnvOutWindow); // 打开运行输出窗口
|
||||||
OpenDynamicCompilerCommand = new RelayCommand(OpenDynamicCompiler); // 打开动态编译仓库窗口
|
OpenDynamicCompilerCommand = new RelayCommand(OpenDynamicCompiler); // 打开动态编译窗口
|
||||||
|
|
||||||
|
OpenRemoteServerCommand = new RelayCommand(OpenRemoteServer); // 打开动态编译窗口
|
||||||
this.flowProjectService = flowProjectService;
|
this.flowProjectService = flowProjectService;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SaveProject() => environment.SaveProject(); // 保存项目
|
private void SaveProject() => flowEnvironment.SaveProject(); // 保存项目
|
||||||
private void LoadLocalProject() {
|
private void LoadLocalProject()
|
||||||
|
{
|
||||||
|
|
||||||
flowProjectService.SelectProjectFile(); //选择项目
|
flowProjectService.SelectProjectFile(); //选择项目
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void LoadRemoteProject()
|
private void LoadRemoteProject()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
private void CreateFlowCanvas() => flowNodeService.CreateFlowCanvas();
|
private void CreateFlowCanvas() => flowNodeService.CreateFlowCanvas();
|
||||||
|
|
||||||
private void RemoteFlowCanvas() => flowNodeService.RemoveFlowCanvas();
|
private void RemoteFlowCanvas() => flowNodeService.RemoveFlowCanvas();
|
||||||
|
|
||||||
private void StartUIFlow() => environment.StartFlowAsync([.. flowNodeService.FlowCanvass.Select(c => c.Guid)]);
|
private void StartUIFlow()
|
||||||
private void StartCurrentCanvasFlow() => environment.StartFlowAsync([flowNodeService.CurrentSelectCanvas.Guid]);
|
{
|
||||||
|
var canvass = flowNodeService.FlowCanvass;
|
||||||
|
if(canvass.Length > 0)
|
||||||
|
{
|
||||||
|
string[] guids = [..canvass.Select(c => c.Guid)];
|
||||||
|
flowEnvironment.StartFlowAsync(guids);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
private void StartCurrentCanvasFlow()
|
||||||
|
{
|
||||||
|
var canvas = flowNodeService.CurrentSelectCanvas;
|
||||||
|
if (canvas is null) return;
|
||||||
|
flowEnvironment.StartFlowAsync([canvas.Guid]);
|
||||||
|
}
|
||||||
private void StopCurrentCanvasFlow() { }
|
private void StopCurrentCanvasFlow() { }
|
||||||
private void OpenDynamicCompiler() { }
|
private void OpenDynamicCompiler() { }
|
||||||
private void OpenEnvOutWindow() => LogWindow.Instance?.Show();
|
private void OpenEnvOutWindow() => LogWindow.Instance?.Show();
|
||||||
|
|
||||||
|
private void OpenRemoteServer()
|
||||||
|
{
|
||||||
|
flowEnvironment.StartRemoteServerAsync();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -372,7 +372,7 @@ namespace Serein.Workbench.Views
|
|||||||
if (TryPlaceNodeInRegion(nodeControl, position, out var regionControl)) // 判断添加到区域容器
|
if (TryPlaceNodeInRegion(nodeControl, position, out var regionControl)) // 判断添加到区域容器
|
||||||
{
|
{
|
||||||
// 通知运行环境调用加载节点子项的方法
|
// 通知运行环境调用加载节点子项的方法
|
||||||
_ = flowEnvironment.PlaceNodeToContainerAsync(Guid,
|
flowEnvironment.PlaceNodeToContainer(Guid,
|
||||||
nodeControl.ViewModel.NodeModel.Guid, // 待移动的节点
|
nodeControl.ViewModel.NodeModel.Guid, // 待移动的节点
|
||||||
regionControl.ViewModel.NodeModel.Guid); // 目标的容器节点
|
regionControl.ViewModel.NodeModel.Guid); // 目标的容器节点
|
||||||
return;
|
return;
|
||||||
@@ -566,7 +566,8 @@ namespace Serein.Workbench.Views
|
|||||||
// F5 调试当前选定节点
|
// F5 调试当前选定节点
|
||||||
var nodeModel = selectNodeControls[0].ViewModel.NodeModel;
|
var nodeModel = selectNodeControls[0].ViewModel.NodeModel;
|
||||||
SereinEnv.WriteLine(InfoType.INFO, $"调试运行当前节点:{nodeModel.Guid}");
|
SereinEnv.WriteLine(InfoType.INFO, $"调试运行当前节点:{nodeModel.Guid}");
|
||||||
_ = nodeModel.StartFlowAsync(new DynamicContext(flowEnvironment), new CancellationToken());
|
_ = flowEnvironment.StartFlowFromSelectNodeAsync(nodeModel.Guid);
|
||||||
|
//_ = nodeModel.StartFlowAsync(new DynamicContext(flowEnvironment), new CancellationToken());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -898,7 +899,7 @@ namespace Serein.Workbench.Views
|
|||||||
{
|
{
|
||||||
var canvasGuid = this.Guid;
|
var canvasGuid = this.Guid;
|
||||||
|
|
||||||
await flowEnvironment.ConnectInvokeNodeAsync(
|
flowEnvironment.ConnectInvokeNode(
|
||||||
canvasGuid,
|
canvasGuid,
|
||||||
cd.StartJunction.MyNode.Guid,
|
cd.StartJunction.MyNode.Guid,
|
||||||
cd.CurrentJunction.MyNode.Guid,
|
cd.CurrentJunction.MyNode.Guid,
|
||||||
@@ -922,7 +923,7 @@ namespace Serein.Workbench.Views
|
|||||||
}
|
}
|
||||||
var canvasGuid = this.Guid;
|
var canvasGuid = this.Guid;
|
||||||
|
|
||||||
await flowEnvironment.ConnectArgSourceNodeAsync(
|
flowEnvironment.ConnectArgSourceNode(
|
||||||
canvasGuid,
|
canvasGuid,
|
||||||
cd.StartJunction.MyNode.Guid,
|
cd.StartJunction.MyNode.Guid,
|
||||||
cd.CurrentJunction.MyNode.Guid,
|
cd.CurrentJunction.MyNode.Guid,
|
||||||
@@ -1269,7 +1270,7 @@ namespace Serein.Workbench.Views
|
|||||||
if (!string.IsNullOrEmpty(guid))
|
if (!string.IsNullOrEmpty(guid))
|
||||||
{
|
{
|
||||||
var canvasGuid = this.Guid;
|
var canvasGuid = this.Guid;
|
||||||
flowEnvironment.RemoveNodeAsync(canvasGuid, guid);
|
flowEnvironment.RemoveNode(canvasGuid, guid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1491,10 +1492,10 @@ namespace Serein.Workbench.Views
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
contextMenu.Items.Add(WpfFuncTool.CreateMenuItem("设为起点", (s, e) => flowEnvironment.SetStartNodeAsync(canvasGuid, nodeGuid)));
|
contextMenu.Items.Add(WpfFuncTool.CreateMenuItem("设为起点", (s, e) => flowEnvironment.SetStartNode(canvasGuid, nodeGuid)));
|
||||||
contextMenu.Items.Add(WpfFuncTool.CreateMenuItem("删除", async (s, e) =>
|
contextMenu.Items.Add(WpfFuncTool.CreateMenuItem("删除", async (s, e) =>
|
||||||
{
|
{
|
||||||
var result = await flowEnvironment.RemoveNodeAsync(canvasGuid, nodeGuid);
|
flowEnvironment.RemoveNode(canvasGuid, nodeGuid);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
#region 右键菜单功能 - 控件对齐
|
#region 右键菜单功能 - 控件对齐
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
<MenuItem Header="项目">
|
<MenuItem Header="项目">
|
||||||
<MenuItem Header="保存项目" Command="{Binding SaveProjectCommand}"></MenuItem>
|
<MenuItem Header="保存项目" Command="{Binding SaveProjectCommand}"></MenuItem>
|
||||||
<MenuItem Header="加载本地项目" Command="{Binding LoadLocalProjectCommand}" ></MenuItem>
|
<MenuItem Header="加载本地项目" Command="{Binding LoadLocalProjectCommand}" ></MenuItem>
|
||||||
<MenuItem Header="加载远程项目"></MenuItem>
|
<!--<MenuItem Header="加载远程项目"></MenuItem>-->
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
|
||||||
<MenuItem Header="画布">
|
<MenuItem Header="画布">
|
||||||
@@ -24,19 +24,19 @@
|
|||||||
|
|
||||||
<MenuItem Header="运行">
|
<MenuItem Header="运行">
|
||||||
<MenuItem Header="运行(仅当前画布)" Command="{Binding StartCurrentCanvasFlowCommand}"></MenuItem>
|
<MenuItem Header="运行(仅当前画布)" Command="{Binding StartCurrentCanvasFlowCommand}"></MenuItem>
|
||||||
<MenuItem Header="运行(从选定节点)" ></MenuItem>
|
<!--<MenuItem Header="运行(从选定节点)" ></MenuItem>-->
|
||||||
<MenuItem Header="运行(全部画布)" Command="{Binding StartFlowCommand}"></MenuItem>
|
<MenuItem Header="运行(全部画布)" Command="{Binding StartFlowCommand}"></MenuItem>
|
||||||
<MenuItem Header="结束流程" ></MenuItem>
|
<!--<MenuItem Header="结束流程" ></MenuItem>-->
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
|
||||||
<MenuItem Header="视图">
|
<MenuItem Header="视图">
|
||||||
<MenuItem Header="输出窗口" Command="{Binding OpenEnvOutWindowCommand}"></MenuItem>
|
<MenuItem Header="输出窗口" Command="{Binding OpenEnvOutWindowCommand}"></MenuItem>
|
||||||
<MenuItem Header="定位节点" ></MenuItem>
|
<!--<MenuItem Header="定位节点" ></MenuItem>-->
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<!--<MenuItem Header="拓展">
|
<MenuItem Header="拓展">
|
||||||
<MenuItem Header="动态编译" ></MenuItem>
|
<!--<MenuItem Header="动态编译" ></MenuItem>-->
|
||||||
<MenuItem Header="启动远程服务"></MenuItem>
|
<MenuItem Header="启动远程服务"></MenuItem>
|
||||||
</MenuItem>-->
|
</MenuItem>
|
||||||
</Menu>
|
</Menu>
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
Reference in New Issue
Block a user