mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-05-01 03:53:22 +08:00
完成mvvm模式下,画布、节点编辑的基本重构
This commit is contained in:
49
.claudiaideconfig
Normal file
49
.claudiaideconfig
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"BackgroundImageAbsolutePath": "C:\\Users\\Az\\Pictures\\anime_girl_brunette1.png",
|
||||||
|
"BackgroundImagesDirectoryAbsolutePath": "c:\\users\\az\\appdata\\local\\microsoft\\visualstudio\\17.0_a4315dfe\\extensions\\mtri5ge5.xs4\\Images",
|
||||||
|
"BlurMethod": 0,
|
||||||
|
"BlurRadius": 0,
|
||||||
|
"EditorBackgroundColor": "",
|
||||||
|
"EditorBackgroundColorObject": null,
|
||||||
|
"ExpandToIDE": false,
|
||||||
|
"Extensions": ".png, .jpg, .gif, .bmp",
|
||||||
|
"ImageBackgroundType": 0,
|
||||||
|
"ImageFadeAnimationInterval": "PT5S",
|
||||||
|
"ImageStretch": 0,
|
||||||
|
"IncludeSubdirectories": false,
|
||||||
|
"IsLimitToMainlyEditorWindow": false,
|
||||||
|
"IsTransparentToContentMargin": false,
|
||||||
|
"IsTransparentToStickyScroll": false,
|
||||||
|
"LoopSlideshow": true,
|
||||||
|
"MaxHeight": 0,
|
||||||
|
"MaxWidth": 0,
|
||||||
|
"Opacity": 0.1,
|
||||||
|
"PositionHorizon": 1,
|
||||||
|
"PositionVertical": 1,
|
||||||
|
"ShuffleSlideshow": false,
|
||||||
|
"SoftEdgeX": 0,
|
||||||
|
"SoftEdgeY": 0,
|
||||||
|
"StickyScrollColor": "#00000000",
|
||||||
|
"StickyScrollColorObject": {
|
||||||
|
"A": 0,
|
||||||
|
"B": 0,
|
||||||
|
"G": 0,
|
||||||
|
"R": 0,
|
||||||
|
"ScA": 0,
|
||||||
|
"ScB": 0,
|
||||||
|
"ScG": 0,
|
||||||
|
"ScR": 0
|
||||||
|
},
|
||||||
|
"TileMode": 0,
|
||||||
|
"UpdateImageInterval": "PT1M",
|
||||||
|
"ViewBoxPointX": 0,
|
||||||
|
"ViewBoxPointY": 0,
|
||||||
|
"ViewPortHeight": 1,
|
||||||
|
"ViewPortPointX": 0,
|
||||||
|
"ViewPortPointY": 0,
|
||||||
|
"ViewPortWidth": 1,
|
||||||
|
"WebApiDownloadInterval": "PT5M",
|
||||||
|
"WebApiEndpoint": "",
|
||||||
|
"WebApiJsonKey": "",
|
||||||
|
"WebSingleUrl": ""
|
||||||
|
}
|
||||||
@@ -146,11 +146,11 @@ namespace Serein.Library.Api
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否完成
|
/// 是否完成
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsSucceed { get; protected set; } = true;
|
public bool IsSucceed { get;} = true;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 错误提示
|
/// 错误提示
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string ErrorTips { get; protected set; } = string.Empty;
|
public string ErrorTips { get;} = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -168,9 +168,15 @@ namespace Serein.Library.Api
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class ProjectSavingEventArgs : FlowEventArgs
|
public class ProjectSavingEventArgs : FlowEventArgs
|
||||||
{
|
{
|
||||||
public ProjectSavingEventArgs()
|
public ProjectSavingEventArgs(SereinProjectData projectData)
|
||||||
{
|
{
|
||||||
|
ProjectData = projectData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 项目数据
|
||||||
|
/// </summary>
|
||||||
|
public SereinProjectData ProjectData { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -186,11 +192,11 @@ namespace Serein.Library.Api
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 已加载了的程序集
|
/// 已加载了的程序集
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public NodeLibraryInfo NodeLibraryInfo { get; protected set; }
|
public NodeLibraryInfo NodeLibraryInfo { get;}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// dll文件中有效的流程方法描述
|
/// dll文件中有效的流程方法描述
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<MethodDetailsInfo> MethodDetailss { get; protected set; }
|
public List<MethodDetailsInfo> MethodDetailss { get;}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -279,31 +285,31 @@ namespace Serein.Library.Api
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 连接关系中始节点的Guid
|
/// 连接关系中始节点的Guid
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string FromNodeGuid { get; protected set; }
|
public string FromNodeGuid { get;}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 连接关系中目标节点的Guid
|
/// 连接关系中目标节点的Guid
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string ToNodeGuid { get; protected set; }
|
public string ToNodeGuid { get;}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 连接类型
|
/// 连接类型
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ConnectionInvokeType ConnectionInvokeType { get; protected set; }
|
public ConnectionInvokeType ConnectionInvokeType { get;}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 表示此次需要在两个节点之间创建连接关系,或是移除连接关系
|
/// 表示此次需要在两个节点之间创建连接关系,或是移除连接关系
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ConnectChangeType ChangeType { get; protected set; }
|
public ConnectChangeType ChangeType { get;}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 指示需要创建什么类型的连接线
|
/// 指示需要创建什么类型的连接线
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public JunctionOfConnectionType JunctionOfConnectionType { get; protected set; }
|
public JunctionOfConnectionType JunctionOfConnectionType { get;}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 节点对应的方法入参所需参数来源
|
/// 节点对应的方法入参所需参数来源
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ConnectionArgSourceType ConnectionArgSourceType { get; protected set; }
|
public ConnectionArgSourceType ConnectionArgSourceType { get;}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 第几个参数
|
/// 第几个参数
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int ArgIndex { get; protected set; }
|
public int ArgIndex { get;}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -313,12 +319,12 @@ namespace Serein.Library.Api
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class CanvasCreateEventArgs : FlowEventArgs
|
public class CanvasCreateEventArgs : FlowEventArgs
|
||||||
{
|
{
|
||||||
public CanvasCreateEventArgs(FlowCanvasModel model)
|
public CanvasCreateEventArgs(FlowCanvasDetails model)
|
||||||
{
|
{
|
||||||
Model = model;
|
Model = model;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FlowCanvasModel Model { get; }
|
public FlowCanvasDetails Model { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -342,6 +348,7 @@ namespace Serein.Library.Api
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 节点添加事件参数
|
/// 节点添加事件参数
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="canvasGuid">画布</param>
|
||||||
/// <param name="nodeModel">节点对象</param>
|
/// <param name="nodeModel">节点对象</param>
|
||||||
/// <param name="position">位置</param>
|
/// <param name="position">位置</param>
|
||||||
public NodeCreateEventArgs(string canvasGuid, NodeModelBase nodeModel, PositionOfUI position)
|
public NodeCreateEventArgs(string canvasGuid, NodeModelBase nodeModel, PositionOfUI position)
|
||||||
@@ -350,15 +357,23 @@ namespace Serein.Library.Api
|
|||||||
this.NodeModel = nodeModel;
|
this.NodeModel = nodeModel;
|
||||||
this.Position = position;
|
this.Position = position;
|
||||||
}
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 所处画布Guid
|
||||||
|
/// </summary>
|
||||||
public string CanvasGuid { get; }
|
public string CanvasGuid { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 节点Model对象
|
/// 节点Model对象
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public NodeModelBase NodeModel { get; private set; }
|
public NodeModelBase NodeModel { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 在UI上的位置
|
||||||
|
/// </summary>
|
||||||
public PositionOfUI Position { get; private set; }
|
public PositionOfUI Position { get; private set; }
|
||||||
public string RegeionGuid { get; private set; }
|
/// <summary>
|
||||||
|
/// 容器
|
||||||
|
/// </summary>
|
||||||
|
//public string RegeionGuid { get; private set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -487,16 +502,16 @@ namespace Serein.Library.Api
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 中断的节点Guid
|
/// 中断的节点Guid
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string NodeGuid { get; protected set; }
|
public string NodeGuid { get;}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 监听对象类别
|
/// 监听对象类别
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ObjSourceType ObjSource { get; protected set; }
|
public ObjSourceType ObjSource { get;}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 新的数据
|
/// 新的数据
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public object NewData { get; protected set; }
|
public object NewData { get;}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -514,9 +529,9 @@ namespace Serein.Library.Api
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 中断的节点Guid
|
/// 中断的节点Guid
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string NodeGuid { get; protected set; }
|
public string NodeGuid { get;}
|
||||||
public bool IsInterrupt { get; protected set; }
|
public bool IsInterrupt { get;}
|
||||||
// public InterruptClass Class { get; protected set; }
|
// public InterruptClass Class { get;}
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 节点触发了中断事件参数
|
/// 节点触发了中断事件参数
|
||||||
@@ -549,9 +564,9 @@ namespace Serein.Library.Api
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 中断的节点Guid
|
/// 中断的节点Guid
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string NodeGuid { get; protected set; }
|
public string NodeGuid { get;}
|
||||||
public string Expression { get; protected set; }
|
public string Expression { get;}
|
||||||
public InterruptTriggerType Type { get; protected set; }
|
public InterruptTriggerType Type { get;}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -880,7 +895,7 @@ 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<FlowCanvasInfo> CreateCanvasAsync(string canvasName, int width , int height);
|
Task<FlowCanvasDetailsInfo> CreateCanvasAsync(string canvasName, int width , int height);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 删除画布
|
/// 删除画布
|
||||||
|
|||||||
@@ -21,9 +21,9 @@ namespace Serein.Library
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="model"></param>
|
/// <param name="model"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static FlowCanvasInfo ToInfo(this FlowCanvasModel model)
|
public static FlowCanvasDetailsInfo ToInfo(this FlowCanvasDetails model)
|
||||||
{
|
{
|
||||||
return new FlowCanvasInfo
|
return new FlowCanvasDetailsInfo
|
||||||
{
|
{
|
||||||
Guid = model.Guid,
|
Guid = model.Guid,
|
||||||
Height = model.Height,
|
Height = model.Height,
|
||||||
@@ -33,6 +33,7 @@ namespace Serein.Library
|
|||||||
ScaleY = model.ScaleY,
|
ScaleY = model.ScaleY,
|
||||||
ViewX = model.ViewX,
|
ViewX = model.ViewX,
|
||||||
ViewY = model.ViewY,
|
ViewY = model.ViewY,
|
||||||
|
StartNode = model.StartNode,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,7 +42,7 @@ namespace Serein.Library
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="model"></param>
|
/// <param name="model"></param>
|
||||||
/// <param name="info"></param>
|
/// <param name="info"></param>
|
||||||
public static void LoadInfo(this FlowCanvasModel model, FlowCanvasInfo info)
|
public static void LoadInfo(this FlowCanvasDetails model, FlowCanvasDetailsInfo info)
|
||||||
{
|
{
|
||||||
model.Guid = info.Guid;
|
model.Guid = info.Guid;
|
||||||
model.Height = info.Height;
|
model.Height = info.Height;
|
||||||
@@ -51,6 +52,7 @@ namespace Serein.Library
|
|||||||
model.ScaleY = info.ScaleY;
|
model.ScaleY = info.ScaleY;
|
||||||
model.ViewX = info.ViewX;
|
model.ViewX = info.ViewX;
|
||||||
model.ViewY = info.ViewY;
|
model.ViewY = info.ViewY;
|
||||||
|
model.StartNode = info.StartNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -102,6 +104,7 @@ namespace Serein.Library
|
|||||||
NodeInfo nodeInfo = new NodeInfo
|
NodeInfo nodeInfo = new NodeInfo
|
||||||
{
|
{
|
||||||
Guid = nodeModel.Guid,
|
Guid = nodeModel.Guid,
|
||||||
|
CanvasGuid = nodeModel.CanvasGuid,
|
||||||
AssemblyName = nodeModel.MethodDetails.AssemblyName,
|
AssemblyName = nodeModel.MethodDetails.AssemblyName,
|
||||||
MethodName = nodeModel.MethodDetails?.MethodName,
|
MethodName = nodeModel.MethodDetails?.MethodName,
|
||||||
Label = nodeModel.MethodDetails?.MethodAnotherName,
|
Label = nodeModel.MethodDetails?.MethodAnotherName,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Serein.Library.Api;
|
using Serein.Library.Api;
|
||||||
|
using Serein.Library.FlowNode;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -8,50 +9,86 @@ using System.Threading.Tasks;
|
|||||||
namespace Serein.Library
|
namespace Serein.Library
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 流程画布
|
||||||
|
/// </summary>
|
||||||
[NodeProperty(ValuePath = NodeValuePath.Node)]
|
[NodeProperty(ValuePath = NodeValuePath.Node)]
|
||||||
public partial class FlowCanvasModel
|
public partial class FlowCanvasDetails
|
||||||
{
|
{
|
||||||
public FlowCanvasModel(IFlowEnvironment env)
|
public FlowCanvasDetails(IFlowEnvironment env)
|
||||||
{
|
{
|
||||||
Env = env;
|
Env = env;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IFlowEnvironment Env { get; }
|
public IFlowEnvironment Env { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 标识画布ID
|
||||||
|
/// </summary>
|
||||||
[PropertyInfo(IsProtection = true)]
|
[PropertyInfo(IsProtection = true)]
|
||||||
private string _guid;
|
private string _guid;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 画布名称
|
||||||
|
/// </summary>
|
||||||
[PropertyInfo(IsNotification = true)]
|
[PropertyInfo(IsNotification = true)]
|
||||||
private string _name;
|
private string _name;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 画布宽度
|
||||||
|
/// </summary>
|
||||||
[PropertyInfo(IsNotification = true)]
|
[PropertyInfo(IsNotification = true)]
|
||||||
private double _width;
|
private double _width;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 画布高度
|
||||||
|
/// </summary>
|
||||||
[PropertyInfo(IsNotification = true)]
|
[PropertyInfo(IsNotification = true)]
|
||||||
private double _height;
|
private double _height;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 预览位置X
|
/// 预览位置X
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[PropertyInfo]
|
[PropertyInfo(IsNotification = true)]
|
||||||
private double _viewX ;
|
private double _viewX ;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 预览位置Y
|
/// 预览位置Y
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[PropertyInfo]
|
[PropertyInfo(IsNotification = true)]
|
||||||
private double _viewY ;
|
private double _viewY ;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 缩放比例X
|
/// 缩放比例X
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[PropertyInfo]
|
[PropertyInfo(IsNotification = true)]
|
||||||
private double _scaleX ;
|
private double _scaleX = 1;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 缩放比例Y
|
/// 缩放比例Y
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[PropertyInfo]
|
[PropertyInfo(IsNotification = true)]
|
||||||
private double _scaleY ;
|
private double _scaleY = 1;
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 起始节点私有属性
|
||||||
|
/// </summary>
|
||||||
|
private string _startNode;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public partial class FlowCanvasDetails
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
60
Library/FlowNode/FlowCanvasDetailsInfo.cs
Normal file
60
Library/FlowNode/FlowCanvasDetailsInfo.cs
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Serein.Library
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 画布信息
|
||||||
|
/// </summary>
|
||||||
|
public class FlowCanvasDetailsInfo
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 起始节点Guid
|
||||||
|
/// </summary>
|
||||||
|
public string StartNode;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 标识画布ID
|
||||||
|
/// </summary>
|
||||||
|
public string Guid;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 画布名称
|
||||||
|
/// </summary>
|
||||||
|
public string Name;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 画布宽度
|
||||||
|
/// </summary>
|
||||||
|
public double Width;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 画布高度
|
||||||
|
/// </summary>
|
||||||
|
public double Height;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 预览位置X
|
||||||
|
/// </summary>
|
||||||
|
public double ViewX;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 预览位置Y
|
||||||
|
/// </summary>
|
||||||
|
public double ViewY;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 缩放比例X
|
||||||
|
/// </summary>
|
||||||
|
public double ScaleX;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 缩放比例Y
|
||||||
|
/// </summary>
|
||||||
|
public double ScaleY;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -48,7 +48,7 @@ namespace Serein.Library
|
|||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 项目保存文件
|
/// 项目数据
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class SereinProjectData
|
public class SereinProjectData
|
||||||
{
|
{
|
||||||
@@ -64,16 +64,20 @@ namespace Serein.Library
|
|||||||
|
|
||||||
public NodeLibraryInfo[] Librarys { get; set; }
|
public NodeLibraryInfo[] Librarys { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
///// <summary>
|
||||||
/// 起始节点GUID
|
///// 起始节点GUID
|
||||||
/// </summary>
|
///// </summary>
|
||||||
|
|
||||||
public string StartNode { get; set; }
|
//public string StartNode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 画布集合
|
||||||
|
/// </summary>
|
||||||
|
public FlowCanvasDetailsInfo[] Canvass { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 节点集合
|
/// 节点集合
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
||||||
public NodeInfo[] Nodes { get; set; }
|
public NodeInfo[] Nodes { get; set; }
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -83,11 +87,10 @@ namespace Serein.Library
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class Basic
|
public class Basic
|
||||||
{
|
{
|
||||||
/// <summary>
|
///// <summary>
|
||||||
/// 画布
|
///// 画布
|
||||||
/// </summary>
|
///// </summary>
|
||||||
|
//public FlowCanvasInfo Canvas { get; set; }
|
||||||
public FlowCanvasInfo Canvas { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 版本
|
/// 版本
|
||||||
@@ -95,7 +98,9 @@ namespace Serein.Library
|
|||||||
|
|
||||||
public string Versions { get; set; }
|
public string Versions { get; set; }
|
||||||
}
|
}
|
||||||
/// <summary>
|
|
||||||
|
|
||||||
|
/* /// <summary>
|
||||||
/// 画布信息,项目文件相关
|
/// 画布信息,项目文件相关
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class FlowCanvasInfo
|
public class FlowCanvasInfo
|
||||||
@@ -132,7 +137,7 @@ namespace Serein.Library
|
|||||||
/// 缩放比例Y
|
/// 缩放比例Y
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double ScaleY { get; set; }
|
public double ScaleY { get; set; }
|
||||||
}
|
}*/
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 项目依赖的程序集,项目文件相关
|
/// 项目依赖的程序集,项目文件相关
|
||||||
@@ -187,7 +192,6 @@ namespace Serein.Library
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string CanvasGuid { get; set; }
|
public string CanvasGuid { get; set; }
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 节点的GUID
|
/// 节点的GUID
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@@ -91,6 +92,7 @@ namespace Serein.Library.Utils
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
tcs.SetException(ex);
|
tcs.SetException(ex);
|
||||||
|
Debug.WriteLine(ex);
|
||||||
}
|
}
|
||||||
}, null);
|
}, null);
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,10 @@
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static class EnvMsgTheme
|
public static class EnvMsgTheme
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 尝试保存项目
|
||||||
|
/// </summary>
|
||||||
|
public const string SaveProject = nameof(SaveProject);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取远程环境信息
|
/// 获取远程环境信息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -301,7 +301,7 @@ namespace Serein.NodeFlow.Env
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 运行环境加载的画布集合
|
/// 运行环境加载的画布集合
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private Dictionary<string, FlowCanvasModel> FlowCanvass { get; } = [];
|
private Dictionary<string, FlowCanvasDetails> FlowCanvass { get; } = [];
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 存放触发器节点(运行时全部调用)
|
/// 存放触发器节点(运行时全部调用)
|
||||||
@@ -309,35 +309,35 @@ namespace Serein.NodeFlow.Env
|
|||||||
private List<SingleFlipflopNode> FlipflopNodes { get; } = [];
|
private List<SingleFlipflopNode> FlipflopNodes { get; } = [];
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
/// <summary>
|
||||||
|
/// 起始节点私有属性
|
||||||
|
/// </summary>
|
||||||
|
private NodeModelBase? _startNode = null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 起始节点私有属性
|
/// 起始节点
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private NodeModelBase? _startNode = null;
|
private NodeModelBase? StartNode
|
||||||
|
{
|
||||||
/// <summary>
|
get
|
||||||
/// 起始节点
|
{
|
||||||
/// </summary>
|
return _startNode;
|
||||||
private NodeModelBase? StartNode
|
}
|
||||||
{
|
set
|
||||||
get
|
{
|
||||||
{
|
if (value is null)
|
||||||
return _startNode;
|
{
|
||||||
}
|
return;
|
||||||
set
|
}
|
||||||
{
|
if (_startNode is not null)
|
||||||
if (value is null)
|
{
|
||||||
{
|
_startNode.IsStart = false;
|
||||||
return;
|
}
|
||||||
}
|
value.IsStart = true;
|
||||||
if (_startNode is not null)
|
_startNode = value;
|
||||||
{
|
}
|
||||||
_startNode.IsStart = false;
|
}*/
|
||||||
}
|
|
||||||
value.IsStart = true;
|
|
||||||
_startNode = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 流程任务管理
|
/// 流程任务管理
|
||||||
@@ -373,12 +373,11 @@ namespace Serein.NodeFlow.Env
|
|||||||
IOC.Reset();
|
IOC.Reset();
|
||||||
IOC.Register<IScriptFlowApi, ScriptFlowApi>(); // 注册脚本接口
|
IOC.Register<IScriptFlowApi, ScriptFlowApi>(); // 注册脚本接口
|
||||||
|
|
||||||
var flowTaskOptions = new FlowWorkLibrary
|
var flowTaskOptions = new FlowWorkOptions
|
||||||
{
|
{
|
||||||
|
|
||||||
Environment = this,
|
Environment = this,
|
||||||
FlowContextPool = new ObjectPool<IDynamicContext>(() => new DynamicContext(this)),
|
FlowContextPool = new ObjectPool<IDynamicContext>(() => new DynamicContext(this)),
|
||||||
Nodes = NodeModels.Values.ToList(),
|
//Nodes = NodeModels.Values.ToList(),
|
||||||
AutoRegisterTypes = this.FlowLibraryManagement.GetaAutoRegisterType(),
|
AutoRegisterTypes = this.FlowLibraryManagement.GetaAutoRegisterType(),
|
||||||
InitMds = this.FlowLibraryManagement.GetMdsOnFlowStart(NodeType.Init),
|
InitMds = this.FlowLibraryManagement.GetMdsOnFlowStart(NodeType.Init),
|
||||||
LoadMds = this.FlowLibraryManagement.GetMdsOnFlowStart(NodeType.Loading),
|
LoadMds = this.FlowLibraryManagement.GetMdsOnFlowStart(NodeType.Loading),
|
||||||
@@ -534,7 +533,8 @@ namespace Serein.NodeFlow.Env
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void SaveProject()
|
public void SaveProject()
|
||||||
{
|
{
|
||||||
OnProjectSaving?.Invoke(new ProjectSavingEventArgs());
|
var project = GetProjectInfoAsync().GetAwaiter().GetResult();
|
||||||
|
OnProjectSaving?.Invoke(new ProjectSavingEventArgs(project));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -562,7 +562,7 @@ namespace Serein.NodeFlow.Env
|
|||||||
_ = Task.Run( async () =>
|
_ = Task.Run( async () =>
|
||||||
{
|
{
|
||||||
await LoadNodeInfosAsync(projectData.Nodes.ToList()); // 加载节点信息
|
await LoadNodeInfosAsync(projectData.Nodes.ToList()); // 加载节点信息
|
||||||
await SetStartNodeAsync("", projectData.StartNode); // 设置起始节点
|
//await SetStartNodeAsync("", projectData.StartNode); // 设置起始节点
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -615,16 +615,17 @@ namespace Serein.NodeFlow.Env
|
|||||||
/// 序列化当前项目的依赖信息、节点信息
|
/// 序列化当前项目的依赖信息、节点信息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public Task<SereinProjectData> GetProjectInfoAsync()
|
public async Task<SereinProjectData> GetProjectInfoAsync()
|
||||||
{
|
{
|
||||||
var projectData = new SereinProjectData()
|
var projectData = new SereinProjectData()
|
||||||
{
|
{
|
||||||
Librarys = this.FlowLibraryManagement.GetAllLibraryInfo().ToArray(),
|
Librarys = this.FlowLibraryManagement.GetAllLibraryInfo().ToArray(),
|
||||||
Nodes = NodeModels.Values.Select(node => node.ToInfo()).Where(info => info is not null).ToArray(),
|
Nodes = NodeModels.Values.Select(node => node.ToInfo()).Where(info => info is not null).ToArray(),
|
||||||
StartNode = NodeModels.Values.FirstOrDefault(it => it.IsStart)?.Guid,
|
Canvass = FlowCanvass.Values.Select(canvas => canvas.ToInfo()).ToArray(),
|
||||||
|
//StartNode = NodeModels.Values.FirstOrDefault(it => it.IsStart)?.Guid,
|
||||||
};
|
};
|
||||||
|
|
||||||
return Task.FromResult(projectData);
|
return projectData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -776,22 +777,22 @@ namespace Serein.NodeFlow.Env
|
|||||||
/// <param name="width">宽度</param>
|
/// <param name="width">宽度</param>
|
||||||
/// <param name="height">高度</param>
|
/// <param name="height">高度</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public Task<FlowCanvasInfo> CreateCanvasAsync(string canvasName, int width, int height)
|
public async Task<FlowCanvasDetailsInfo> CreateCanvasAsync(string canvasName, int width, int height)
|
||||||
{
|
{
|
||||||
var model = new FlowCanvasModel(this)
|
var model = new FlowCanvasDetails(this)
|
||||||
{
|
{
|
||||||
Guid = Guid.NewGuid().ToString(),
|
Guid = Guid.NewGuid().ToString(),
|
||||||
Height = height,
|
Height = height,
|
||||||
Name = !string.IsNullOrWhiteSpace(canvasName) ? canvasName : $"流程图 {_addCanvasCount++}",
|
Width = width,
|
||||||
Width = height,
|
Name = !string.IsNullOrWhiteSpace(canvasName) ? canvasName : $"流程图{_addCanvasCount++}",
|
||||||
};
|
};
|
||||||
FlowCanvass.Add(model.Guid, model);
|
FlowCanvass.Add(model.Guid, model);
|
||||||
UIContextOperation.Invoke(() =>
|
await UIContextOperation.InvokeAsync(() =>
|
||||||
{
|
{
|
||||||
OnCanvasCreate.Invoke(new CanvasCreateEventArgs(model));
|
OnCanvasCreate.Invoke(new CanvasCreateEventArgs(model));
|
||||||
});
|
});
|
||||||
var info = model.ToInfo();
|
var info = model.ToInfo();
|
||||||
return Task.FromResult(info);
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -799,15 +800,29 @@ namespace Serein.NodeFlow.Env
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="canvasGuid">画布Guid</param>
|
/// <param name="canvasGuid">画布Guid</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public Task<bool> RemoveCanvasAsync(string canvasGuid)
|
public async Task<bool> RemoveCanvasAsync(string canvasGuid)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!FlowCanvass.TryGetValue(canvasGuid, out var model))
|
if (!FlowCanvass.TryGetValue(canvasGuid, out var model))
|
||||||
{
|
{
|
||||||
return Task.FromResult(false);
|
return false;
|
||||||
}
|
}
|
||||||
var count = NodeModels.Values.Count(node => node.CanvasGuid.Equals(canvasGuid));
|
var count = NodeModels.Values.Count(node => node.CanvasGuid.Equals(canvasGuid));
|
||||||
return Task.FromResult(count == 0);
|
if(count > 0)
|
||||||
|
{
|
||||||
|
SereinEnv.WriteLine(InfoType.WARN, "无法删除具有节点的画布");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (FlowCanvass.Remove(canvasGuid))
|
||||||
|
{
|
||||||
|
await UIContextOperation.InvokeAsync(() =>
|
||||||
|
{
|
||||||
|
OnCanvasRemove.Invoke(new CanvasRemoveEventArgs(canvasGuid));
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -981,7 +996,7 @@ namespace Serein.NodeFlow.Env
|
|||||||
PositionOfUI position,
|
PositionOfUI position,
|
||||||
MethodDetailsInfo? methodDetailsInfo = null)
|
MethodDetailsInfo? methodDetailsInfo = null)
|
||||||
{
|
{
|
||||||
if (!FlowCanvass.ContainsKey(canvasGuid))
|
if (!TryGetCanvasModel(canvasGuid,out var cavnasModel))
|
||||||
{
|
{
|
||||||
return Task.FromResult<NodeInfo>(null);
|
return Task.FromResult<NodeInfo>(null);
|
||||||
}
|
}
|
||||||
@@ -1005,16 +1020,17 @@ namespace Serein.NodeFlow.Env
|
|||||||
}
|
}
|
||||||
|
|
||||||
TryAddNode(nodeModel);
|
TryAddNode(nodeModel);
|
||||||
nodeModel.Position = position;
|
nodeModel.CanvasGuid = canvasGuid; // 设置所属于的画布
|
||||||
|
nodeModel.Position = position; // 设置位置
|
||||||
|
|
||||||
// 通知UI更改
|
// 通知UI更改
|
||||||
UIContextOperation?.Invoke(() => OnNodeCreate?.Invoke(new NodeCreateEventArgs(canvasGuid, nodeModel, position)));
|
UIContextOperation?.Invoke(() => OnNodeCreate?.Invoke(new NodeCreateEventArgs(canvasGuid, nodeModel, position)));
|
||||||
|
|
||||||
// 因为需要UI先布置了元素,才能通知UI变更特效
|
// 因为需要UI先布置了元素,才能通知UI变更特效
|
||||||
// 如果不存在流程起始控件,默认设置为流程起始控件
|
// 如果不存在流程起始控件,默认设置为流程起始控件
|
||||||
if (StartNode is null)
|
if (cavnasModel.StartNode is null)
|
||||||
{
|
{
|
||||||
SetStartNode(canvasGuid, nodeModel);
|
SetStartNode(cavnasModel, nodeModel);
|
||||||
}
|
}
|
||||||
var nodeInfo = nodeModel.ToInfo();
|
var nodeInfo = nodeModel.ToInfo();
|
||||||
return Task.FromResult(nodeInfo);
|
return Task.FromResult(nodeInfo);
|
||||||
@@ -1392,15 +1408,16 @@ namespace Serein.NodeFlow.Env
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 设置起点控件
|
/// 设置起点控件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="newNodeGuid"></param>
|
/// <param name="canvasGuid">画布</param>
|
||||||
|
/// <param name="newNodeGuid">节点Guid</param>
|
||||||
public Task<string> SetStartNodeAsync(string canvasGuid, string newNodeGuid)
|
public Task<string> SetStartNodeAsync(string canvasGuid, string newNodeGuid)
|
||||||
{
|
{
|
||||||
if (!FlowCanvass.ContainsKey(canvasGuid) || !TryGetNodeModel(newNodeGuid, out var newStartNodeModel))
|
if (!TryGetCanvasModel(canvasGuid, out var canvasModel) || !TryGetNodeModel(newNodeGuid, out var newStartNodeModel))
|
||||||
{
|
{
|
||||||
return Task.FromResult(StartNode?.Guid ?? string.Empty);
|
return Task.FromResult(canvasModel.StartNode ?? string.Empty);
|
||||||
}
|
}
|
||||||
SetStartNode(canvasGuid, newStartNodeModel);
|
SetStartNode(canvasModel, newStartNodeModel);
|
||||||
return Task.FromResult(StartNode?.Guid ?? string.Empty);
|
return Task.FromResult(canvasModel.StartNode ?? string.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -1512,9 +1529,25 @@ namespace Serein.NodeFlow.Env
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 从Guid获取画布
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="nodeGuid">节点Guid</param>
|
||||||
|
/// <returns>节点Model</returns>
|
||||||
|
/// <exception cref="ArgumentNullException">无法获取节点、Guid/节点为null时报错</exception>
|
||||||
|
public bool TryGetCanvasModel(string nodeGuid, out FlowCanvasDetails canvasDetails)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(nodeGuid))
|
||||||
|
{
|
||||||
|
canvasDetails = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return FlowCanvass.TryGetValue(nodeGuid, out canvasDetails) && canvasDetails is not null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Guid 转 NodeModel
|
/// 从Guid获取节点
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="nodeGuid">节点Guid</param>
|
/// <param name="nodeGuid">节点Guid</param>
|
||||||
/// <returns>节点Model</returns>
|
/// <returns>节点Model</returns>
|
||||||
@@ -1913,15 +1946,11 @@ namespace Serein.NodeFlow.Env
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="newStartNode"></param>
|
/// <param name="newStartNode"></param>
|
||||||
/// <param name="oldStartNode"></param>
|
/// <param name="oldStartNode"></param>
|
||||||
private void SetStartNode(string canvasGuid, NodeModelBase newStartNode)
|
private void SetStartNode(FlowCanvasDetails cavnasModel, NodeModelBase newStartNode)
|
||||||
{
|
{
|
||||||
if (!FlowCanvass.ContainsKey(canvasGuid))
|
var oldNodeGuid = cavnasModel.StartNode;
|
||||||
{
|
cavnasModel.StartNode = newStartNode.Guid;
|
||||||
return;
|
UIContextOperation?.Invoke(() => OnStartNodeChange?.Invoke(new StartNodeChangeEventArgs(cavnasModel.Guid, oldNodeGuid, cavnasModel.StartNode)));
|
||||||
}
|
|
||||||
var oldNodeGuid = StartNode?.Guid;
|
|
||||||
StartNode = newStartNode;
|
|
||||||
UIContextOperation?.Invoke(() => OnStartNodeChange?.Invoke(new StartNodeChangeEventArgs(canvasGuid, oldNodeGuid, StartNode.Guid)));
|
|
||||||
|
|
||||||
//if (OperatingSystem.IsWindows())
|
//if (OperatingSystem.IsWindows())
|
||||||
//{
|
//{
|
||||||
|
|||||||
@@ -238,7 +238,7 @@ namespace Serein.NodeFlow.Env
|
|||||||
/// <param name="width">宽度</param>
|
/// <param name="width">宽度</param>
|
||||||
/// <param name="height">高度</param>
|
/// <param name="height">高度</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<FlowCanvasInfo> CreateCanvasAsync(string canvasName, int width, int height)
|
public async Task<FlowCanvasDetailsInfo> CreateCanvasAsync(string canvasName, int width, int height)
|
||||||
{
|
{
|
||||||
return await currentFlowEnvironment.CreateCanvasAsync(canvasName, width, height);
|
return await currentFlowEnvironment.CreateCanvasAsync(canvasName, width, height);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ namespace Serein.NodeFlow.Env
|
|||||||
}
|
}
|
||||||
|
|
||||||
[AutoSocketHandle(ThemeValue = EnvMsgTheme.CreateCanvas, IsReturnValue = false)]
|
[AutoSocketHandle(ThemeValue = EnvMsgTheme.CreateCanvas, IsReturnValue = false)]
|
||||||
public void CreateCanvas([UseMsgId] string msgId, [UseData] FlowCanvasInfo canvasInfo)
|
public void CreateCanvas([UseMsgId] string msgId, [UseData] FlowCanvasDetailsInfo canvasInfo)
|
||||||
{
|
{
|
||||||
_ = remoteFlowEnvironment.InvokeTriggerAsync(msgId, canvasInfo);
|
_ = remoteFlowEnvironment.InvokeTriggerAsync(msgId, canvasInfo);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -312,7 +312,7 @@ namespace Serein.NodeFlow.Env
|
|||||||
|
|
||||||
|
|
||||||
[AutoSocketHandle(ThemeValue = EnvMsgTheme.CreateCanvas, IsReturnValue = false)]
|
[AutoSocketHandle(ThemeValue = EnvMsgTheme.CreateCanvas, IsReturnValue = false)]
|
||||||
public async Task<FlowCanvasInfo> CreateCanvas(string canvasName, int width, int height)
|
public async Task<FlowCanvasDetailsInfo> CreateCanvas(string canvasName, int width, int height)
|
||||||
{
|
{
|
||||||
var canvasInfo = await environment.CreateCanvasAsync(canvasName, width, height); // 监听到客户端创建节点的请求
|
var canvasInfo = await environment.CreateCanvasAsync(canvasName, width, height); // 监听到客户端创建节点的请求
|
||||||
return canvasInfo;
|
return canvasInfo;
|
||||||
|
|||||||
@@ -131,11 +131,28 @@ namespace Serein.NodeFlow.Env
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 保存项目
|
/// 远程环境下保存项目
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void SaveProject()
|
public void SaveProject()
|
||||||
{
|
{
|
||||||
OnProjectSaving?.Invoke(new ProjectSavingEventArgs());
|
_ = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
// 保存项目
|
||||||
|
var result = await msgClient.SendAndWaitDataAsync<SereinProjectData>(EnvMsgTheme.SaveProject);
|
||||||
|
if (result is not null)
|
||||||
|
{
|
||||||
|
OnProjectSaving?.Invoke(new ProjectSavingEventArgs(result));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取远程环境
|
||||||
|
//var projectData = new SereinProjectData()
|
||||||
|
//{
|
||||||
|
// Librarys = this.FlowLibraryManagement.GetAllLibraryInfo().ToArray(),
|
||||||
|
// Nodes = NodeModels.Values.Select(node => node.ToInfo()).Where(info => info is not null).ToArray(),
|
||||||
|
// StartNode = NodeModels.Values.FirstOrDefault(it => it.IsStart)?.Guid,
|
||||||
|
//};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -167,14 +184,26 @@ namespace Serein.NodeFlow.Env
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
var nodeInfos = flowEnvInfo.Project.Nodes.ToList();
|
// 加载画布
|
||||||
LoadNodeInfos(nodeInfos); // 加载节点
|
foreach (var info in flowEnvInfo.Project.Canvass)
|
||||||
|
|
||||||
var canvasGuid = nodeInfos.FirstOrDefault(item => item.Guid == flowEnvInfo.Project.StartNode)?.CanvasGuid;
|
|
||||||
if (!string.IsNullOrEmpty(canvasGuid))
|
|
||||||
{
|
{
|
||||||
_ = SetStartNodeAsync(canvasGuid, flowEnvInfo.Project.StartNode); // 设置流程起点
|
var canvasModel = new FlowCanvasDetails(this);
|
||||||
|
canvasModel.LoadInfo(info);
|
||||||
|
var e = new CanvasCreateEventArgs(canvasModel);
|
||||||
|
OnCanvasCreate?.Invoke(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 加载节点
|
||||||
|
var nodeInfos = flowEnvInfo.Project.Nodes.ToList();
|
||||||
|
LoadNodeInfos(nodeInfos);
|
||||||
|
|
||||||
|
// 设置每个画布的起始节点
|
||||||
|
foreach (var info in flowEnvInfo.Project.Canvass)
|
||||||
|
{
|
||||||
|
_ = SetStartNodeAsync(info.Guid, info.StartNode); // 设置流程起点
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
UIContextOperation?.Invoke(() =>
|
UIContextOperation?.Invoke(() =>
|
||||||
{
|
{
|
||||||
OnProjectLoaded?.Invoke(new ProjectLoadedEventArgs()); // 加载完成
|
OnProjectLoaded?.Invoke(new ProjectLoadedEventArgs()); // 加载完成
|
||||||
@@ -427,9 +456,9 @@ namespace Serein.NodeFlow.Env
|
|||||||
/// <param name="width">宽度</param>
|
/// <param name="width">宽度</param>
|
||||||
/// <param name="height">高度</param>
|
/// <param name="height">高度</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<FlowCanvasInfo> CreateCanvasAsync(string canvasName, int width, int height)
|
public async Task<FlowCanvasDetailsInfo> CreateCanvasAsync(string canvasName, int width, int height)
|
||||||
{
|
{
|
||||||
var info = await msgClient.SendAndWaitDataAsync<FlowCanvasInfo>(EnvMsgTheme.CreateCanvas, new
|
var info = await msgClient.SendAndWaitDataAsync<FlowCanvasDetailsInfo>(EnvMsgTheme.CreateCanvas, new
|
||||||
{
|
{
|
||||||
canvasName,
|
canvasName,
|
||||||
width,
|
width,
|
||||||
@@ -437,7 +466,7 @@ namespace Serein.NodeFlow.Env
|
|||||||
});
|
});
|
||||||
if (info is not null)
|
if (info is not null)
|
||||||
{
|
{
|
||||||
var model = new FlowCanvasModel(this)
|
var model = new FlowCanvasDetails(this)
|
||||||
{
|
{
|
||||||
Guid = info.Guid,
|
Guid = info.Guid,
|
||||||
Height = info.Height,
|
Height = info.Height,
|
||||||
@@ -506,6 +535,7 @@ namespace Serein.NodeFlow.Env
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 设置远程环境的流程起点节点
|
/// 设置远程环境的流程起点节点
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="canvasGuid">节点画布</param>
|
||||||
/// <param name="nodeGuid">尝试设置为起始节点的节点Guid</param>
|
/// <param name="nodeGuid">尝试设置为起始节点的节点Guid</param>
|
||||||
/// <returns>被设置为起始节点的Guid</returns>
|
/// <returns>被设置为起始节点的Guid</returns>
|
||||||
public async Task<string> SetStartNodeAsync(string canvasGuid, string nodeGuid)
|
public async Task<string> SetStartNodeAsync(string canvasGuid, string nodeGuid)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using Serein.NodeFlow.Model;
|
|||||||
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.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
|
|
||||||
namespace Serein.NodeFlow
|
namespace Serein.NodeFlow
|
||||||
@@ -21,24 +22,23 @@ namespace Serein.NodeFlow
|
|||||||
private ConcurrentDictionary<SingleFlipflopNode, CancellationTokenSource> dictGlobalFlipflop = [];
|
private ConcurrentDictionary<SingleFlipflopNode, CancellationTokenSource> dictGlobalFlipflop = [];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 结束运行时需要执行的方法
|
/// 结束运行时需要执行的方法
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private Func<Task>? ExitAction { get; set; }
|
private Func<Task>? ExitAction { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 初始化选项
|
/// 初始化选项
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public FlowWorkLibrary WorkLibrary { get; }
|
public FlowWorkOptions WorkOptions { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 流程任务管理
|
/// 流程任务管理
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="library"></param>
|
/// <param name="options"></param>
|
||||||
public FlowWorkManagement(FlowWorkLibrary library)
|
public FlowWorkManagement(FlowWorkOptions options)
|
||||||
{
|
{
|
||||||
WorkLibrary = library;
|
WorkOptions = options;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,43 +48,83 @@ namespace Serein.NodeFlow
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<bool> RunAsync(CancellationToken token)
|
public async Task<bool> RunAsync(CancellationToken token)
|
||||||
{
|
{
|
||||||
NodeModelBase? startNode = WorkLibrary.Nodes.FirstOrDefault(node => node.IsStart);
|
#region 注册所有节点所属的类的类型,如果注册失败则退出
|
||||||
if (startNode is null)
|
List<NodeModelBase> nodes = new List<NodeModelBase>();
|
||||||
|
foreach (var item in WorkOptions.Flows.Values)
|
||||||
|
{
|
||||||
|
var temp = item.GetNodes();
|
||||||
|
nodes.AddRange(temp);
|
||||||
|
}
|
||||||
|
if (!RegisterAllType(nodes))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 调用所有流程类的Init、Load事件
|
||||||
|
|
||||||
if (!RegisterAllType())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
var initState = await TryInit();
|
var initState = await TryInit();
|
||||||
if (!initState)
|
if (!initState)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
};
|
}
|
||||||
|
;
|
||||||
var loadState = await TryLoadAsync();
|
var loadState = await TryLoadAsync();
|
||||||
if (!loadState)
|
if (!loadState)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
};
|
}
|
||||||
var task = CallFlipflopNode();
|
;
|
||||||
await CallStartNode(startNode);
|
#endregion
|
||||||
await task;
|
|
||||||
|
// 开始调用流程
|
||||||
|
foreach (var kvp in WorkOptions.Flows)
|
||||||
|
{
|
||||||
|
var guid = kvp.Key;
|
||||||
|
var flow = kvp.Value;
|
||||||
|
var flowNodes = flow.GetNodes();
|
||||||
|
|
||||||
|
// 找到流程的起始节点,开始运行
|
||||||
|
NodeModelBase? startNode = flowNodes.FirstOrDefault(node => node.IsStart);
|
||||||
|
if (startNode is null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 是否后台运行当前画布流程
|
||||||
|
if (flow.IsTaskAsync)
|
||||||
|
{
|
||||||
|
_ = Task.Run(async () => await CallStartNode(startNode));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await CallStartNode(startNode);
|
||||||
|
}
|
||||||
|
var flipflopTasks = CallFlipflopNode(flow); // 获取所有触发器异步任务
|
||||||
|
_ = Task.Run(async () => await flipflopTasks); // 后台调用流程中的触发器
|
||||||
|
}
|
||||||
|
|
||||||
|
// 等待流程运行完成
|
||||||
await CallExit();
|
await CallExit();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region 初始化
|
#region 初始化
|
||||||
private bool RegisterAllType()
|
/// <summary>
|
||||||
|
/// 初始化节点所需的所有类型
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
private bool RegisterAllType(List<NodeModelBase> nodes)
|
||||||
{
|
{
|
||||||
var env = WorkLibrary.Environment;
|
var env = WorkOptions.Environment;
|
||||||
var nodeMds = WorkLibrary.Nodes.Select(item => item.MethodDetails).ToList(); // 获取环境中所有节点的方法信息
|
|
||||||
|
|
||||||
|
|
||||||
|
var nodeMds = nodes.Select(item => item.MethodDetails).ToList(); // 获取环境中所有节点的方法信息
|
||||||
var allMds = new List<MethodDetails>();
|
var allMds = new List<MethodDetails>();
|
||||||
allMds.AddRange(nodeMds.Where(md => md?.ActingInstanceType is not null));
|
allMds.AddRange(nodeMds.Where(md => md?.ActingInstanceType is not null));
|
||||||
allMds.AddRange(WorkLibrary.InitMds.Where(md => md?.ActingInstanceType is not null));
|
allMds.AddRange(WorkOptions.InitMds.Where(md => md?.ActingInstanceType is not null));
|
||||||
allMds.AddRange(WorkLibrary.LoadMds.Where(md => md?.ActingInstanceType is not null));
|
allMds.AddRange(WorkOptions.LoadMds.Where(md => md?.ActingInstanceType is not null));
|
||||||
allMds.AddRange(WorkLibrary.ExitMds.Where(md => md?.ActingInstanceType is not null));
|
allMds.AddRange(WorkOptions.ExitMds.Where(md => md?.ActingInstanceType is not null));
|
||||||
var isSuccessful = true;
|
var isSuccessful = true;
|
||||||
foreach (var md in allMds)
|
foreach (var md in allMds)
|
||||||
{
|
{
|
||||||
@@ -114,10 +154,10 @@ namespace Serein.NodeFlow
|
|||||||
|
|
||||||
private async Task<bool> TryInit()
|
private async Task<bool> TryInit()
|
||||||
{
|
{
|
||||||
var env = WorkLibrary.Environment;
|
var env = WorkOptions.Environment;
|
||||||
var initMds = WorkLibrary.InitMds;
|
var initMds = WorkOptions.InitMds;
|
||||||
var pool = WorkLibrary.FlowContextPool;
|
var pool = WorkOptions.FlowContextPool;
|
||||||
var ioc = WorkLibrary.Environment.IOC;
|
var ioc = WorkOptions.Environment.IOC;
|
||||||
foreach (var md in initMds) // 初始化
|
foreach (var md in initMds) // 初始化
|
||||||
{
|
{
|
||||||
if (!env.TryGetDelegateDetails(md.AssemblyName, md.MethodName, out var dd)) // 流程运行初始化
|
if (!env.TryGetDelegateDetails(md.AssemblyName, md.MethodName, out var dd)) // 流程运行初始化
|
||||||
@@ -136,10 +176,10 @@ namespace Serein.NodeFlow
|
|||||||
}
|
}
|
||||||
private async Task<bool> TryLoadAsync()
|
private async Task<bool> TryLoadAsync()
|
||||||
{
|
{
|
||||||
var env = WorkLibrary.Environment;
|
var env = WorkOptions.Environment;
|
||||||
var loadMds = WorkLibrary.LoadMds;
|
var loadMds = WorkOptions.LoadMds;
|
||||||
var pool = WorkLibrary.FlowContextPool;
|
var pool = WorkOptions.FlowContextPool;
|
||||||
var ioc = WorkLibrary.Environment.IOC;
|
var ioc = WorkOptions.Environment.IOC;
|
||||||
foreach (var md in loadMds) // 加载时
|
foreach (var md in loadMds) // 加载时
|
||||||
{
|
{
|
||||||
if (!env.TryGetDelegateDetails(md.AssemblyName, md.MethodName, out var dd)) // 流程运行初始化
|
if (!env.TryGetDelegateDetails(md.AssemblyName, md.MethodName, out var dd)) // 流程运行初始化
|
||||||
@@ -159,10 +199,10 @@ namespace Serein.NodeFlow
|
|||||||
}
|
}
|
||||||
private async Task<bool> CallExit()
|
private async Task<bool> CallExit()
|
||||||
{
|
{
|
||||||
var env = WorkLibrary.Environment;
|
var env = WorkOptions.Environment;
|
||||||
var mds = WorkLibrary.ExitMds;
|
var mds = WorkOptions.ExitMds;
|
||||||
var pool = WorkLibrary.FlowContextPool;
|
var pool = WorkOptions.FlowContextPool;
|
||||||
var ioc = WorkLibrary.Environment.IOC;
|
var ioc = WorkOptions.Environment.IOC;
|
||||||
|
|
||||||
ioc.Run<FlowInterruptTool>(fit => fit.CancelAllTrigger());// 取消所有中断
|
ioc.Run<FlowInterruptTool>(fit => fit.CancelAllTrigger());// 取消所有中断
|
||||||
foreach (var md in mds) // 结束时
|
foreach (var md in mds) // 结束时
|
||||||
@@ -186,10 +226,10 @@ namespace Serein.NodeFlow
|
|||||||
return isSuccessful;
|
return isSuccessful;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task CallFlipflopNode()
|
private Task CallFlipflopNode(FlowTask flow)
|
||||||
{
|
{
|
||||||
var env = WorkLibrary.Environment;
|
var env = WorkOptions.Environment;
|
||||||
var flipflopNodes = WorkLibrary.Nodes.Where(item => item is SingleFlipflopNode node
|
var flipflopNodes = flow.GetNodes().Where(item => item is SingleFlipflopNode node
|
||||||
&& !node.IsStart
|
&& !node.IsStart
|
||||||
&& node.DebugSetting.IsEnable
|
&& node.DebugSetting.IsEnable
|
||||||
&& node.NotExitPreviousNode())
|
&& node.NotExitPreviousNode())
|
||||||
@@ -206,10 +246,16 @@ namespace Serein.NodeFlow
|
|||||||
}
|
}
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 从某一个节点开始执行
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="startNode"></param>
|
||||||
|
/// <returns></returns>
|
||||||
private async Task CallStartNode(NodeModelBase startNode)
|
private async Task CallStartNode(NodeModelBase startNode)
|
||||||
{
|
{
|
||||||
var pool = WorkLibrary.FlowContextPool;
|
var pool = WorkOptions.FlowContextPool;
|
||||||
var token = WorkLibrary.CancellationTokenSource.Token;
|
var token = WorkOptions.CancellationTokenSource.Token;
|
||||||
var context = pool.Allocate();
|
var context = pool.Allocate();
|
||||||
await startNode.StartFlowAsync(context, token);
|
await startNode.StartFlowAsync(context, token);
|
||||||
context.Exit();
|
context.Exit();
|
||||||
@@ -227,9 +273,9 @@ namespace Serein.NodeFlow
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task StartFlowInSelectNodeAsync(IFlowEnvironment env, NodeModelBase startNode)
|
public async Task StartFlowInSelectNodeAsync(IFlowEnvironment env, NodeModelBase startNode)
|
||||||
{
|
{
|
||||||
var pool = WorkLibrary.FlowContextPool;
|
var pool = WorkOptions.FlowContextPool;
|
||||||
var context = pool.Allocate();
|
var context = pool.Allocate();
|
||||||
var token = WorkLibrary.CancellationTokenSource.Token;
|
var token = WorkOptions.CancellationTokenSource.Token;
|
||||||
await startNode.StartFlowAsync(context, token); // 开始运行时从选定节点开始运行
|
await startNode.StartFlowAsync(context, token); // 开始运行时从选定节点开始运行
|
||||||
context.Reset();
|
context.Reset();
|
||||||
pool.Free(context);
|
pool.Free(context);
|
||||||
@@ -294,7 +340,7 @@ namespace Serein.NodeFlow
|
|||||||
CancellationToken singleToken)
|
CancellationToken singleToken)
|
||||||
{
|
{
|
||||||
|
|
||||||
var pool = WorkLibrary.FlowContextPool;
|
var pool = WorkOptions.FlowContextPool;
|
||||||
while (!singleToken.IsCancellationRequested && !singleToken.IsCancellationRequested)
|
while (!singleToken.IsCancellationRequested && !singleToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|||||||
@@ -9,10 +9,29 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace Serein.NodeFlow
|
namespace Serein.NodeFlow
|
||||||
{
|
{
|
||||||
|
|
||||||
|
public class FlowTask
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 是否异步启动流程
|
||||||
|
/// </summary>
|
||||||
|
public bool IsTaskAsync { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 流程起始节点
|
||||||
|
/// </summary>
|
||||||
|
public Func<NodeModelBase> GetStartNode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取当前画布流程的所有节点
|
||||||
|
/// </summary>
|
||||||
|
public Func<List<NodeModelBase>> GetNodes { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 节点任务执行依赖
|
/// 节点任务执行依赖
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class FlowWorkLibrary()
|
public class FlowWorkOptions()
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 流程运行环境
|
/// 流程运行环境
|
||||||
@@ -29,14 +48,21 @@ namespace Serein.NodeFlow
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public Serein.Library.Utils.ObjectPool<IDynamicContext> FlowContextPool { get; set; }
|
public Serein.Library.Utils.ObjectPool<IDynamicContext> FlowContextPool { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 每个画布需要启用的节点
|
||||||
|
/// </summary>
|
||||||
|
public Dictionary<string, FlowTask> Flows { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 当前任务加载的所有节点
|
/// 当前任务加载的所有节点
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<NodeModelBase> Nodes { get; set; }// = nodes;
|
//public List<NodeModelBase> Nodes { get; set; }// = nodes;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 需要注册的类型
|
/// 需要注册的类型
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Dictionary<RegisterSequence, List<Type>> AutoRegisterTypes { get; set; } //= autoRegisterTypes;
|
public Dictionary<RegisterSequence, List<Type>> AutoRegisterTypes { get; set; } //= autoRegisterTypes;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 初始化时需要的方法
|
/// 初始化时需要的方法
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -59,10 +59,12 @@ namespace Serein.Library
|
|||||||
/// 是否通知UI
|
/// 是否通知UI
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsNotification = false;
|
public bool IsNotification = false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否使用Console.WriteLine打印
|
/// 是否使用Console.WriteLine打印
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsPrint = false;
|
public bool IsPrint = false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否禁止参数进行修改(初始化后不能再通过 Setter 修改)
|
/// 是否禁止参数进行修改(初始化后不能再通过 Setter 修改)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
68
Workbench/Api/IFlowCanvas.cs
Normal file
68
Workbench/Api/IFlowCanvas.cs
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
using Serein.Library;
|
||||||
|
using Serein.Workbench.Node.View;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Serein.Workbench.Api
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 流程画布
|
||||||
|
/// </summary>
|
||||||
|
public interface IFlowCanvas
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 画布标识
|
||||||
|
/// </summary>
|
||||||
|
string Guid { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 画布名称
|
||||||
|
/// </summary>
|
||||||
|
string Name { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 移除节点
|
||||||
|
/// </summary>
|
||||||
|
void Remove(NodeControlBase nodeControl);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 添加节点
|
||||||
|
/// </summary>
|
||||||
|
void Add(NodeControlBase nodeControl);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建节点之间方法调用关系
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fromNodeControl">调用顺序中的起始节点</param>
|
||||||
|
/// <param name="toNodeControl">下一节点</param>
|
||||||
|
/// <param name="type">调用类型</param>
|
||||||
|
void CreateInvokeConnection(NodeControlBase fromNodeControl, NodeControlBase toNodeControl, ConnectionInvokeType type);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 移除节点之间的调用关系
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fromNodeControl">调用顺序中的起始节点</param>
|
||||||
|
/// <param name="toNodeControl">下一节点</param>
|
||||||
|
void RemoveInvokeConnection(NodeControlBase fromNodeControl, NodeControlBase toNodeControl);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建节点之间的参数传递关系
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fromNodeControl">参数来源节点</param>
|
||||||
|
/// <param name="toNodeControl">获取参数的节点</param>
|
||||||
|
/// <param name="type">指示参数是如何获取的</param>
|
||||||
|
/// <param name="index">作用在节点的第几个入参</param>
|
||||||
|
void CreateArgConnection(NodeControlBase fromNodeControl, NodeControlBase toNodeControl, ConnectionArgSourceType type, int index);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 移除节点之间的参数传递关系
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fromNodeControl">参数来源节点</param>
|
||||||
|
/// <param name="toNodeControl">获取参数的节点</param>
|
||||||
|
/// <param name="index">移除节点第几个入参</param>
|
||||||
|
void RemoveArgConnection(NodeControlBase fromNodeControl, NodeControlBase toNodeControl, int index);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -32,7 +32,7 @@ namespace Serein.Workbench
|
|||||||
collection.AddSingleton<FlowLibrarysViewModel>();
|
collection.AddSingleton<FlowLibrarysViewModel>();
|
||||||
collection.AddSingleton<FlowEditViewModel>();
|
collection.AddSingleton<FlowEditViewModel>();
|
||||||
|
|
||||||
collection.AddTransient<FlowCanvasViewModel>(); // 依赖信息
|
collection.AddTransient<FlowCanvasViewModel>(); // 画布
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void AddWorkbenchServices(this IServiceCollection collection)
|
public static void AddWorkbenchServices(this IServiceCollection collection)
|
||||||
@@ -40,8 +40,8 @@ namespace Serein.Workbench
|
|||||||
collection.AddSingleton<IFlowEEForwardingService, FlowEEForwardingService>(); // 流程事件管理
|
collection.AddSingleton<IFlowEEForwardingService, FlowEEForwardingService>(); // 流程事件管理
|
||||||
collection.AddSingleton<IWorkbenchEventService, WorkbenchEventService>(); // 流程事件管理
|
collection.AddSingleton<IWorkbenchEventService, WorkbenchEventService>(); // 流程事件管理
|
||||||
collection.AddSingleton<FlowNodeService>(); // 节点操作管理
|
collection.AddSingleton<FlowNodeService>(); // 节点操作管理
|
||||||
// collection.AddSingleton<IKeyEventService, KeyEventService>(); // 按键事件管理
|
// collection.AddSingleton<IKeyEventService, KeyEventService>(); // 按键事件管理
|
||||||
//collection.AddSingleton<FlowNodeControlService>(); // 流程节点控件管理
|
//collection.AddSingleton<FlowNodeControlService>(); // 流程节点控件管理
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -97,21 +97,17 @@ namespace Serein.Workbench
|
|||||||
collection.AddViewModelServices();
|
collection.AddViewModelServices();
|
||||||
var services = collection.BuildServiceProvider(); // 绑定并返回获取实例的服务接口
|
var services = collection.BuildServiceProvider(); // 绑定并返回获取实例的服务接口
|
||||||
App.ServiceProvider = services;
|
App.ServiceProvider = services;
|
||||||
_ = Task.Run(async () =>
|
#if DEBUG
|
||||||
{
|
_ = this.LoadLocalProjectAsync();
|
||||||
await Task.Delay(500);
|
#endif
|
||||||
await this.LoadLocalProjectAsync();
|
|
||||||
App.GetService<IFlowEnvironment>().LoadProject(new FlowEnvInfo { Project = App.FlowProjectData }, App.FileDataPath);
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private async Task LoadLocalProjectAsync()
|
private async Task LoadLocalProjectAsync()
|
||||||
{
|
{
|
||||||
|
await Task.Delay(500);
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
if (1 == 1)
|
if (1 == 10)
|
||||||
{
|
{
|
||||||
// 这里是测试代码,可以删除
|
// 这里是测试代码,可以删除
|
||||||
string filePath;
|
string filePath;
|
||||||
@@ -124,7 +120,7 @@ namespace Serein.Workbench
|
|||||||
App.FlowProjectData = JsonConvert.DeserializeObject<SereinProjectData>(content);
|
App.FlowProjectData = JsonConvert.DeserializeObject<SereinProjectData>(content);
|
||||||
App.FileDataPath = System.IO.Path.GetDirectoryName(filePath)!; // filePath;//
|
App.FileDataPath = System.IO.Path.GetDirectoryName(filePath)!; // filePath;//
|
||||||
var dir = Path.GetDirectoryName(filePath);
|
var dir = Path.GetDirectoryName(filePath);
|
||||||
|
App.GetService<IFlowEnvironment>().LoadProject(new FlowEnvInfo { Project = App.FlowProjectData }, App.FileDataPath);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ using Serein.Library.Utils;
|
|||||||
using Serein.NodeFlow;
|
using Serein.NodeFlow;
|
||||||
using Serein.NodeFlow.Env;
|
using Serein.NodeFlow.Env;
|
||||||
using Serein.NodeFlow.Tool;
|
using Serein.NodeFlow.Tool;
|
||||||
|
using Serein.Workbench.Api;
|
||||||
using Serein.Workbench.Extension;
|
using Serein.Workbench.Extension;
|
||||||
using Serein.Workbench.Node;
|
using Serein.Workbench.Node;
|
||||||
using Serein.Workbench.Node.View;
|
using Serein.Workbench.Node.View;
|
||||||
@@ -292,14 +293,14 @@ namespace Serein.Workbench
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
InitializeCanvas(project.Basic.Canvas.Width, project.Basic.Canvas.Height);// 设置画布大小
|
//InitializeCanvas(project.Basic.Canvas.Width, project.Basic.Canvas.Height);// 设置画布大小
|
||||||
//foreach (var connection in Connections)
|
//foreach (var connection in Connections)
|
||||||
//{
|
//{
|
||||||
// connection.RefreshLine(); // 窗体完成加载后试图刷新所有连接线
|
// connection.RefreshLine(); // 窗体完成加载后试图刷新所有连接线
|
||||||
//}
|
//}
|
||||||
SereinEnv.WriteLine(InfoType.INFO, $"运行环境当前工作目录:{System.IO.Directory.GetCurrentDirectory()}");
|
SereinEnv.WriteLine(InfoType.INFO, $"运行环境当前工作目录:{System.IO.Directory.GetCurrentDirectory()}");
|
||||||
|
|
||||||
var canvasData = project.Basic.Canvas;
|
/*var canvasData = project.Basic.Canvas;
|
||||||
if (canvasData is not null)
|
if (canvasData is not null)
|
||||||
{
|
{
|
||||||
scaleTransform.ScaleX = 1;
|
scaleTransform.ScaleX = 1;
|
||||||
@@ -312,7 +313,7 @@ namespace Serein.Workbench
|
|||||||
translateTransform.Y += canvasData.ViewY;
|
translateTransform.Y += canvasData.ViewY;
|
||||||
// 应用变换组
|
// 应用变换组
|
||||||
FlowChartCanvas.RenderTransform = canvasTransformGroup;
|
FlowChartCanvas.RenderTransform = canvasTransformGroup;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -356,15 +357,15 @@ namespace Serein.Workbench
|
|||||||
|
|
||||||
projectData.Basic = new Basic
|
projectData.Basic = new Basic
|
||||||
{
|
{
|
||||||
Canvas = new FlowCanvasInfo
|
//Canvas = new FlowCanvasInfo
|
||||||
{
|
//{
|
||||||
Height = FlowChartCanvas.Height,
|
// Height = FlowChartCanvas.Height,
|
||||||
Width = FlowChartCanvas.Width,
|
// Width = FlowChartCanvas.Width,
|
||||||
ViewX = translateTransform.X,
|
// ViewX = translateTransform.X,
|
||||||
ViewY = translateTransform.Y,
|
// ViewY = translateTransform.Y,
|
||||||
ScaleX = scaleTransform.ScaleX,
|
// ScaleX = scaleTransform.ScaleX,
|
||||||
ScaleY = scaleTransform.ScaleY,
|
// ScaleY = scaleTransform.ScaleY,
|
||||||
},
|
//},
|
||||||
Versions = "1",
|
Versions = "1",
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -527,7 +528,7 @@ namespace Serein.Workbench
|
|||||||
/// 节点连接关系变更
|
/// 节点连接关系变更
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="eventArgs"></param>
|
/// <param name="eventArgs"></param>
|
||||||
private void FlowEnvironment_NodeConnectChangeEvemt(NodeConnectChangeEventArgs eventArgs)
|
private void FlowEnvironment_NodeConnectChangeEvemt(NodeConnectChangeEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
string fromNodeGuid = eventArgs.FromNodeGuid;
|
string fromNodeGuid = eventArgs.FromNodeGuid;
|
||||||
string toNodeGuid = eventArgs.ToNodeGuid;
|
string toNodeGuid = eventArgs.ToNodeGuid;
|
||||||
@@ -2444,7 +2445,7 @@ namespace Serein.Workbench
|
|||||||
var controlObj = Activator.CreateInstance(controlType, [viewModel]);
|
var controlObj = Activator.CreateInstance(controlType, [viewModel]);
|
||||||
if (controlObj is NodeControlBase nodeControl)
|
if (controlObj is NodeControlBase nodeControl)
|
||||||
{
|
{
|
||||||
nodeControl.NodeCanvas = nodeCanvas;
|
nodeControl.FlowCanvas = (Api.IFlowCanvas)nodeCanvas;
|
||||||
return nodeControl;
|
return nodeControl;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -2731,6 +2732,7 @@ public class FlowLibrary
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 顶部菜单栏 - 远程管理
|
#region 顶部菜单栏 - 远程管理
|
||||||
private async void ButtonStartRemoteServer_Click(object sender, RoutedEventArgs e)
|
private async void ButtonStartRemoteServer_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Reflection.Metadata;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -13,35 +14,50 @@ using System.Xml.Linq;
|
|||||||
|
|
||||||
namespace Serein.Workbench.Models
|
namespace Serein.Workbench.Models
|
||||||
{
|
{
|
||||||
public partial class FlowCanvasModel : ObservableObject
|
public partial class FlowEditorTabModel : ObservableObject
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// tab 名称
|
||||||
|
/// </summary>
|
||||||
public string Name
|
public string Name
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
|
||||||
var vm = (FlowCanvasViewModel)content.DataContext;
|
var vm = (FlowCanvasViewModel)Content.DataContext;
|
||||||
return vm.Name;
|
return vm.Model.Name ?? "null";
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
var vm = (FlowCanvasViewModel)content.DataContext;
|
var vm = (FlowCanvasViewModel)Content.DataContext;
|
||||||
vm.Name = value;
|
vm.Model.Name = value;
|
||||||
OnPropertyChanged(nameof(Name));
|
OnPropertyChanged(nameof(Name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 正在选中
|
||||||
|
/// </summary>
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private bool _isSelected;
|
private bool _isSelected;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 正在编辑标题
|
||||||
|
/// </summary>
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private bool _isEditing;
|
private bool _isEditing;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// tab对应的控件
|
||||||
|
/// </summary>
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private FlowCanvasView content;
|
private FlowCanvasView content;
|
||||||
|
|
||||||
|
|
||||||
public FlowCanvasModel()
|
public FlowEditorTabModel(FlowCanvasView content)
|
||||||
{
|
{
|
||||||
|
this.Content = content;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
using Serein.Library;
|
using Serein.Library;
|
||||||
using Serein.Library.Api;
|
using Serein.Library.Api;
|
||||||
|
using Serein.Workbench.Api;
|
||||||
using Serein.Workbench.Node.ViewModel;
|
using Serein.Workbench.Node.ViewModel;
|
||||||
|
using Serein.Workbench.Views;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Data;
|
using System.Windows.Data;
|
||||||
@@ -18,13 +20,14 @@ namespace Serein.Workbench.Node.View
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 节点所在的画布(以后需要将画布封装出来,实现多画布的功能)
|
/// 节点所在的画布(以后需要将画布封装出来,实现多画布的功能)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Canvas NodeCanvas { get; set; }
|
public IFlowCanvas FlowCanvas { get; set; }
|
||||||
|
|
||||||
private INodeContainerControl nodeContainerControl;
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 如果该节点放置在了某个容器节点,就会记录这个容器节点
|
/// 如果该节点放置在了某个容器节点,就会记录这个容器节点
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private INodeContainerControl NodeContainerControl { get; }
|
|
||||||
|
private INodeContainerControl nodeContainerControl;
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 记录与该节点控件有关的所有连接
|
/// 记录与该节点控件有关的所有连接
|
||||||
@@ -53,11 +56,11 @@ namespace Serein.Workbench.Node.View
|
|||||||
public void PlaceToContainer(INodeContainerControl nodeContainerControl)
|
public void PlaceToContainer(INodeContainerControl nodeContainerControl)
|
||||||
{
|
{
|
||||||
this.nodeContainerControl = nodeContainerControl;
|
this.nodeContainerControl = nodeContainerControl;
|
||||||
NodeCanvas.Children.Remove(this); // 临时从画布上移除
|
FlowCanvas.Remove(this); // 临时从画布上移除
|
||||||
var result = nodeContainerControl.PlaceNode(this);
|
var result = nodeContainerControl.PlaceNode(this);
|
||||||
if (!result) // 检查是否放置成功,如果不成功,需要重新添加回来
|
if (!result) // 检查是否放置成功,如果不成功,需要重新添加回来
|
||||||
{
|
{
|
||||||
NodeCanvas.Children.Add(this); // 从画布上移除
|
FlowCanvas.Add(this); // 从画布上移除
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -70,7 +73,7 @@ namespace Serein.Workbench.Node.View
|
|||||||
var result = nodeContainerControl.TakeOutNode(this); // 从控件取出
|
var result = nodeContainerControl.TakeOutNode(this); // 从控件取出
|
||||||
if (result) // 移除成功时才添加到画布上
|
if (result) // 移除成功时才添加到画布上
|
||||||
{
|
{
|
||||||
NodeCanvas.Children.Add(this); // 重新添加到画布上
|
FlowCanvas.Add(this); // 重新添加到画布上
|
||||||
if (nodeContainerControl is NodeControlBase containerControl)
|
if (nodeContainerControl is NodeControlBase containerControl)
|
||||||
{
|
{
|
||||||
this.ViewModel.NodeModel.Position.X = containerControl.ViewModel.NodeModel.Position.X + containerControl.Width + 10;
|
this.ViewModel.NodeModel.Position.X = containerControl.ViewModel.NodeModel.Position.X + containerControl.Width + 10;
|
||||||
@@ -128,20 +131,12 @@ namespace Serein.Workbench.Node.View
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void SetBinding()
|
public void SetBinding()
|
||||||
{
|
{
|
||||||
// 绑定 Canvas.Left
|
var p = ViewModel.NodeModel.Position;
|
||||||
Binding leftBinding = new Binding("X")
|
|
||||||
{
|
Binding leftBinding = new(nameof(p.X)) { Source = p, Mode = BindingMode.TwoWay };
|
||||||
Source = ViewModel.NodeModel.Position, // 如果 X 属性在当前 DataContext 中
|
|
||||||
Mode = BindingMode.TwoWay
|
|
||||||
};
|
|
||||||
BindingOperations.SetBinding(this, Canvas.LeftProperty, leftBinding);
|
BindingOperations.SetBinding(this, Canvas.LeftProperty, leftBinding);
|
||||||
|
|
||||||
// 绑定 Canvas.Top
|
Binding topBinding = new(nameof(p.Y)) { Source = p, Mode = BindingMode.TwoWay };
|
||||||
Binding topBinding = new Binding("Y")
|
|
||||||
{
|
|
||||||
Source = ViewModel.NodeModel.Position, // 如果 Y 属性在当前 DataContext 中
|
|
||||||
Mode = BindingMode.TwoWay
|
|
||||||
};
|
|
||||||
BindingOperations.SetBinding(this, Canvas.TopProperty, topBinding);
|
BindingOperations.SetBinding(this, Canvas.TopProperty, topBinding);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Serein.NodeFlow.Model;
|
using Serein.NodeFlow.Model;
|
||||||
|
using Serein.Workbench.Api;
|
||||||
using Serein.Workbench.Node.ViewModel;
|
using Serein.Workbench.Node.ViewModel;
|
||||||
|
|
||||||
namespace Serein.Workbench.Node.View
|
namespace Serein.Workbench.Node.View
|
||||||
|
|||||||
@@ -25,9 +25,11 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Remove="Node\FlipflopRegionControl.xaml.cs" />
|
<Compile Remove="Node\FlipflopRegionControl.xaml.cs" />
|
||||||
|
<Compile Remove="Node\INodeContainerControl.cs" />
|
||||||
<Compile Remove="Node\Junction\NodeJunctionViewBase.cs" />
|
<Compile Remove="Node\Junction\NodeJunctionViewBase.cs" />
|
||||||
<Compile Remove="Node\NodeBase.cs" />
|
<Compile Remove="Node\NodeBase.cs" />
|
||||||
<Compile Remove="Node\View\ActionRegionControl.xaml.cs" />
|
<Compile Remove="Node\View\ActionRegionControl.xaml.cs" />
|
||||||
|
<Compile Remove="Services\NodeControlService.cs" />
|
||||||
<Compile Remove="Themes\ConditionControl.xaml.cs" />
|
<Compile Remove="Themes\ConditionControl.xaml.cs" />
|
||||||
<Compile Remove="Themes\ConditionControlModel.cs" />
|
<Compile Remove="Themes\ConditionControlModel.cs" />
|
||||||
<Compile Remove="Themes\ConnectionControl.xaml.cs" />
|
<Compile Remove="Themes\ConnectionControl.xaml.cs" />
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ namespace Serein.Workbench.Services
|
|||||||
/// 转发流程运行环境各个事件的实现类
|
/// 转发流程运行环境各个事件的实现类
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="flowEnvironment"></param>
|
/// <param name="flowEnvironment"></param>
|
||||||
/// <param name="flowNodeControlService"></param>
|
/// <param name="flowEnvironmentEvent"></param>
|
||||||
public FlowEEForwardingService(IFlowEnvironment flowEnvironment,
|
public FlowEEForwardingService(IFlowEnvironment flowEnvironment,
|
||||||
IFlowEnvironmentEvent flowEnvironmentEvent)
|
IFlowEnvironmentEvent flowEnvironmentEvent)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
using Serein.Library;
|
using Serein.Library;
|
||||||
using Serein.Library.Api;
|
using Serein.Library.Api;
|
||||||
using Serein.Workbench.Api;
|
using Serein.Workbench.Api;
|
||||||
|
using Serein.Workbench.Node;
|
||||||
using Serein.Workbench.Node.View;
|
using Serein.Workbench.Node.View;
|
||||||
using Serein.Workbench.Node.ViewModel;
|
using Serein.Workbench.Node.ViewModel;
|
||||||
|
using Serein.Workbench.ViewModels;
|
||||||
using Serein.Workbench.Views;
|
using Serein.Workbench.Views;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
|
||||||
namespace Serein.Workbench.Services
|
namespace Serein.Workbench.Services
|
||||||
{
|
{
|
||||||
@@ -12,9 +15,23 @@ namespace Serein.Workbench.Services
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class FlowNodeService
|
public class FlowNodeService
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
#region 流程节点操作的相关事件
|
#region 流程节点操作的相关事件
|
||||||
public Action<FlowCanvasView> OnCreateFlowCanvasView { get; set; }
|
/// <summary>
|
||||||
public Action<string> OnRemoveFlowCanvasView { get; set; }
|
/// 添加了画布
|
||||||
|
/// </summary>
|
||||||
|
public Action<FlowCanvasView> OnCreateFlowCanvasView { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 移除了画布
|
||||||
|
/// </summary>
|
||||||
|
public Action<FlowCanvasView> OnRemoveFlowCanvasView { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 添加了节点
|
||||||
|
/// </summary>
|
||||||
|
public Action<NodeControlBase> OnCreateNode { get; set; }
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
@@ -32,7 +49,7 @@ namespace Serein.Workbench.Services
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 当前需要创建的节点类型
|
/// 当前需要创建的节点类型
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public NodeControlType? CurrentNodeControlType { get; set; }
|
public NodeControlType CurrentNodeControlType { get; set; } = NodeControlType.None;
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -55,23 +72,27 @@ namespace Serein.Workbench.Services
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public NodeControlBase? ConnectionEndNode { get; set; }
|
public NodeControlBase? ConnectionEndNode { get; set; }
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 记录流程画布
|
/// 记录流程画布
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly Dictionary<string, FlowCanvasView> FlowCanvasViews = [];
|
private readonly Dictionary<string, FlowCanvasView> Canvass = [];
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 记录加载的节点
|
/// 记录加载的节点
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly Dictionary<string, NodeControlViewModelBase> NodeControls = [];
|
private readonly Dictionary<string, NodeControlBase> NodeControls = [];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 运行环境接口
|
||||||
|
/// </summary>
|
||||||
private readonly IFlowEnvironment flowEnvironment;
|
private readonly IFlowEnvironment flowEnvironment;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 运行环境事件转发器
|
||||||
|
/// </summary>
|
||||||
private readonly IFlowEEForwardingService flowEEForwardingService;
|
private readonly IFlowEEForwardingService flowEEForwardingService;
|
||||||
|
|
||||||
|
|
||||||
#region 初始化
|
#region 初始化
|
||||||
public FlowNodeService(IFlowEnvironment flowEnvironment,
|
public FlowNodeService(IFlowEnvironment flowEnvironment,
|
||||||
IFlowEEForwardingService flowEEForwardingService)
|
IFlowEEForwardingService flowEEForwardingService)
|
||||||
@@ -79,44 +100,292 @@ namespace Serein.Workbench.Services
|
|||||||
this.flowEnvironment = flowEnvironment;
|
this.flowEnvironment = flowEnvironment;
|
||||||
this.flowEEForwardingService = flowEEForwardingService;
|
this.flowEEForwardingService = flowEEForwardingService;
|
||||||
InitFlowEvent();
|
InitFlowEvent();
|
||||||
|
InitNodeType();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void InitFlowEvent()
|
|
||||||
|
/// <summary>
|
||||||
|
/// 注册节点类型
|
||||||
|
/// </summary>
|
||||||
|
private void InitNodeType()
|
||||||
{
|
{
|
||||||
flowEEForwardingService.OnCanvasCreate += FlowEEForwardingService_OnCanvasCreate;
|
flowEnvironment.NodeMVVMManagement.RegisterUI(NodeControlType.UI, typeof(UINodeControl), typeof(UINodeControlViewModel));
|
||||||
flowEEForwardingService.OnCanvasRemove += FlowEEForwardingService_OnCanvasRemove;
|
flowEnvironment.NodeMVVMManagement.RegisterUI(NodeControlType.Action, typeof(ActionNodeControl), typeof(ActionNodeControlViewModel));
|
||||||
flowEEForwardingService.OnNodeCreate += FlowEEForwardingService_OnNodeCreate;
|
flowEnvironment.NodeMVVMManagement.RegisterUI(NodeControlType.Flipflop, typeof(FlipflopNodeControl), typeof(FlipflopNodeControlViewModel));
|
||||||
flowEEForwardingService.OnNodeRemove += FlowEEForwardingService_OnNodeRemove;
|
flowEnvironment.NodeMVVMManagement.RegisterUI(NodeControlType.ExpOp, typeof(ExpOpNodeControl), typeof(ExpOpNodeControlViewModel));
|
||||||
|
flowEnvironment.NodeMVVMManagement.RegisterUI(NodeControlType.ExpCondition, typeof(ConditionNodeControl), typeof(ConditionNodeControlViewModel));
|
||||||
|
flowEnvironment.NodeMVVMManagement.RegisterUI(NodeControlType.ConditionRegion, typeof(ConditionRegionControl), typeof(ConditionRegionNodeControlViewModel));
|
||||||
|
flowEnvironment.NodeMVVMManagement.RegisterUI(NodeControlType.GlobalData, typeof(GlobalDataControl), typeof(GlobalDataNodeControlViewModel));
|
||||||
|
flowEnvironment.NodeMVVMManagement.RegisterUI(NodeControlType.Script, typeof(ScriptNodeControl), typeof(ScriptNodeControlViewModel));
|
||||||
|
flowEnvironment.NodeMVVMManagement.RegisterUI(NodeControlType.NetScript, typeof(NetScriptNodeControl), typeof(NetScriptNodeControlViewModel));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 注册节点事件
|
||||||
|
/// </summary>
|
||||||
|
private void InitFlowEvent()
|
||||||
|
{
|
||||||
|
flowEEForwardingService.OnCanvasCreate += FlowEEForwardingService_OnCanvasCreate; // 创建了画布
|
||||||
|
flowEEForwardingService.OnCanvasRemove += FlowEEForwardingService_OnCanvasRemove; // 移除了画布
|
||||||
|
flowEEForwardingService.OnNodeCreate += FlowEEForwardingService_OnNodeCreate; // 创建了节点
|
||||||
|
flowEEForwardingService.OnNodeRemove += FlowEEForwardingService_OnNodeRemove; // 移除了节点
|
||||||
|
|
||||||
|
flowEEForwardingService.OnNodePlace += FlowEEForwardingService_OnNodePlace; // 节点放置在容器中
|
||||||
|
flowEEForwardingService.OnNodeTakeOut += FlowEEForwardingService_OnNodeTakeOut; ; // 节点从容器中取出
|
||||||
|
|
||||||
|
flowEEForwardingService.OnNodeConnectChange += FlowEEForwardingService_OnNodeConnectChange; // 节点连接状态改变事件
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FlowEEForwardingService_OnNodeConnectChange(NodeConnectChangeEventArgs e)
|
||||||
|
{
|
||||||
|
var canvasGuid = e.CanvasGuid;
|
||||||
|
string fromNodeGuid = e.FromNodeGuid;
|
||||||
|
string toNodeGuid = e.ToNodeGuid;
|
||||||
|
if (!TryGetCanvas(canvasGuid, out var flowCanvas)
|
||||||
|
|| flowCanvas is not IFlowCanvas flow
|
||||||
|
|| !TryGetControl(fromNodeGuid, out var fromNode)
|
||||||
|
|| !TryGetControl(toNodeGuid, out var toNode))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Action? action = (e.JunctionOfConnectionType, e.ChangeType) switch
|
||||||
|
{
|
||||||
|
(JunctionOfConnectionType.Invoke, NodeConnectChangeEventArgs.ConnectChangeType.Create) => () => flow.CreateInvokeConnection(fromNode, toNode, e.ConnectionInvokeType), // 创建节点之间的调用关系
|
||||||
|
(JunctionOfConnectionType.Invoke, NodeConnectChangeEventArgs.ConnectChangeType.Remove) => () => flow.RemoveInvokeConnection(fromNode, toNode), // 移除节点之间的调用关系
|
||||||
|
(JunctionOfConnectionType.Arg, NodeConnectChangeEventArgs.ConnectChangeType.Create) => () => flow.CreateArgConnection(fromNode, toNode, e.ConnectionArgSourceType, e.ArgIndex), // 创建节点之间的参数传递关系
|
||||||
|
(JunctionOfConnectionType.Arg, NodeConnectChangeEventArgs.ConnectChangeType.Remove) => () => flow.RemoveArgConnection(fromNode, toNode, e.ArgIndex), // 移除节点之间的参数传递关系
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
action?.Invoke();
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FlowEEForwardingService_OnNodeTakeOut(NodeTakeOutEventArgs eventArgs)
|
||||||
|
{
|
||||||
|
string nodeGuid = eventArgs.NodeGuid;
|
||||||
|
if (!TryGetControl(nodeGuid, out var nodeControl))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
nodeControl.TakeOutContainer(); // 从容器节点中取出
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FlowEEForwardingService_OnNodePlace(NodePlaceEventArgs eventArgs)
|
||||||
|
{
|
||||||
|
string nodeGuid = eventArgs.NodeGuid;
|
||||||
|
string containerNodeGuid = eventArgs.ContainerNodeGuid;
|
||||||
|
if (!TryGetControl(nodeGuid, out var nodeControl)
|
||||||
|
|| !TryGetControl(containerNodeGuid, out var containerNodeControl))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (containerNodeControl is not INodeContainerControl containerControl)
|
||||||
|
{
|
||||||
|
SereinEnv.WriteLine(InfoType.WARN,
|
||||||
|
$"节点[{nodeGuid}]无法放置于节点[{containerNodeGuid}]," +
|
||||||
|
$"因为后者并不实现 INodeContainerControl 接口");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
nodeControl.PlaceToContainer(containerControl); // 放置在容器节点中
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 节点、画布相关的事件
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 节点移除
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="eventArgs"></param>
|
||||||
private void FlowEEForwardingService_OnNodeRemove(NodeRemoveEventArgs eventArgs)
|
private void FlowEEForwardingService_OnNodeRemove(NodeRemoveEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
if (!TryGetCanvas(eventArgs.CanvasGuid, out var nodeCanvas) || nodeCanvas is not IFlowCanvas api)
|
||||||
|
{
|
||||||
|
SereinEnv.WriteLine(InfoType.INFO, $"无法移除节点,画布不存在。");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!TryGetControl(eventArgs.NodeGuid, out var nodeControl))
|
||||||
|
{
|
||||||
|
SereinEnv.WriteLine(InfoType.INFO, $"无法移除节点,节点不存在。");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
api.Remove(nodeControl);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 节点创建
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="eventArgs"></param>
|
||||||
|
|
||||||
private void FlowEEForwardingService_OnNodeCreate(NodeCreateEventArgs eventArgs)
|
private void FlowEEForwardingService_OnNodeCreate(NodeCreateEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
#region 校验事件传入值
|
||||||
|
var position = eventArgs.Position;
|
||||||
|
var cavnasGuid = eventArgs.CanvasGuid;
|
||||||
|
var nodeModel = eventArgs.NodeModel;
|
||||||
|
if (NodeControls.ContainsKey(nodeModel.Guid))
|
||||||
|
{
|
||||||
|
SereinEnv.WriteLine(InfoType.WARN, $"创建节点时发生意外:节点Guid重复 - {nodeModel.Guid}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!flowEnvironment.NodeMVVMManagement.TryGetType(nodeModel.ControlType, out var nodeMVVM))
|
||||||
|
{
|
||||||
|
SereinEnv.WriteLine(InfoType.INFO, $"无法创建{nodeModel.ControlType}节点,节点类型尚未注册。");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (nodeMVVM.ControlType == null|| nodeMVVM.ViewModelType == null)
|
||||||
|
{
|
||||||
|
SereinEnv.WriteLine(InfoType.INFO, $"无法创建{nodeModel.ControlType}节点,UI类型尚未注册(请通过 NodeMVVMManagement.RegisterUI() 方法进行注册)。");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TryGetCanvas(cavnasGuid, out var nodeCanvas))
|
||||||
|
{
|
||||||
|
SereinEnv.WriteLine(InfoType.INFO, $"无法创建{nodeModel.ControlType}节点,不存在画布【{cavnasGuid}】。");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 创建控件
|
||||||
|
|
||||||
|
NodeControlBase nodeControl;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
nodeControl = CreateNodeControl(nodeMVVM.ControlType, // 控件UI类型
|
||||||
|
nodeMVVM.ViewModelType, // 控件VIewModel类型
|
||||||
|
nodeModel, // 控件数据实体
|
||||||
|
nodeCanvas); // 所在画布
|
||||||
|
OnCreateNode.Invoke(nodeControl); // 创建节点
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
SereinEnv.WriteLine(ex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeControls.TryAdd(nodeControl.ViewModel.NodeModel.Guid, nodeControl); // 记录创建了的节点控件
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 画布移除
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="eventArgs"></param>
|
||||||
private void FlowEEForwardingService_OnCanvasRemove(CanvasRemoveEventArgs eventArgs)
|
private void FlowEEForwardingService_OnCanvasRemove(CanvasRemoveEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
OnRemoveFlowCanvasView.Invoke(eventArgs.CanvasGuid);
|
if (!TryGetCanvas(eventArgs.CanvasGuid, out var nodeCanvas))
|
||||||
|
{
|
||||||
|
SereinEnv.WriteLine(InfoType.INFO, $"无法移除画布,画布不存在。");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
OnRemoveFlowCanvasView.Invoke(nodeCanvas);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 画布创建
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="eventArgs"></param>
|
||||||
private void FlowEEForwardingService_OnCanvasCreate(CanvasCreateEventArgs eventArgs)
|
private void FlowEEForwardingService_OnCanvasCreate(CanvasCreateEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
var info = eventArgs.Model;
|
|
||||||
var model = eventArgs.Model;
|
var model = eventArgs.Model;
|
||||||
FlowCanvasView canvasView = new FlowCanvasView();
|
var guid = model.Guid;
|
||||||
canvasView.ViewModel.CanvasGuid = info.Guid;
|
if (Canvass.ContainsKey(guid))
|
||||||
canvasView.ViewModel.Model = model;
|
{
|
||||||
FlowCanvasViews.Add(info.Guid, canvasView);
|
SereinEnv.WriteLine(InfoType.WARN, $"创建画布时发生意外:节点Guid重复 - {guid}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
FlowCanvasView canvasView = new FlowCanvasView(model);
|
||||||
|
//canvasView.ViewModel.Model = model;
|
||||||
|
//canvasView.ViewModel.CanvasGuid = model.Guid;
|
||||||
|
//canvasView.ViewModel.Name = model.Name;
|
||||||
|
//canvasView.SetBinding(model);
|
||||||
|
Canvass.Add(model.Guid, canvasView);
|
||||||
OnCreateFlowCanvasView.Invoke(canvasView); // 传递给订阅者
|
OnCreateFlowCanvasView.Invoke(canvasView); // 传递给订阅者
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建节点控件
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="controlType">节点控件视图控件类型</param>
|
||||||
|
/// <param name="viewModelType">节点控件ViewModel类型</param>
|
||||||
|
/// <param name="model">节点Model实例</param>
|
||||||
|
/// <param name="nodeCanvas">节点所在画布</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <exception cref="Exception">无法创建节点控件</exception>
|
||||||
|
private static NodeControlBase CreateNodeControl(Type controlType, Type viewModelType, NodeModelBase model, IFlowCanvas nodeCanvas)
|
||||||
|
{
|
||||||
|
if ((controlType is null)
|
||||||
|
|| viewModelType is null
|
||||||
|
|| model is null)
|
||||||
|
{
|
||||||
|
throw new Exception("无法创建节点控件");
|
||||||
|
}
|
||||||
|
if (typeof(NodeControlBase).IsSubclassOf(controlType) || typeof(NodeControlViewModelBase).IsSubclassOf(viewModelType))
|
||||||
|
{
|
||||||
|
throw new Exception("无法创建节点控件");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(model.Guid))
|
||||||
|
{
|
||||||
|
model.Guid = Guid.NewGuid().ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
var viewModel = Activator.CreateInstance(viewModelType, [model]);
|
||||||
|
var controlObj = Activator.CreateInstance(controlType, [viewModel]);
|
||||||
|
if (controlObj is NodeControlBase nodeControl)
|
||||||
|
{
|
||||||
|
nodeControl.FlowCanvas = nodeCanvas;
|
||||||
|
return nodeControl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception("无法创建节点控件");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 从Guid获取节点控件
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="nodeGuid"></param>
|
||||||
|
/// <param name="nodeControl"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private bool TryGetControl(string nodeGuid, out NodeControlBase nodeControl)
|
||||||
|
{
|
||||||
|
nodeControl = null;
|
||||||
|
if (string.IsNullOrEmpty(nodeGuid))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return NodeControls.TryGetValue(nodeGuid, out nodeControl);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 从Guid获取画布视图
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="nodeGuid"></param>
|
||||||
|
/// <param name="nodeControl"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private bool TryGetCanvas(string nodeGuid, out FlowCanvasView flowCanvas)
|
||||||
|
{
|
||||||
|
flowCanvas = null;
|
||||||
|
if (string.IsNullOrEmpty(nodeGuid))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return Canvass.TryGetValue(nodeGuid, out flowCanvas);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -128,8 +397,8 @@ namespace Serein.Workbench.Services
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public void CreateFlowCanvas()
|
public void CreateFlowCanvas()
|
||||||
{
|
{
|
||||||
int height = 1000;
|
int width = 1200;
|
||||||
int width = 600;
|
int height = 780;
|
||||||
_ = Task.Run(async () =>
|
_ = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
var result = await flowEnvironment.CreateCanvasAsync("", width, height);
|
var result = await flowEnvironment.CreateCanvasAsync("", width, height);
|
||||||
@@ -146,7 +415,8 @@ namespace Serein.Workbench.Services
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_ = flowEnvironment.RemoveCanvasAsync(CurrentSelectCanvas.ViewModel.CanvasGuid);
|
var model = ((FlowCanvasViewModel)CurrentSelectCanvas.DataContext).Model;
|
||||||
|
_ = flowEnvironment.RemoveCanvasAsync(model.Guid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -154,32 +424,31 @@ namespace Serein.Workbench.Services
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void CreateNode()
|
public void CreateNode()
|
||||||
{
|
{
|
||||||
string canvasGuid = CurrentSelectCanvas.ViewModel.CanvasGuid;
|
var model = ((FlowCanvasViewModel)CurrentSelectCanvas.DataContext).Model;
|
||||||
NodeControlType? nodeType = CurrentNodeControlType;
|
|
||||||
|
string canvasGuid = model.Guid;
|
||||||
|
NodeControlType nodeType = CurrentNodeControlType;
|
||||||
PositionOfUI? position = CurrentMouseLocation;
|
PositionOfUI? position = CurrentMouseLocation;
|
||||||
MethodDetailsInfo? methodDetailsInfo = CurrentDragMdInfo;
|
MethodDetailsInfo? methodDetailsInfo = CurrentDragMdInfo;
|
||||||
if (nodeType is null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (position is null)
|
if (position is null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_ = flowEnvironment.CreateNodeAsync(canvasGuid, (NodeControlType)nodeType, position, methodDetailsInfo);
|
_ = flowEnvironment.CreateNodeAsync(canvasGuid, nodeType, position, methodDetailsInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 向运行环境发出请求:移除节点
|
/// 向运行环境发出请求:移除节点
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void RemoteNode()
|
public void RemoteNode(NodeControlBase nodeControl)
|
||||||
{
|
{
|
||||||
NodeControlBase? node = CurrentSelectNodeControl;
|
//NodeControlBase? node = CurrentSelectNodeControl;
|
||||||
if (node is null)
|
if (nodeControl is null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var model = node.ViewModel.NodeModel;
|
var model = nodeControl.ViewModel.NodeModel;
|
||||||
if (model is null)
|
if (model is null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
/*
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
namespace Serein.Workbench.Services
|
namespace Serein.Workbench.Services
|
||||||
{
|
{
|
||||||
@@ -38,7 +39,6 @@ namespace Serein.Workbench.Services
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal class KeyEventService : IKeyEventService
|
internal class KeyEventService : IKeyEventService
|
||||||
{
|
{
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 按键按下
|
/// 按键按下
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -77,4 +77,3 @@ namespace Serein.Workbench.Services
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
@@ -18,14 +18,6 @@ using System.Threading.Tasks;
|
|||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace Serein.Workbench.Api
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Serein.Workbench.Services
|
namespace Serein.Workbench.Services
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
using Serein.Library;
|
using Microsoft.Win32;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using Serein.Library;
|
||||||
using Serein.Library.Api;
|
using Serein.Library.Api;
|
||||||
|
using Serein.Workbench.Api;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Security.Cryptography.X509Certificates;
|
using System.Security.Cryptography.X509Certificates;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@@ -50,25 +54,32 @@ namespace Serein.Workbench.Services
|
|||||||
{
|
{
|
||||||
|
|
||||||
private readonly IFlowEnvironment flowEnvironment;
|
private readonly IFlowEnvironment flowEnvironment;
|
||||||
|
private readonly IFlowEEForwardingService flowEEForwardingService;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 管理工作台的事件
|
/// 管理工作台的事件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="flowEnvironment"></param>
|
/// <param name="flowEnvironment"></param>
|
||||||
public WorkbenchEventService(IFlowEnvironment flowEnvironment)
|
/// <param name="flowEEForwardingService"></param>
|
||||||
|
public WorkbenchEventService(IFlowEnvironment flowEnvironment, IFlowEEForwardingService flowEEForwardingService)
|
||||||
{
|
{
|
||||||
this.flowEnvironment = flowEnvironment;
|
this.flowEnvironment = flowEnvironment;
|
||||||
|
this.flowEEForwardingService = flowEEForwardingService;
|
||||||
|
InitEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SubscribeEvents()
|
private void InitEvents()
|
||||||
{
|
{
|
||||||
|
flowEEForwardingService.OnProjectSaving += SaveProjectToLocalFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 预览了某个方法信息(待创建)
|
/// 预览了某个方法信息(待创建)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event PreviewlMethodInfoHandler? OnPreviewlMethodInfo;
|
public event PreviewlMethodInfoHandler? OnPreviewlMethodInfo;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 预览依赖方法信息
|
/// 预览依赖方法信息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -84,6 +95,96 @@ namespace Serein.Workbench.Services
|
|||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 保存项目数据到本地文件
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="e"></param>
|
||||||
|
private void SaveProjectToLocalFile(ProjectSavingEventArgs e)
|
||||||
|
{
|
||||||
|
var project = e.ProjectData;
|
||||||
|
// 创建一个新的保存文件对话框
|
||||||
|
SaveFileDialog saveFileDialog = new()
|
||||||
|
{
|
||||||
|
Filter = "DynamicNodeFlow Files (*.dnf)|*.dnf",
|
||||||
|
DefaultExt = "dnf",
|
||||||
|
FileName = "project.dnf"
|
||||||
|
// FileName = System.IO.Path.GetFileName(App.FileDataPath)
|
||||||
|
};
|
||||||
|
|
||||||
|
// 显示保存文件对话框
|
||||||
|
bool? result = saveFileDialog.ShowDialog();
|
||||||
|
// 如果用户选择了文件并点击了保存按钮
|
||||||
|
if (result == false)
|
||||||
|
{
|
||||||
|
SereinEnv.WriteLine(InfoType.ERROR, "取消保存文件");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var savePath = saveFileDialog.FileName;
|
||||||
|
string? librarySavePath = System.IO.Path.GetDirectoryName(savePath);
|
||||||
|
if (string.IsNullOrEmpty(librarySavePath))
|
||||||
|
{
|
||||||
|
SereinEnv.WriteLine(InfoType.ERROR, "保存项目DLL时返回了意外的文件保存路径");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Uri saveProjectFileUri = new Uri(savePath);
|
||||||
|
SereinEnv.WriteLine(InfoType.INFO, "项目文件保存路径:" + savePath);
|
||||||
|
for (int index = 0; index < project.Librarys.Length; index++)
|
||||||
|
{
|
||||||
|
NodeLibraryInfo? library = project.Librarys[index];
|
||||||
|
string sourceFilePath = new Uri(library.FilePath).LocalPath; // 源文件夹
|
||||||
|
string targetDir = System.IO.Path.Combine(librarySavePath, library.AssemblyName); // 目标文件夹
|
||||||
|
if (!Path.Exists(targetDir))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(targetDir);
|
||||||
|
}
|
||||||
|
string targetFilePath = System.IO.Path.Combine(targetDir, library.FileName); // 目标文件夹
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (File.Exists(sourceFilePath))
|
||||||
|
{
|
||||||
|
if (!File.Exists(targetFilePath))
|
||||||
|
{
|
||||||
|
SereinEnv.WriteLine(InfoType.INFO, $"源文件路径 : {sourceFilePath}");
|
||||||
|
SereinEnv.WriteLine(InfoType.INFO, $"目标路径 : {targetFilePath}");
|
||||||
|
File.Copy(sourceFilePath, targetFilePath, true);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SereinEnv.WriteLine(InfoType.WARN, $"目标路径已有类库文件: {targetFilePath}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SereinEnv.WriteLine(InfoType.WARN, $"源文件不存在 : {targetFilePath}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IOException ex)
|
||||||
|
{
|
||||||
|
|
||||||
|
SereinEnv.WriteLine(InfoType.ERROR, ex.Message);
|
||||||
|
}
|
||||||
|
var dirName = System.IO.Path.GetDirectoryName(targetFilePath);
|
||||||
|
if (!string.IsNullOrEmpty(dirName))
|
||||||
|
{
|
||||||
|
var tmpUri2 = new Uri(targetFilePath);
|
||||||
|
var relativePath = saveProjectFileUri.MakeRelativeUri(tmpUri2).ToString(); // 转为类库的相对文件路径
|
||||||
|
|
||||||
|
//string relativePath = System.IO.Path.GetRelativePath(savePath, targetPath);
|
||||||
|
project.Librarys[index].FilePath = relativePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
JObject projectJsonData = JObject.FromObject(project);
|
||||||
|
File.WriteAllText(savePath, projectJsonData.ToString());
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,27 @@
|
|||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using Serein.Library;
|
using Serein.Library;
|
||||||
|
using Serein.Library.Api;
|
||||||
|
using Serein.Workbench.Api;
|
||||||
using Serein.Workbench.Node.View;
|
using Serein.Workbench.Node.View;
|
||||||
|
using Serein.Workbench.Services;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
|
||||||
namespace Serein.Workbench.ViewModels
|
namespace Serein.Workbench.ViewModels
|
||||||
{
|
{
|
||||||
public partial class FlowCanvasViewModel : ObservableObject
|
public partial class FlowCanvasViewModel : ObservableObject
|
||||||
{
|
{
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 画布当前选中的节点
|
/// 画布当前选中的节点
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public NodeControlBase CurrentSelectNodeControl { get; set; }
|
public NodeControlBase CurrentSelectNode { get; set; }
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 正在创建节点方法调用关系
|
/// 正在创建节点方法调用关系
|
||||||
@@ -29,29 +35,13 @@ namespace Serein.Workbench.ViewModels
|
|||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private bool _isConnectionArgSourceNode;
|
private bool _isConnectionArgSourceNode;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 画布显示名称
|
|
||||||
/// </summary>
|
|
||||||
[ObservableProperty]
|
|
||||||
private string _name;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 画布ID
|
|
||||||
/// </summary>
|
|
||||||
[ObservableProperty]
|
|
||||||
private string _canvasGuid;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 画布数据实体
|
/// 画布数据实体
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private FlowCanvasModel _model;
|
private FlowCanvasDetails _model;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public FlowCanvasViewModel()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
using Serein.Workbench.Api;
|
||||||
using Serein.Workbench.Models;
|
using Serein.Workbench.Models;
|
||||||
|
using Serein.Workbench.Node.View;
|
||||||
using Serein.Workbench.Services;
|
using Serein.Workbench.Services;
|
||||||
using Serein.Workbench.Views;
|
using Serein.Workbench.Views;
|
||||||
using System;
|
using System;
|
||||||
@@ -20,13 +22,17 @@ namespace Serein.Workbench.ViewModels
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class FlowEditViewModel : ObservableObject
|
public partial class FlowEditViewModel : ObservableObject
|
||||||
{
|
{
|
||||||
public ObservableCollection<FlowCanvasModel> Tabs { get; set; } = [];
|
public ObservableCollection<FlowEditorTabModel> CanvasTabs { get; set; } = [];
|
||||||
public ICommand AddTabCommand { get; set; }
|
public ICommand AddTabCommand { get; set; }
|
||||||
public ICommand RemoveTabCommand { get; set; }
|
public ICommand RemoveTabCommand { get; set; }
|
||||||
public ICommand RenameTabCommand { get; set; }
|
public ICommand RenameTabCommand { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 当前选择的画布
|
||||||
|
/// </summary>
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private FlowCanvasModel _selectedTab;
|
private FlowEditorTabModel _selectedTab;
|
||||||
|
|
||||||
private readonly FlowNodeService flowNodeService;
|
private readonly FlowNodeService flowNodeService;
|
||||||
|
|
||||||
@@ -34,39 +40,42 @@ namespace Serein.Workbench.ViewModels
|
|||||||
{
|
{
|
||||||
this.flowNodeService = flowNodeService;
|
this.flowNodeService = flowNodeService;
|
||||||
AddTabCommand = new RelayCommand(AddTab);
|
AddTabCommand = new RelayCommand(AddTab);
|
||||||
RemoveTabCommand = new RelayCommand(RemoveTab, CanRemoveTab);
|
RemoveTabCommand = new RelayCommand(RemoveTab);
|
||||||
|
|
||||||
flowNodeService.OnCreateFlowCanvasView += OnCreateFlowCanvasView; // 运行环境创建了画布
|
flowNodeService.OnCreateFlowCanvasView += OnCreateFlowCanvasView; // 创建了画布
|
||||||
flowNodeService.OnRemoveFlowCanvasView += OnRemoveFlowCanvasView; // 运行环境移除了画布
|
flowNodeService.OnRemoveFlowCanvasView += OnRemoveFlowCanvasView; // 移除了画布
|
||||||
this.PropertyChanged += OnPropertyChanged;
|
this.PropertyChanged += OnPropertyChanged;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void OnPropertyChanged(object? value, PropertyChangedEventArgs e)
|
private void OnPropertyChanged(object? value, PropertyChangedEventArgs e)
|
||||||
{
|
{
|
||||||
if (nameof(SelectedTab).Equals(e.PropertyName) && value is FlowCanvasModel model)
|
if (this.SelectedTab is null) return;
|
||||||
{
|
flowNodeService.CurrentSelectCanvas = this.SelectedTab.Content;
|
||||||
flowNodeService.CurrentSelectCanvas = model.Content; // 选中的视图发生改变
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#region 响应环境事件
|
#region 响应环境事件
|
||||||
private void OnCreateFlowCanvasView(FlowCanvasView FlowCanvasView)
|
private void OnCreateFlowCanvasView(FlowCanvasView canvas)
|
||||||
{
|
{
|
||||||
var model = new FlowCanvasModel { Content = FlowCanvasView, Name = FlowCanvasView.ViewModel.Name };
|
var model = new FlowEditorTabModel(canvas);
|
||||||
Tabs.Add(model);
|
CanvasTabs.Add(model);
|
||||||
|
SelectedTab = model;
|
||||||
}
|
}
|
||||||
private void OnRemoveFlowCanvasView(string canvasGuid)
|
private void OnRemoveFlowCanvasView(FlowCanvasView canvas)
|
||||||
{
|
{
|
||||||
var tab = Tabs.FirstOrDefault(t => t.Content.ViewModel.Model.Guid.Equals(canvasGuid, StringComparison.OrdinalIgnoreCase));
|
var tab = CanvasTabs.FirstOrDefault(c => c.Content.Guid.Equals(canvas.Guid));
|
||||||
if (tab is null)
|
if (tab is null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Tabs.Remove(tab);
|
CanvasTabs.Remove(tab);
|
||||||
Tabs.Remove(SelectedTab);
|
|
||||||
if(Tabs.Count > 0 && Tabs[^1] is FlowCanvasModel view )
|
if (CanvasTabs.Count > 0 && CanvasTabs[^1] is FlowEditorTabModel c)
|
||||||
{
|
{
|
||||||
SelectedTab = view;
|
SelectedTab = c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
@@ -75,10 +84,9 @@ namespace Serein.Workbench.ViewModels
|
|||||||
private void AddTab() => flowNodeService.CreateFlowCanvas();
|
private void AddTab() => flowNodeService.CreateFlowCanvas();
|
||||||
private void RemoveTab()
|
private void RemoveTab()
|
||||||
{
|
{
|
||||||
if (Tabs.Count > 0 && SelectedTab != null) flowNodeService.RemoveFlowCanvas();
|
if (CanvasTabs.Count > 0 && SelectedTab != null) flowNodeService.RemoveFlowCanvas();
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool CanRemoveTab() => SelectedTab != null;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -86,12 +94,12 @@ namespace Serein.Workbench.ViewModels
|
|||||||
/// 进入编辑模式
|
/// 进入编辑模式
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="tab"></param>
|
/// <param name="tab"></param>
|
||||||
public void StartEditingTab(FlowCanvasModel tab)
|
public void StartEditingTab(FlowEditorTabModel tab)
|
||||||
{
|
{
|
||||||
if (tab != null)
|
if (tab != null)
|
||||||
{
|
{
|
||||||
tab.IsEditing = true;
|
tab.IsEditing = true;
|
||||||
OnPropertyChanged(nameof(Tabs)); // 刷新Tabs集合,以便更新UI
|
OnPropertyChanged(nameof(CanvasTabs)); // 刷新Tabs集合,以便更新UI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,13 +108,13 @@ namespace Serein.Workbench.ViewModels
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="tab"></param>
|
/// <param name="tab"></param>
|
||||||
/// <param name="newName"></param>
|
/// <param name="newName"></param>
|
||||||
public void EndEditingTab(FlowCanvasModel tab, string newName)
|
public void EndEditingTab(FlowEditorTabModel tab, string? newName = null)
|
||||||
{
|
{
|
||||||
if (tab != null)
|
if (tab != null)
|
||||||
{
|
{
|
||||||
tab.IsEditing = false;
|
tab.IsEditing = false;
|
||||||
tab.Name = newName; // 设置新名称
|
if(tab.Name != newName && !string.IsNullOrWhiteSpace(newName)) tab.Name = newName; // 名称合法时设置新名称
|
||||||
OnPropertyChanged(nameof(Tabs)); // 刷新Tabs集合
|
OnPropertyChanged(nameof(CanvasTabs)); // 刷新Tabs集合
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using Serein.Workbench.Api;
|
using Serein.Workbench.Api;
|
||||||
using Serein.Workbench.Models;
|
using Serein.Workbench.Models;
|
||||||
|
using Serein.Workbench.Services;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
@@ -13,10 +14,12 @@ namespace Serein.Workbench.ViewModels
|
|||||||
internal partial class FlowWorkbenchViewModel : ObservableObject
|
internal partial class FlowWorkbenchViewModel : ObservableObject
|
||||||
{
|
{
|
||||||
private readonly IFlowEEForwardingService flowEEForwardingService;
|
private readonly IFlowEEForwardingService flowEEForwardingService;
|
||||||
|
private readonly IWorkbenchEventService workbenchEventService;
|
||||||
|
|
||||||
public FlowWorkbenchViewModel(IFlowEEForwardingService flowEEForwardingService)
|
public FlowWorkbenchViewModel(IFlowEEForwardingService flowEEForwardingService, IWorkbenchEventService workbenchEventService)
|
||||||
{
|
{
|
||||||
this.flowEEForwardingService = flowEEForwardingService;
|
this.flowEEForwardingService = flowEEForwardingService;
|
||||||
|
this.workbenchEventService = workbenchEventService;
|
||||||
//flowEEForwardingService.OnDllLoad += FlowEEForwardingService_OnDllLoad;
|
//flowEEForwardingService.OnDllLoad += FlowEEForwardingService_OnDllLoad;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,12 +26,22 @@ namespace Serein.Workbench.ViewModels
|
|||||||
/// 增加流程图
|
/// 增加流程图
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ICommand CreateFlowCanvasCommand { get; private set; }
|
public ICommand CreateFlowCanvasCommand { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 增加流程图
|
/// 移除流程图
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ICommand RemoteFlowCanvasCommand { get; private set; }
|
public ICommand RemoteFlowCanvasCommand { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 运行当前画布流程
|
||||||
|
/// </summary>
|
||||||
|
public ICommand StartCurrentCanvasFlowCommand { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 停止当前画布流程
|
||||||
|
/// </summary>
|
||||||
|
public ICommand StopCurrentCanvasFlowCommand { get; private set; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 打开环境输出窗口
|
/// 打开环境输出窗口
|
||||||
@@ -49,13 +59,33 @@ namespace Serein.Workbench.ViewModels
|
|||||||
{
|
{
|
||||||
this.environment = environment;
|
this.environment = environment;
|
||||||
|
|
||||||
SaveProjectCommand = new RelayCommand(SaveProject);
|
SaveProjectCommand = new RelayCommand(SaveProject); // 保存项目
|
||||||
|
LoadLocalProjectCommand = new RelayCommand(LoadLocalProject); // 加载本地项目
|
||||||
|
LoadRemoteProjectCommand = new RelayCommand(LoadRemoteProject); // 加载远程项目
|
||||||
|
|
||||||
|
CreateFlowCanvasCommand = new RelayCommand(CreateFlowCanvas); // 增加画布
|
||||||
|
RemoteFlowCanvasCommand = new RelayCommand(RemoteFlowCanvas); // 移除画布
|
||||||
|
|
||||||
|
StartCurrentCanvasFlowCommand = new RelayCommand(StartCurrentCanvasFlow); // 运行当前流程
|
||||||
|
StopCurrentCanvasFlowCommand = new RelayCommand(StopCurrentCanvasFlow); // 停止当前流程
|
||||||
|
|
||||||
|
OpenEnvOutWindowCommand = new RelayCommand(OpenEnvOutWindow); // 打开运行输出窗口
|
||||||
|
OpenDynamicCompilerCommand = new RelayCommand(OpenDynamicCompiler); // 打开动态编译仓库窗口
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SaveProject()
|
private void SaveProject() {
|
||||||
{
|
environment.SaveProject(); // 保存项目
|
||||||
|
|
||||||
}
|
}
|
||||||
|
private void LoadLocalProject() {
|
||||||
|
//environment.LoadProject(); // 加载项目
|
||||||
|
}
|
||||||
|
private void LoadRemoteProject() { }
|
||||||
|
private void CreateFlowCanvas() { }
|
||||||
|
private void RemoteFlowCanvas() { }
|
||||||
|
private void StartCurrentCanvasFlow() { }
|
||||||
|
private void StopCurrentCanvasFlow() { }
|
||||||
|
private void OpenDynamicCompiler() { }
|
||||||
|
private void OpenEnvOutWindow() { }
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,11 @@
|
|||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:local="clr-namespace:Serein.Workbench.Views"
|
xmlns:local="clr-namespace:Serein.Workbench.Views"
|
||||||
xmlns:tool="clr-namespace:Serein.Workbench.Tool.Converters"
|
xmlns:tool="clr-namespace:Serein.Workbench.Tool.Converters"
|
||||||
|
xmlns:vm="clr-namespace:Serein.Workbench.ViewModels"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="450" d:DesignWidth="800">
|
d:DesignHeight="450"
|
||||||
|
d:DesignWidth="800"
|
||||||
|
d:DataContext="{d:DesignInstance vm:FlowCanvasViewModel}">
|
||||||
|
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<tool:RightThumbPositionConverter x:Key="RightThumbPositionConverter" />
|
<tool:RightThumbPositionConverter x:Key="RightThumbPositionConverter" />
|
||||||
@@ -16,22 +19,23 @@
|
|||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
|
|
||||||
<DockPanel x:Name="FlowChartStackPanel"
|
<DockPanel x:Name="FlowChartStackPanel"
|
||||||
ClipToBounds="True">
|
ClipToBounds="True">
|
||||||
|
|
||||||
<Canvas ClipToBounds="True"
|
<Canvas ClipToBounds="True"
|
||||||
x:Name="FlowChartCanvas"
|
x:Name="FlowChartCanvas"
|
||||||
Background="#E1FBEA"
|
Background="#E1FBEA"
|
||||||
AllowDrop="True"
|
AllowDrop="True"
|
||||||
Width="1000"
|
Width="{Binding Model.Width, Mode=TwoWay}"
|
||||||
Height="600"
|
Height="{Binding Model.Height, Mode=TwoWay}"
|
||||||
MouseLeftButtonDown ="FlowChartCanvas_MouseLeftButtonDown"
|
MouseLeftButtonDown ="FlowChartCanvas_MouseLeftButtonDown"
|
||||||
MouseLeftButtonUp="FlowChartCanvas_MouseLeftButtonUp"
|
MouseLeftButtonUp="FlowChartCanvas_MouseLeftButtonUp"
|
||||||
MouseDown="FlowChartCanvas_MouseDown"
|
MouseDown="FlowChartCanvas_MouseDown"
|
||||||
MouseUp="FlowChartCanvas_MouseUp"
|
MouseUp="FlowChartCanvas_MouseUp"
|
||||||
MouseMove="FlowChartCanvas_MouseMove"
|
MouseMove="FlowChartCanvas_MouseMove"
|
||||||
MouseWheel="FlowChartCanvas_MouseWheel"
|
MouseWheel="FlowChartCanvas_MouseWheel"
|
||||||
Drop="FlowChartCanvas_Drop"
|
Drop="FlowChartCanvas_Drop"
|
||||||
DragOver="FlowChartCanvas_DragOver"
|
DragOver="FlowChartCanvas_DragOver"
|
||||||
>
|
>
|
||||||
|
|
||||||
<Rectangle x:Name="SelectionRectangle"
|
<Rectangle x:Name="SelectionRectangle"
|
||||||
Stroke="Blue"
|
Stroke="Blue"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -19,29 +19,30 @@
|
|||||||
<!--DragOver="TabControl_DragOver"
|
<!--DragOver="TabControl_DragOver"
|
||||||
Drop="TabControl_Drop"
|
Drop="TabControl_Drop"
|
||||||
AllowDrop="True"-->
|
AllowDrop="True"-->
|
||||||
<TabControl SelectedItem="{Binding SelectedTab}" >
|
<TabControl SelectedItem="{Binding SelectedTab}"
|
||||||
|
SelectionChanged="TabControl_SelectionChanged"
|
||||||
|
x:Name="CanvasTab">
|
||||||
<TabControl.ItemTemplate>
|
<TabControl.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<StackPanel>
|
<StackPanel >
|
||||||
<!-- 双击选项卡名称来进入编辑模式 -->
|
<!-- 双击选项卡名称来进入编辑模式 -->
|
||||||
<TextBlock Text="{Binding Name}"
|
<TextBlock Text="{Binding Name}"
|
||||||
FontSize="18"
|
FontSize="18"
|
||||||
Visibility="{Binding IsEditing, Converter={StaticResource InvertableBooleanToVisibilityConverter},ConverterParameter=Inverted}"
|
Visibility="{Binding IsEditing, Converter={StaticResource InvertableBooleanToVisibilityConverter},ConverterParameter=Inverted}"
|
||||||
PreviewMouseLeftButtonDown="TextBlock_PreviewMouseLeftButtonDown"
|
PreviewMouseLeftButtonDown="TextBlock_PreviewMouseLeftButtonDown"
|
||||||
MouseLeftButtonDown="TextBlock_MouseLeftButtonDown"/>
|
MouseLeftButtonDown="TextBlock_MouseLeftButtonDown"/>
|
||||||
<!-- 编辑模式下显示TextBox -->
|
<!-- 编辑模式下显示TextBox -->
|
||||||
<TextBox Text="{Binding Name, Mode=TwoWay}"
|
<TextBox Text="{Binding Name, Mode=TwoWay}"
|
||||||
FontSize="18"
|
FontSize="18"
|
||||||
Visibility="{Binding IsEditing, Converter={StaticResource InvertableBooleanToVisibilityConverter},ConverterParameter=Normal}"
|
Visibility="{Binding IsEditing, Converter={StaticResource InvertableBooleanToVisibilityConverter},ConverterParameter=Normal}"
|
||||||
KeyDown="TextBox_KeyDown"
|
KeyDown="TextBox_KeyDown" />
|
||||||
LostFocus="TextBox_LostFocus"/>
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</TabControl.ItemTemplate>
|
</TabControl.ItemTemplate>
|
||||||
|
|
||||||
<!-- Tabs Collection -->
|
<!-- Tabs Collection -->
|
||||||
<TabControl.ItemsSource>
|
<TabControl.ItemsSource>
|
||||||
<Binding Path="Tabs" />
|
<Binding Path="CanvasTabs" />
|
||||||
</TabControl.ItemsSource>
|
</TabControl.ItemsSource>
|
||||||
|
|
||||||
<!-- Content of the Tab (e.g., FlowCanvasView) -->
|
<!-- Content of the Tab (e.g., FlowCanvasView) -->
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
using Serein.Workbench.ViewModels;
|
using Serein.Workbench.ViewModels;
|
||||||
using System;
|
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;
|
||||||
@@ -30,16 +31,18 @@ namespace Serein.Workbench.Views
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class FlowEditView : UserControl
|
public partial class FlowEditView : UserControl
|
||||||
{
|
{
|
||||||
|
|
||||||
public FlowEditView()
|
public FlowEditView()
|
||||||
{
|
{
|
||||||
this.DataContext = App.GetService<Locator>().FlowEditViewModel;
|
this.DataContext = App.GetService<Locator>().FlowEditViewModel;
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TextBlock_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
private void TextBlock_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||||
{
|
{
|
||||||
var textBlock = sender as TextBlock;
|
var textBlock = sender as TextBlock;
|
||||||
var tab = textBlock?.DataContext as FlowCanvasModel;
|
var tab = textBlock?.DataContext as FlowCanvasViewModel;
|
||||||
if (tab != null)
|
if (tab != null)
|
||||||
{
|
{
|
||||||
DragDrop.DoDragDrop(textBlock, tab, DragDropEffects.Move);
|
DragDrop.DoDragDrop(textBlock, tab, DragDropEffects.Move);
|
||||||
@@ -47,7 +50,7 @@ namespace Serein.Workbench.Views
|
|||||||
}
|
}
|
||||||
private void TabControl_DragOver(object sender, DragEventArgs e)
|
private void TabControl_DragOver(object sender, DragEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.Data.GetDataPresent(typeof(FlowCanvasModel)))
|
if (e.Data.GetDataPresent(typeof(FlowCanvasViewModel)))
|
||||||
{
|
{
|
||||||
e.Effects = DragDropEffects.Move;
|
e.Effects = DragDropEffects.Move;
|
||||||
}
|
}
|
||||||
@@ -59,73 +62,83 @@ namespace Serein.Workbench.Views
|
|||||||
|
|
||||||
private void TabControl_Drop(object sender, DragEventArgs e)
|
private void TabControl_Drop(object sender, DragEventArgs e)
|
||||||
{
|
{
|
||||||
var sourceTab = e.Data.GetData(typeof(FlowCanvasModel)) as FlowCanvasModel;
|
var sourceTab = e.Data.GetData(typeof(FlowEditorTabModel)) as FlowEditorTabModel;
|
||||||
var targetTab = (sender as TabControl)?.SelectedItem as FlowCanvasModel;
|
var targetTab = (sender as TabControl)?.SelectedItem as FlowEditorTabModel;
|
||||||
var viewModel = (FlowEditViewModel)this.DataContext;
|
var viewModel = (FlowEditViewModel)this.DataContext;
|
||||||
if (sourceTab != null && targetTab != null && sourceTab != targetTab)
|
if (sourceTab != null && targetTab != null && sourceTab != targetTab)
|
||||||
{
|
{
|
||||||
var sourceIndex = viewModel.Tabs.IndexOf(sourceTab);
|
var sourceIndex = viewModel.CanvasTabs.IndexOf(sourceTab);
|
||||||
var targetIndex = viewModel.Tabs.IndexOf(targetTab);
|
var targetIndex = viewModel.CanvasTabs.IndexOf(targetTab);
|
||||||
|
|
||||||
// 删除源项并插入到目标位置
|
// 删除源项并插入到目标位置
|
||||||
viewModel.Tabs.Remove(sourceTab);
|
viewModel.CanvasTabs.Remove(sourceTab);
|
||||||
viewModel.Tabs.Insert(targetIndex, sourceTab);
|
viewModel.CanvasTabs.Insert(targetIndex, sourceTab);
|
||||||
|
|
||||||
// 更新视图模型中的选中的Tab
|
// 更新视图模型中的选中的Tab
|
||||||
viewModel.SelectedTab = sourceTab;
|
viewModel.SelectedTab = sourceTab;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 按下确认或回车
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender"></param>
|
||||||
|
/// <param name="e"></param>
|
||||||
private void TextBox_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
|
private void TextBox_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (e.Key == Key.Enter || e.Key == Key.Escape)
|
if (e.Key == Key.Enter || e.Key == Key.Escape)
|
||||||
{
|
{
|
||||||
var textBox = sender as TextBox;
|
if (sender is TextBox textBox
|
||||||
var newName = textBox?.Text;
|
&& textBox.DataContext is FlowEditorTabModel tab
|
||||||
if (string.IsNullOrEmpty(newName))
|
&& DataContext is FlowEditViewModel viewModel)
|
||||||
{
|
{
|
||||||
|
viewModel.EndEditingTab(tab, textBox.Text); // 确认新名称
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var tab = textBox?.DataContext as FlowCanvasModel;
|
|
||||||
if (tab != null)
|
|
||||||
{
|
|
||||||
var viewModel = (FlowEditViewModel)this.DataContext;
|
|
||||||
viewModel.EndEditingTab(tab, newName); // 确认新名称
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TextBox_LostFocus(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
var textBox = sender as TextBox;
|
|
||||||
var newName = textBox?.Text;
|
|
||||||
if (string.IsNullOrEmpty(newName))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var tab = textBox?.DataContext as FlowCanvasModel;
|
|
||||||
if (tab != null && tab.IsEditing)
|
|
||||||
{
|
|
||||||
var viewModel = (FlowEditViewModel)this.DataContext;
|
|
||||||
viewModel.EndEditingTab(tab, newName); // 确认新名称
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 双击tab进入编辑状态
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender"></param>
|
||||||
|
/// <param name="e"></param>
|
||||||
private void TextBlock_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
private void TextBlock_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.ClickCount == 2)
|
if (e.ClickCount == 2)
|
||||||
{
|
{
|
||||||
var textBlock = sender as TextBlock;
|
if (sender is TextBlock textBlock
|
||||||
var tab = textBlock?.DataContext as FlowCanvasModel;
|
&& textBlock.DataContext is FlowEditorTabModel tab
|
||||||
if (tab != null)
|
&& DataContext is FlowEditViewModel viewModel)
|
||||||
{
|
{
|
||||||
var viewModel = (FlowEditViewModel)this.DataContext;
|
viewModel.StartEditingTab(tab); // 确认新名称
|
||||||
viewModel.StartEditingTab(tab);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private FlowEditorTabModel lastTab;
|
||||||
|
|
||||||
|
private void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (sender is TabControl tabControl
|
||||||
|
&& tabControl.SelectedIndex > 0
|
||||||
|
&& DataContext is FlowEditViewModel viewModel
|
||||||
|
&& viewModel.CanvasTabs[tabControl.SelectedIndex] is FlowEditorTabModel tab)
|
||||||
|
{
|
||||||
|
|
||||||
|
viewModel.EndEditingTab(lastTab); // 确认新名称
|
||||||
|
lastTab = tab;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,12 +4,15 @@
|
|||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:local="clr-namespace:Serein.Workbench.Views"
|
xmlns:local="clr-namespace:Serein.Workbench.Views"
|
||||||
|
xmlns:vm="clr-namespace:Serein.Workbench.ViewModels"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="70" d:DesignWidth="350">
|
d:DesignHeight="70" d:DesignWidth="350"
|
||||||
|
d:DataContext="{d:DesignInstance vm:MainMenuBarViewModel}"
|
||||||
|
>
|
||||||
<Grid >
|
<Grid >
|
||||||
<Menu DockPanel.Dock="Top" Grid.Row="0" Grid.ColumnSpan="5" Height="20">
|
<Menu DockPanel.Dock="Top" Grid.Row="0" Grid.ColumnSpan="5" Height="20">
|
||||||
<MenuItem Header="项目">
|
<MenuItem Header="项目">
|
||||||
<MenuItem Header="保存项目" ></MenuItem>
|
<MenuItem Header="保存项目" Command="{Binding SaveProjectCommand}"></MenuItem>
|
||||||
<MenuItem Header="加载本地项目" ></MenuItem>
|
<MenuItem Header="加载本地项目" ></MenuItem>
|
||||||
<MenuItem Header="加载远程项目"></MenuItem>
|
<MenuItem Header="加载远程项目"></MenuItem>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ namespace Serein.Workbench.Views
|
|||||||
{
|
{
|
||||||
public MainMenuBarView()
|
public MainMenuBarView()
|
||||||
{
|
{
|
||||||
this.DataContext = App.GetService<Locator>().MainViewModel;
|
this.DataContext = App.GetService<Locator>().MainMenuBarViewModel;
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user