diff --git a/FlowEdit/FlowEdit可视化流程编辑器.zip b/FlowEdit/FlowEdit可视化流程编辑器beta(基于WebSocket的远程控制).zip
similarity index 61%
rename from FlowEdit/FlowEdit可视化流程编辑器.zip
rename to FlowEdit/FlowEdit可视化流程编辑器beta(基于WebSocket的远程控制).zip
index 38ecc69..d866967 100644
Binary files a/FlowEdit/FlowEdit可视化流程编辑器.zip and b/FlowEdit/FlowEdit可视化流程编辑器beta(基于WebSocket的远程控制).zip differ
diff --git a/FlowStartTool/Program.cs b/FlowStartTool/Program.cs
index 3db3c81..8dd7e9c 100644
--- a/FlowStartTool/Program.cs
+++ b/FlowStartTool/Program.cs
@@ -1,9 +1,11 @@
using Newtonsoft.Json;
using Serein.Library;
using Serein.Library.Api;
+using Serein.Library.Utils;
using Serein.NodeFlow.Env;
using System.Diagnostics;
using System.Reflection;
+using static System.Net.Mime.MediaTypeNames;
namespace Serein.FlowStartTool
{
@@ -18,7 +20,7 @@ namespace Serein.FlowStartTool
SereinProjectData? flowProjectData;
string exeAssemblyDictPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
-
+
if (args.Length == 1)
{
filePath = args[0];
@@ -26,6 +28,7 @@ namespace Serein.FlowStartTool
}
else if (args.Length == 0)
{
+ Console.WriteLine("loading project file data...");
filePath = Process.GetCurrentProcess().ProcessName + ".dnf";
fileDataPath = exeAssemblyDictPath;
@@ -66,10 +69,32 @@ namespace Serein.FlowStartTool
public static bool IsRuning;
public static async Task StartFlow(SereinProjectData flowProjectData, string fileDataPath)
{
- Env = new FlowEnvironment();
+ SynchronizationContext? uiContext = SynchronizationContext.Current; // 在UI线程上获取UI线程上下文信息
+ var uIContextOperation = new UIContextOperation(uiContext); // 封装一个调用UI线程的工具类
+
+ //if (OperatingSystem.IsLinux())
+ //{
+
+ //}
+
+ // if (uIContextOperation is null)
+ //{
+ // throw new Exception("无法封装 UIContextOperation ");
+ //}
+ //else
+ //{
+ // env = new FlowEnvironmentDecorator(uIContextOperation);
+ // this.window = window;
+ //}
+
+ Env = new FlowEnvironmentDecorator(uIContextOperation); // Linux 环境下没有线程上下文(暂时没有写)
Env.LoadProject(new FlowEnvInfo { Project = flowProjectData }, fileDataPath); // 加载项目
- await Env.StartAsync();
+ await Env.StartRemoteServerAsync(7525); // 启动 web socket 监听远程请求
+
+ //await Env.StartAsync();
+
+
IsRuning = false;
}
diff --git a/FlowStartTool/Serein.FlowStartTool.csproj b/FlowStartTool/Serein.FlowStartTool.csproj
index 71a1916..bb0d729 100644
--- a/FlowStartTool/Serein.FlowStartTool.csproj
+++ b/FlowStartTool/Serein.FlowStartTool.csproj
@@ -8,7 +8,7 @@
enable
enable
prompt
- project
+ starter
diff --git a/Library/Api/IFlowEnvironment.cs b/Library/Api/IFlowEnvironment.cs
index b1b777b..7719fc4 100644
--- a/Library/Api/IFlowEnvironment.cs
+++ b/Library/Api/IFlowEnvironment.cs
@@ -1,4 +1,5 @@
-using Serein.Library.Utils;
+
+using Serein.Library.Utils;
using System;
using System.Collections.Generic;
using System.Threading;
@@ -228,10 +229,10 @@ namespace Serein.Library.Api
///
///
- public delegate void NodeRemoteHandler(NodeRemoteEventArgs eventArgs);
- public class NodeRemoteEventArgs : FlowEventArgs
+ public delegate void NodeRemoveHandler(NodeRemoveEventArgs eventArgs);
+ public class NodeRemoveEventArgs : FlowEventArgs
{
- public NodeRemoteEventArgs(string nodeGuid)
+ public NodeRemoveEventArgs(string nodeGuid)
{
this.NodeGuid = nodeGuid;
}
@@ -478,10 +479,15 @@ namespace Serein.Library.Api
RunState FlipFlopState { get; set; }
///
- /// 拓展功能时,如需订阅事件,则需要使用该属性
+ /// 表示当前环境
///
IFlowEnvironment CurrentEnv { get; }
+ ///
+ /// 由运行环境提供的UI线程上下文操作,用于类库中需要在UI线程中操作视觉元素的场景
+ ///
+ UIContextOperation UIContextOperation { get; }
+
#endregion
#region 事件
@@ -509,7 +515,7 @@ namespace Serein.Library.Api
///
/// 移除节点事件
///
- event NodeRemoteHandler OnNodeRemote;
+ event NodeRemoveHandler OnNodeRemove;
///
/// 起始节点变化事件
@@ -674,13 +680,13 @@ namespace Serein.Library.Api
/// 起始节点
/// 目标节点
/// 连接类型
- void RemoveConnect(string fromNodeGuid, string toNodeGuid, ConnectionType connectionType);
+ Task RemoveConnectAsync(string fromNodeGuid, string toNodeGuid, ConnectionType connectionType);
///
/// 移除节点/区域/基础控件
///
/// 待移除的节点Guid
- void RemoveNode(string nodeGuid);
+ Task RemoveNodeAsync(string nodeGuid);
///
/// 激活未启动的全局触发器
diff --git a/Library/FlowNode/Attribute.cs b/Library/FlowNode/Attribute.cs
index 435b632..22a16c7 100644
--- a/Library/FlowNode/Attribute.cs
+++ b/Library/FlowNode/Attribute.cs
@@ -20,6 +20,7 @@ namespace Serein.Library
{
public bool IsNotification = false;
public bool IsPrint = false;
+ public bool IsProtection = false;
}
}
diff --git a/Library/Entity/NodeDebugSetting.cs b/Library/FlowNode/NodeDebugSetting.cs
similarity index 58%
rename from Library/Entity/NodeDebugSetting.cs
rename to Library/FlowNode/NodeDebugSetting.cs
index 25ad76b..8c3dc45 100644
--- a/Library/Entity/NodeDebugSetting.cs
+++ b/Library/FlowNode/NodeDebugSetting.cs
@@ -9,27 +9,41 @@ namespace Serein.Library
///
/// 节点调试设置,用于中断节点的运行
///
- public class NodeDebugSetting
+ [AutoProperty(ValuePath = nameof(NodeDebugSetting))]
+ public partial class NodeDebugSetting
{
+ private readonly NodeModelBase nodeModel;
+ ///
+ /// 创建属于某个节点的调试设置
+ ///
+ ///
+ public NodeDebugSetting(NodeModelBase nodeModel)
+ {
+ this.nodeModel = nodeModel;
+ }
///
/// 是否使能
///
- public bool IsEnable { get; set; } = true;
+ [PropertyInfo(IsNotification = true)]
+ private bool _isEnable = true;
///
/// 中断级别,暂时停止继续执行后继分支。
///
- public InterruptClass InterruptClass { get; set; } = InterruptClass.None;
+ [PropertyInfo]
+ private InterruptClass _interruptClass = InterruptClass.None;
///
/// 取消中断的回调函数
///
- public Action CancelInterruptCallback { get; set; }
+ [PropertyInfo]
+ private Action _cancelInterruptCallback;
///
- /// 中断Task(用来取消中断)
+ /// 中断Task(用来中断)
///
- public Func> GetInterruptTask { get; set; }
+ [PropertyInfo]
+ private Func> _getInterruptTask;
}
@@ -53,3 +67,6 @@ namespace Serein.Library
Global,
}
}
+
+
+
diff --git a/Library/FlowNode/NodeModelBaseData.cs b/Library/FlowNode/NodeModelBaseData.cs
index f221326..e1f7798 100644
--- a/Library/FlowNode/NodeModelBaseData.cs
+++ b/Library/FlowNode/NodeModelBaseData.cs
@@ -1,17 +1,93 @@
using Serein.Library.Api;
-using Serein.Library;
using System;
using System.Collections.Generic;
+using System.ComponentModel;
using System.Threading;
namespace Serein.Library
{
+
///
/// 节点基类(数据):条件控件,动作控件,条件区域,动作区域
///
+ [AutoProperty(ValuePath = nameof(NodeModelBase))] // 是否更名为 NodeProperty?
public abstract partial class NodeModelBase : IDynamicFlowNode
{
+
+ [PropertyInfo(IsProtection = true)]
+ private IFlowEnvironment _env;
+
+ ///
+ /// 在画布中的位置
+ ///
+ [PropertyInfo(IsProtection = true)]
+ private PositionOfUI _position ;
+
+ ///
+ /// 附加的调试功能
+ ///
+ [PropertyInfo(IsProtection = true)]
+ private NodeDebugSetting _debugSetting ;
+
+ ///
+ /// 描述节点对应的控件类型
+ ///
+ [PropertyInfo(IsProtection = true)]
+ private NodeControlType _controlType ;
+
+ ///
+ /// 方法描述。不包含Method与委托,需要通过MethodName从环境中获取委托进行调用。
+ ///
+ [PropertyInfo(IsProtection = true)]
+ private MethodDetails _methodDetails ;
+
+ ///
+ /// 标识节点对象全局唯一
+ ///
+ [PropertyInfo(IsProtection = true)]
+ private string _guid ;
+
+ ///
+ /// 显示名称
+ ///
+ [PropertyInfo]
+ private string _displayName ;
+
+ ///
+ /// 是否为起点控件
+ ///
+ [PropertyInfo]
+ private bool _isStart ;
+
+ ///
+ /// 运行时的上一节点
+ ///
+ [PropertyInfo]
+ private NodeModelBase _previousNode ;
+
+
+
+ ///
+ /// 当前节点执行完毕后需要执行的下一个分支的类别
+ ///
+ [PropertyInfo]
+ private ConnectionType _nextOrientation = ConnectionType.None;
+
+ ///
+ /// 运行时的异常信息(仅在 FlowState 为 Error 时存在对应值)
+ ///
+ [PropertyInfo]
+ private Exception _runingException ;
+
+ }
+
+
+
+
+
+ public abstract partial class NodeModelBase : IDynamicFlowNode
+ {
public NodeModelBase(IFlowEnvironment environment)
{
PreviousNodes = new Dictionary>();
@@ -21,75 +97,19 @@ namespace Serein.Library
PreviousNodes[ctType] = new List();
SuccessorNodes[ctType] = new List();
}
- DebugSetting = new NodeDebugSetting();
+ DebugSetting = new NodeDebugSetting(this);
this.Env = environment;
}
- ///
- /// 节点保留对环境的引用,因为需要在属性更改时通知
- ///
- public IFlowEnvironment Env { get; }
-
- ///
- /// 在画布中的位置
- ///
- public PositionOfUI Position { get; set; }
-
- ///
- /// 附加的调试功能
- ///
- public NodeDebugSetting DebugSetting { get; set; }
-
- ///
- /// 描述节点对应的控件类型
- ///
- public NodeControlType ControlType { get; set; }
-
- ///
- /// 方法描述但不包含Method与委托,需要通过MethodName从环境中获取委托进行调用。
- ///
- public MethodDetails MethodDetails { get; set; }
-
- ///
- /// 标识节点对象全局唯一
- ///
- public string Guid { get; set; }
-
- ///
- /// 显示名称
- ///
- public string DisplayName { get; set; } = string.Empty;
-
- ///
- /// 是否为起点控件
- ///
- public bool IsStart { get; set; }
-
- ///
- /// 运行时的上一节点
- ///
- public NodeModelBase PreviousNode { get; set; }
-
///
/// 不同分支的父节点
///
- public Dictionary> PreviousNodes { get; }
-
+ public Dictionary> PreviousNodes { get; }
+
///
/// 不同分支的子节点
///
- public Dictionary> SuccessorNodes { get; }
-
- ///
- /// 当前节点执行完毕后需要执行的下一个分支的类别
- ///
- public ConnectionType NextOrientation { get; set; } = ConnectionType.None;
-
- ///
- /// 运行时的异常信息(仅在 FlowState 为 Error 时存在对应值)
- ///
- public Exception RuningException { get; set; } = null;
-
+ public Dictionary> SuccessorNodes { get; }
///
/// 控制FlowData在同一时间只会被同一个线程更改。
@@ -126,11 +146,75 @@ namespace Serein.Library
}
}
}
-
}
+ /*
+ ///
+ /// 节点基类(数据):条件控件,动作控件,条件区域,动作区域
+ ///
+ public abstract partial class NodeModelBase : IDynamicFlowNode
+ {
+
+ ///
+ /// 节点保留对环境的引用,因为需要在属性更改时通知
+ ///
+ public IFlowEnvironment Env { get; }
+
+ ///
+ /// 在画布中的位置
+ ///
+ public PositionOfUI Position { get; set; }
+
+ ///
+ /// 附加的调试功能
+ ///
+ public NodeDebugSetting DebugSetting { get; set; }
+
+ ///
+ /// 描述节点对应的控件类型
+ ///
+ public NodeControlType ControlType { get; set; }
+
+ ///
+ /// 方法描述。不包含Method与委托,需要通过MethodName从环境中获取委托进行调用。
+ ///
+ public MethodDetails MethodDetails { get; set; }
+
+ ///
+ /// 标识节点对象全局唯一
+ ///
+ public string Guid { get; set; }
+
+ ///
+ /// 显示名称
+ ///
+ public string DisplayName { get; set; } = string.Empty;
+
+ ///
+ /// 是否为起点控件
+ ///
+ public bool IsStart { get; set; }
+
+ ///
+ /// 运行时的上一节点
+ ///
+ public NodeModelBase PreviousNode { get; set; }
+
+ ///
+ /// 当前节点执行完毕后需要执行的下一个分支的类别
+ ///
+ public ConnectionType NextOrientation { get; set; } = ConnectionType.None;
+
+ ///
+ /// 运行时的异常信息(仅在 FlowState 为 Error 时存在对应值)
+ ///
+ public Exception RuningException { get; set; } = null;
+
+
+ }*/
+
///
@@ -156,7 +240,7 @@ namespace Serein.Library
// this.FlowData = builder.FlowData;
// }
-
+
// ///
// /// 节点对应的控件类型
diff --git a/Library/FlowNode/NodeModelBaseFunc.cs b/Library/FlowNode/NodeModelBaseFunc.cs
index 1895138..54f6fb8 100644
--- a/Library/FlowNode/NodeModelBaseFunc.cs
+++ b/Library/FlowNode/NodeModelBaseFunc.cs
@@ -1,6 +1,5 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
-using Serein.Library;
using Serein.Library.Api;
using Serein.Library.Utils;
using Serein.Library.Utils.SereinExpression;
diff --git a/Library/Network/WebSocket/Handle/JsonMsgHandleConfig.cs b/Library/Network/WebSocket/Handle/JsonMsgHandleConfig.cs
index 10e888a..87adcbc 100644
--- a/Library/Network/WebSocket/Handle/JsonMsgHandleConfig.cs
+++ b/Library/Network/WebSocket/Handle/JsonMsgHandleConfig.cs
@@ -212,6 +212,8 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
if (EmitMethodType == EmitHelper.EmitMethodType.HasResultTask && EmitDelegate is Func
/// 信号标识符
- /// 超时时间
/// 等待任务
public async Task GetOrCreateChannelAsync(string signal)
{
diff --git a/Library/Utils/SereinExpression/SerinExpressionEvaluator.cs b/Library/Utils/SereinExpression/SerinExpressionEvaluator.cs
index 1b12021..e583501 100644
--- a/Library/Utils/SereinExpression/SerinExpressionEvaluator.cs
+++ b/Library/Utils/SereinExpression/SerinExpressionEvaluator.cs
@@ -48,8 +48,6 @@ namespace Serein.Library.Utils.SereinExpression
///
public static object Evaluate(string expression, object targetObJ, out bool isChange)
{
- //var parts = expression.Split([' '], 2);
-
var parts = expression.Split(new[] { ' ' }, 2, StringSplitOptions.None);
if (parts.Length != 2)
{
diff --git a/Library/Utils/UIContextOperation.cs b/Library/Utils/UIContextOperation.cs
index 680bbca..f2a7700 100644
--- a/Library/Utils/UIContextOperation.cs
+++ b/Library/Utils/UIContextOperation.cs
@@ -8,7 +8,7 @@ using System.Threading.Tasks;
namespace Serein.Library.Utils
{
///
- /// 为类库提供了在UI线程上下文操作的方法
+ /// 为类库提供了在UI线程上下文操作的方法,如果你在Windows平台上运行,不必手动实例化该类
///
public class UIContextOperation
{
diff --git a/NodeFlow/Env/FlowEnvironment.cs b/NodeFlow/Env/FlowEnvironment.cs
index c6502a7..9a00c63 100644
--- a/NodeFlow/Env/FlowEnvironment.cs
+++ b/NodeFlow/Env/FlowEnvironment.cs
@@ -15,6 +15,7 @@ using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Sockets;
+using System.Numerics;
using System.Reflection;
using System.Security.Cryptography;
using System.Threading;
@@ -29,10 +30,6 @@ namespace Serein.NodeFlow.Env
-
- // ******************************************************88
-
-
///
/// 运行环境
///
@@ -54,8 +51,15 @@ namespace Serein.NodeFlow.Env
this.ChannelFlowInterrupt = new ChannelFlowInterrupt();
this.IsGlobalInterrupt = false;
this.flowStarter = null;
- this.sereinIOC.OnIOCMembersChanged += e => this?.OnIOCMembersChanged?.Invoke(e); // 监听IOC容器的注册
- this.uiContextOperation = uiContextOperation; // 本地环境需要存放视图管理
+ this.sereinIOC.OnIOCMembersChanged += e =>
+ {
+ if (OperatingSystem.IsWindows())
+ {
+ UIContextOperation?.Invoke(() => this?.OnIOCMembersChanged?.Invoke(e)); // 监听IOC容器的注册
+ }
+
+ };
+ this.UIContextOperation = uiContextOperation; // 本地环境需要存放视图管理
}
#region 远程管理
@@ -139,7 +143,7 @@ namespace Serein.NodeFlow.Env
///
/// 移除节点事件
///
- public event NodeRemoteHandler? OnNodeRemote;
+ public event NodeRemoveHandler? OnNodeRemove;
///
/// 起始节点变化事件
@@ -190,10 +194,15 @@ namespace Serein.NodeFlow.Env
#region 属性
+ ///
+ /// 当前环境
+ ///
public IFlowEnvironment CurrentEnv { get => this; }
-
-
+ ///
+ /// UI线程操作类
+ ///
+ public UIContextOperation UIContextOperation { get; set; }
///
@@ -245,11 +254,7 @@ namespace Serein.NodeFlow.Env
///
public ConcurrentDictionary MethodDetailss { get; } = [];
- ///
- /// UI线程操作类
- ///
- private readonly UIContextOperation uiContextOperation;
-
+
///
/// 容器管理
///
@@ -335,7 +340,11 @@ namespace Serein.NodeFlow.Env
public void WriteLineObjToJson(object obj)
{
var msg = JsonConvert.SerializeObject(obj);
- OnEnvOut?.Invoke(msg + Environment.NewLine);
+ if (OperatingSystem.IsWindows())
+ {
+ UIContextOperation?.Invoke(() => OnEnvOut?.Invoke(msg + Environment.NewLine));
+ }
+
}
@@ -370,8 +379,9 @@ namespace Serein.NodeFlow.Env
IOC.Reset(); // 开始运行时清空ioc中注册的实例
- IOC.CustomRegisterInstance(typeof(UIContextOperation).FullName, this.uiContextOperation, false);
IOC.CustomRegisterInstance(typeof(IFlowEnvironment).FullName, this);
+ if (this.UIContextOperation is not null)
+ IOC.CustomRegisterInstance(typeof(UIContextOperation).FullName, this.UIContextOperation, false);
await flowStarter.RunAsync(this, nodes, AutoRegisterTypes, initMethods, loadMethods, exitMethods);
@@ -401,6 +411,12 @@ namespace Serein.NodeFlow.Env
{
return;
}
+ //var getExp = "@get .DebugSetting.IsEnable";
+ //var getExpResult1 = SerinExpressionEvaluator.Evaluate(getExp, nodeModel,out _);
+ //var setExp = "@set .DebugSetting.IsEnable = false";
+ //SerinExpressionEvaluator.Evaluate(setExp, nodeModel,out _);
+ //var getExpResult2 = SerinExpressionEvaluator.Evaluate(getExp, nodeModel, out _);
+
await flowStarter.StartFlowInSelectNodeAsync(this, nodeModel);
}
else
@@ -424,9 +440,9 @@ namespace Serein.NodeFlow.Env
node.ReleaseFlowData(); // 退出时释放对象计数
}
}
+ UIContextOperation?.Invoke(() => OnFlowRunComplete?.Invoke(new FlowEventArgs()));
-
- OnFlowRunComplete?.Invoke(new FlowEventArgs());
+
GC.Collect();
}
@@ -435,7 +451,7 @@ namespace Serein.NodeFlow.Env
/// 激活全局触发器
///
///
- [AutoSocketHandle]
+ // [AutoSocketHandle]
public void ActivateFlipflopNode(string nodeGuid)
{
var nodeModel = GuidToModel(nodeGuid);
@@ -455,7 +471,7 @@ namespace Serein.NodeFlow.Env
/// 关闭全局触发器
///
///
- [AutoSocketHandle]
+ // [AutoSocketHandle]
public void TerminateFlipflopNode(string nodeGuid)
{
var nodeModel = GuidToModel(nodeGuid);
@@ -470,7 +486,7 @@ namespace Serein.NodeFlow.Env
/// 获取当前环境信息(远程连接)
///
///
- [AutoSocketHandle]
+ // [AutoSocketHandle]
public async Task GetEnvInfoAsync()
{
Dictionary> LibraryMds = [];
@@ -535,7 +551,6 @@ namespace Serein.NodeFlow.Env
foreach (var dllPath in dllPaths)
{
var dllFilePath = Path.GetFullPath(Path.Combine(filePath, dllPath));
- //var dllFilePath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(filePath)!, dllPath));
LoadDllNodeInfo(dllFilePath);
}
@@ -564,7 +579,8 @@ namespace Serein.NodeFlow.Env
if (nodeInfo.ChildNodeGuids?.Length > 0)
{
regionChildNodes.Add((nodeModel, nodeInfo.ChildNodeGuids));
- OnNodeCreate?.Invoke(new NodeCreateEventArgs(nodeModel, nodeInfo.Position));
+
+ UIContextOperation?.Invoke(() => OnNodeCreate?.Invoke(new NodeCreateEventArgs(nodeModel, nodeInfo.Position)));
}
else
{
@@ -583,8 +599,9 @@ namespace Serein.NodeFlow.Env
// 节点尚未加载
continue;
}
+ UIContextOperation?.Invoke(() => OnNodeCreate?.Invoke(new NodeCreateEventArgs(childNode, true, item.region.Guid)));
// 存在节点
- OnNodeCreate?.Invoke(new NodeCreateEventArgs(childNode, true, item.region.Guid));
+
}
}
// 加载节点
@@ -602,7 +619,8 @@ namespace Serein.NodeFlow.Env
}
}
if (IsContinue) continue;
- OnNodeCreate?.Invoke(new NodeCreateEventArgs(item.nodeModel, item.position));
+ UIContextOperation?.Invoke(() => OnNodeCreate?.Invoke(new NodeCreateEventArgs(item.nodeModel, item.position)));
+
}
@@ -633,13 +651,14 @@ namespace Serein.NodeFlow.Env
// 遍历当前类型分支的节点(确认连接关系)
foreach (var toNode in item.toNodes)
{
- ConnectNode(fromNode, toNode, item.connectionType); // 加载时确定节点间的连接关系
+ ConnectNodeAsync(fromNode, toNode, item.connectionType); // 加载时确定节点间的连接关系
}
}
}
SetStartNode(projectData.StartNode);
- OnProjectLoaded?.Invoke(new ProjectLoadedEventArgs());
+ UIContextOperation?.Invoke(() => OnProjectLoaded?.Invoke(new ProjectLoadedEventArgs()));
+
}
@@ -684,7 +703,7 @@ namespace Serein.NodeFlow.Env
/// 序列化当前项目的依赖信息、节点信息
///
///
- public async Task GetProjectInfoAsync()
+ public Task GetProjectInfoAsync()
{
var projectData = new SereinProjectData()
{
@@ -692,7 +711,7 @@ namespace Serein.NodeFlow.Env
Nodes = Nodes.Values.Select(node => node.ToInfo()).Where(info => info is not null).ToArray(),
StartNode = Nodes.Values.FirstOrDefault(it => it.IsStart)?.Guid,
};
- return projectData;
+ return Task.FromResult(projectData);
}
@@ -701,7 +720,7 @@ namespace Serein.NodeFlow.Env
///
///
///
- [AutoSocketHandle]
+ // [AutoSocketHandle]
public void LoadDll(string dllPath)
{
LoadDllNodeInfo(dllPath);
@@ -766,11 +785,10 @@ namespace Serein.NodeFlow.Env
///
///
/// 如果是表达式节点条件节点,该项为null
- public async Task CreateNodeAsync(NodeControlType nodeControlType, PositionOfUI position, MethodDetailsInfo? methodDetailsInfo = null)
+ public Task CreateNodeAsync(NodeControlType nodeControlType, PositionOfUI position, MethodDetailsInfo? methodDetailsInfo = null)
{
-
- NodeModelBase? nodeModel = null;
+ NodeModelBase? nodeModel;
if (methodDetailsInfo is null)
{
nodeModel = FlowFunc.CreateNode(this, nodeControlType); // 加载基础节点
@@ -783,7 +801,7 @@ namespace Serein.NodeFlow.Env
}
else
{
- return null;
+ return Task.FromResult(null);
}
}
@@ -792,15 +810,17 @@ namespace Serein.NodeFlow.Env
nodeModel.Position = position;
// 通知UI更改
- OnNodeCreate?.Invoke(new NodeCreateEventArgs(nodeModel, position));
+ UIContextOperation?.Invoke(() => OnNodeCreate?.Invoke(new NodeCreateEventArgs(nodeModel, position)));
+
// 因为需要UI先布置了元素,才能通知UI变更特效
// 如果不存在流程起始控件,默认设置为流程起始控件
if (StartNode is null)
{
SetStartNode(nodeModel);
}
- return nodeModel.ToInfo();
-
+ var nodeInfo = nodeModel.ToInfo();
+ return Task.FromResult(nodeInfo);
+;
}
@@ -809,10 +829,12 @@ namespace Serein.NodeFlow.Env
///
///
///
- public void RemoveNode(string nodeGuid)
+ public async Task RemoveNodeAsync(string nodeGuid)
{
var remoteNode = GuidToModel(nodeGuid);
- if (remoteNode is null) return;
+ if (remoteNode is null)
+ return false;
+
//if (remoteNode.IsStart)
//{
// return;
@@ -832,10 +854,11 @@ namespace Serein.NodeFlow.Env
NodeModelBase? pNode = pnc.Value[i];
pNode.SuccessorNodes[pCType].Remove(remoteNode);
- OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(pNode.Guid,
+ UIContextOperation?.Invoke(() => OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(pNode.Guid,
remoteNode.Guid,
pCType,
- NodeConnectChangeEventArgs.ConnectChangeType.Remote)); // 通知UI
+ NodeConnectChangeEventArgs.ConnectChangeType.Remote))); // 通知UI
+
}
}
@@ -847,14 +870,15 @@ namespace Serein.NodeFlow.Env
{
NodeModelBase? toNode = snc.Value[i];
- RemoteConnect(remoteNode, toNode, connectionType);
+ await RemoteConnectAsync(remoteNode, toNode, connectionType);
}
}
// 从集合中移除节点
Nodes.Remove(nodeGuid);
- OnNodeRemote?.Invoke(new NodeRemoteEventArgs(nodeGuid));
+ UIContextOperation?.Invoke(() => OnNodeRemove?.Invoke(new NodeRemoveEventArgs(nodeGuid)));
+ return true;
}
///
@@ -868,10 +892,10 @@ namespace Serein.NodeFlow.Env
// 获取起始节点与目标节点
var fromNode = GuidToModel(fromNodeGuid);
var toNode = GuidToModel(toNodeGuid);
- if (fromNode is null) return false;
- if (toNode is null) return false;
+ if (fromNode is null || toNode is null) return false;
+
// 开始连接
- return await ConnectNode(fromNode, toNode, connectionType); // 外部调用连接方法
+ return await ConnectNodeAsync(fromNode, toNode, connectionType); // 外部调用连接方法
}
@@ -882,15 +906,14 @@ namespace Serein.NodeFlow.Env
/// 目标节点Guid
/// 连接关系
///
- public void RemoveConnect(string fromNodeGuid, string toNodeGuid, ConnectionType connectionType)
+ public async Task RemoveConnectAsync(string fromNodeGuid, string toNodeGuid, ConnectionType connectionType)
{
// 获取起始节点与目标节点
var fromNode = GuidToModel(fromNodeGuid);
var toNode = GuidToModel(toNodeGuid);
- if (fromNode is null) return;
- if (toNode is null) return;
- RemoteConnect(fromNode, toNode, connectionType);
-
+ if (fromNode is null || toNode is null) return false;
+ var result = await RemoteConnectAsync(fromNode, toNode, connectionType);
+ return result;
}
@@ -958,7 +981,8 @@ namespace Serein.NodeFlow.Env
if (nodeModel is null) return;
nodeModel.Position.X = x;
nodeModel.Position.Y = y;
- OnNodeMoved?.Invoke(new NodeMovedEventArgs(nodeGuid, x, y));
+ UIContextOperation?.Invoke(() => OnNodeMoved?.Invoke(new NodeMovedEventArgs(nodeGuid, x, y)));
+
}
///
@@ -978,12 +1002,13 @@ namespace Serein.NodeFlow.Env
/// 被中断的目标节点Guid
/// 中断级别
/// 操作是否成功
- public async Task SetNodeInterruptAsync(string nodeGuid, InterruptClass interruptClass)
+ public Task SetNodeInterruptAsync(string nodeGuid, InterruptClass interruptClass)
{
var nodeModel = GuidToModel(nodeGuid);
- if (nodeModel is null) return false;
+ if (nodeModel is null)
+ return Task.FromResult(false);
if (interruptClass == InterruptClass.None)
{
nodeModel.CancelInterrupt();
@@ -991,10 +1016,11 @@ namespace Serein.NodeFlow.Env
else if (interruptClass == InterruptClass.Branch)
{
nodeModel.DebugSetting.CancelInterruptCallback?.Invoke();
- nodeModel.DebugSetting.GetInterruptTask = () =>
+ nodeModel.DebugSetting.GetInterruptTask = async () =>
{
TriggerInterrupt(nodeGuid, "", InterruptTriggerEventArgs.InterruptTriggerType.Monitor);
- return ChannelFlowInterrupt.GetOrCreateChannelAsync(nodeGuid);
+ var result = await ChannelFlowInterrupt.GetOrCreateChannelAsync(nodeGuid);
+ return result;
};
nodeModel.DebugSetting.CancelInterruptCallback = () =>
{
@@ -1004,11 +1030,16 @@ namespace Serein.NodeFlow.Env
}
else if (interruptClass == InterruptClass.Global) // 全局……做不了omg
{
- return false;
+ return Task.FromResult(false);
}
- nodeModel.DebugSetting.InterruptClass = interruptClass;
- OnNodeInterruptStateChange?.Invoke(new NodeInterruptStateChangeEventArgs(nodeGuid, interruptClass));
- return true;
+ nodeModel.DebugSetting.InterruptClass = interruptClass;
+ if (OperatingSystem.IsWindows())
+ {
+
+ UIContextOperation?.Invoke(() => OnNodeInterruptStateChange?.Invoke(new NodeInterruptStateChangeEventArgs(nodeGuid, interruptClass)));
+ }
+
+ return Task.FromResult(true);
}
@@ -1018,22 +1049,21 @@ namespace Serein.NodeFlow.Env
/// 如果是节点,传入Guid;如果是对象,传入类型FullName
/// 合法的条件表达式
///
- public async Task AddInterruptExpressionAsync(string key, string expression)
+ public Task AddInterruptExpressionAsync(string key, string expression)
{
- if (string.IsNullOrEmpty(expression)) return false;
+ if (string.IsNullOrEmpty(expression)) return Task.FromResult(false);
if (dictMonitorObjExpInterrupt.TryGetValue(key, out var condition))
{
condition.Clear(); // 暂时
condition.Add(expression);// 暂时
- return true;
}
else
{
var exps = new List();
exps.Add(expression);
dictMonitorObjExpInterrupt.TryAdd(key, exps);
- return true;
}
+ return Task.FromResult(true);
}
///
@@ -1073,19 +1103,41 @@ namespace Serein.NodeFlow.Env
///
///
///
- public async Task<(bool, string[])> CheckObjMonitorStateAsync(string key)
+ public Task<(bool, string[])> CheckObjMonitorStateAsync(string key)
{
if (string.IsNullOrEmpty(key))
- return (false, Array.Empty());
- var isMonitor = dictMonitorObjExpInterrupt.TryGetValue(key, out var exps);
- if (exps is null)
{
- return (isMonitor, Array.Empty());
+ var data = (false, Array.Empty());
+ return Task.FromResult(data);
}
else
{
- return (isMonitor, exps.ToArray());
+ var isMonitor = dictMonitorObjExpInterrupt.TryGetValue(key, out var exps);
+
+ if (exps is null)
+ {
+ var data = (isMonitor, Array.Empty());
+ return Task.FromResult(data);
+ }
+ else
+ {
+ var data = (isMonitor, exps.ToArray());
+ return Task.FromResult(data);
+ }
+
+
}
+
+ //if (exps is null)
+ //{
+ // var data = (isMonitor, Array.Empty());
+ // return Task.FromResult(data);
+ //}
+ //else
+ //{
+ // var data = (isMonitor, exps.ToArray());
+ // return Task.FromResult(data);
+ //}
}
@@ -1140,33 +1192,38 @@ namespace Serein.NodeFlow.Env
{
var nodeModel = GuidToModel(nodeGuid);
if (nodeModel is null) return;
- if(NodeValueChangeLogger.Remove((nodeGuid, path, value)))
+ if (NodeValueChangeLogger.Remove((nodeGuid, path, value)))
{
// 说明存在过重复的修改
return;
}
-
- Console.WriteLine($"本地环境收到数据更改通知:{value}");
-
- var getExp = $"@Get .{path}";
- //Console.WriteLine($"取值表达式:{getExp}");
- var getResult = SerinExpressionEvaluator.Evaluate(getExp, nodeModel, out _);
- Console.WriteLine($"原数据 :{getResult}");
- if (getResult.Equals(value))
- {
- Console.WriteLine("无须修改" );
- return;
- }
-
-
NodeValueChangeLogger.Add((nodeGuid, path, value));
+ var setExp = $"@Set .{path} = {value}"; // 生成 set 表达式
+ SerinExpressionEvaluator.Evaluate(setExp, nodeModel, out _); // 更改对应的数据
+
+
+
+ //Console.WriteLine($"本地环境收到数据更改通知:{value}");
+ //var getExp = $"@Get .{path}";
+ ////Console.WriteLine($"取值表达式:{getExp}");
+ //var getResult = SerinExpressionEvaluator.Evaluate(getExp, nodeModel, out _);
+ ////Console.WriteLine($"原数据 :{getResult}");
+ //if (getResult.Equals(value))
+ //{
+ // Console.WriteLine("无须修改");
+ // return;
+ //}
+
+
+ //NodeValueChangeLogger.Add((nodeGuid, path, value));
+
+
+ //var setExp = $"@Set .{path} = {value}";
+ ////Console.WriteLine($"设值表达式:{setExp}");
+ //SerinExpressionEvaluator.Evaluate(setExp, nodeModel, out _);
+ //getResult = SerinExpressionEvaluator.Evaluate(getExp, nodeModel, out _);
+ //Console.WriteLine($"新数据 :{getResult}");
-
- var setExp = $"@Set .{path} = {value}";
- //Console.WriteLine($"设值表达式:{setExp}");
- SerinExpressionEvaluator.Evaluate(setExp, nodeModel, out _);
- getResult = SerinExpressionEvaluator.Evaluate(getExp, nodeModel, out _);
- Console.WriteLine($"新数据 :{getResult}");
}
@@ -1226,8 +1283,13 @@ namespace Serein.NodeFlow.Env
}
types.AddRange(kv.Value);
}
- var mdInfo = mdlist.Select(md => md.ToInfo()).ToList(); // 转换成方法信息
- OnDllLoad?.Invoke(new LoadDllEventArgs(nodeLibrary, mdInfo)); // 通知UI创建dll面板显示
+ var mdInfos = mdlist.Select(md => md.ToInfo()).ToList(); // 转换成方法信息
+
+ if (OperatingSystem.IsWindows())
+ {
+ UIContextOperation?.Invoke(() => OnDllLoad?.Invoke(new LoadDllEventArgs(nodeLibrary, mdInfos))); // 通知UI创建dll面板显示
+
+ }
}
}
@@ -1239,16 +1301,25 @@ namespace Serein.NodeFlow.Env
/// 目标节点Model
/// 连接关系
///
- private void RemoteConnect(NodeModelBase fromNode, NodeModelBase toNode, ConnectionType connectionType)
+ private async Task RemoteConnectAsync(NodeModelBase fromNode, NodeModelBase toNode, ConnectionType connectionType)
{
fromNode.SuccessorNodes[connectionType].Remove(toNode);
toNode.PreviousNodes[connectionType].Remove(fromNode);
- // 通知UI
- OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNode.Guid,
+
+ if (OperatingSystem.IsWindows())
+ {
+ await UIContextOperation.InvokeAsync(() => OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNode.Guid,
toNode.Guid,
connectionType,
- NodeConnectChangeEventArgs.ConnectChangeType.Remote));
+ NodeConnectChangeEventArgs.ConnectChangeType.Remote)));
+ }
+ //else if (OperatingSystem.IsLinux())
+ //{
+
+ //}
+
+ return true;
}
private (NodeLibrary?, Dictionary>, List) LoadAssembly(string dllPath)
@@ -1377,11 +1448,11 @@ namespace Serein.NodeFlow.Env
/// 起始节点
/// 目标节点
/// 连接关系
- private Task ConnectNode(NodeModelBase fromNode, NodeModelBase toNode, ConnectionType connectionType)
+ private async Task ConnectNodeAsync(NodeModelBase fromNode, NodeModelBase toNode, ConnectionType connectionType)
{
if (fromNode is null || toNode is null || fromNode == toNode)
{
- return Task.FromResult(false);
+ return false;
}
var ToExistOnFrom = true;
@@ -1428,23 +1499,26 @@ namespace Serein.NodeFlow.Env
}
}
}
- if (!isPass)
- {
- return Task.FromResult(false);
- }
- else
+ if (isPass)
{
fromNode.SuccessorNodes[connectionType].Add(toNode); // 添加到起始节点的子分支
toNode.PreviousNodes[connectionType].Add(fromNode); // 添加到目标节点的父分支
- OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNode.Guid,
- toNode.Guid,
- connectionType,
- NodeConnectChangeEventArgs.ConnectChangeType.Create)); // 通知UI
+ if (OperatingSystem.IsWindows())
+ {
+ UIContextOperation?.Invoke(() => OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNode.Guid,
+ toNode.Guid,
+ connectionType,
+ NodeConnectChangeEventArgs.ConnectChangeType.Create))); // 通知UI
+ }
- return Task.FromResult(true);
+ return true;
+ }
+ else
+ {
+ return false;
}
-
+
}
///
@@ -1456,7 +1530,11 @@ namespace Serein.NodeFlow.Env
{
var oldNodeGuid = StartNode?.Guid;
StartNode = newStartNode;
- OnStartNodeChange?.Invoke(new StartNodeChangeEventArgs(oldNodeGuid, StartNode.Guid));
+ if (OperatingSystem.IsWindows())
+ {
+ UIContextOperation?.Invoke(() => OnStartNodeChange?.Invoke(new StartNodeChangeEventArgs(oldNodeGuid, StartNode.Guid)));
+ }
+
}
///
@@ -1465,7 +1543,11 @@ namespace Serein.NodeFlow.Env
///
private void Output(string msg)
{
- OnEnvOut?.Invoke(msg);
+ if (OperatingSystem.IsWindows())
+ {
+ UIContextOperation?.Invoke(() => OnEnvOut?.Invoke(msg));
+ }
+
}
#endregion
@@ -1478,7 +1560,11 @@ namespace Serein.NodeFlow.Env
///
public void NodeLocated(string nodeGuid)
{
- OnNodeLocated?.Invoke(new NodeLocatedEventArgs(nodeGuid));
+ if (OperatingSystem.IsWindows())
+ {
+ UIContextOperation?.Invoke(() => OnNodeLocated?.Invoke(new NodeLocatedEventArgs(nodeGuid)));
+ }
+
}
#endregion
diff --git a/NodeFlow/Env/FlowEnvironmentDecorator.cs b/NodeFlow/Env/FlowEnvironmentDecorator.cs
index 3624612..05255ce 100644
--- a/NodeFlow/Env/FlowEnvironmentDecorator.cs
+++ b/NodeFlow/Env/FlowEnvironmentDecorator.cs
@@ -67,6 +67,7 @@ namespace Serein.NodeFlow.Env
///
public IFlowEnvironment CurrentEnv { get => currentFlowEnvironment; }
+ public UIContextOperation UIContextOperation => currentFlowEnvironment.UIContextOperation;
public ISereinIOC IOC => (ISereinIOC)currentFlowEnvironment;
@@ -103,10 +104,10 @@ namespace Serein.NodeFlow.Env
remove { currentFlowEnvironment.OnNodeCreate -= value; }
}
- public event NodeRemoteHandler OnNodeRemote
+ public event NodeRemoveHandler OnNodeRemove
{
- add { currentFlowEnvironment.OnNodeRemote += value; }
- remove { currentFlowEnvironment.OnNodeRemote -= value; }
+ add { currentFlowEnvironment.OnNodeRemove += value; }
+ remove { currentFlowEnvironment.OnNodeRemove -= value; }
}
public event StartNodeChangeHandler OnStartNodeChange
@@ -198,7 +199,8 @@ namespace Serein.NodeFlow.Env
(var isConnect, var remoteEnvControl) = await currentFlowEnvironment.ConnectRemoteEnv(addres, port, token);
if (isConnect)
{
- remoteFlowEnvironment ??= new RemoteFlowEnvironment(remoteEnvControl);
+
+ remoteFlowEnvironment ??= new RemoteFlowEnvironment(remoteEnvControl, this.UIContextOperation);
currentFlowEnvironment = remoteFlowEnvironment;
}
return (isConnect, remoteEnvControl);
@@ -277,14 +279,14 @@ namespace Serein.NodeFlow.Env
return currentFlowEnvironment.RemoteDll(assemblyFullName);
}
- public void RemoveConnect(string fromNodeGuid, string toNodeGuid, ConnectionType connectionType)
+ public async Task RemoveConnectAsync(string fromNodeGuid, string toNodeGuid, ConnectionType connectionType)
{
- currentFlowEnvironment.RemoveConnect(fromNodeGuid, toNodeGuid, connectionType);
+ return await currentFlowEnvironment.RemoveConnectAsync(fromNodeGuid, toNodeGuid, connectionType);
}
- public void RemoveNode(string nodeGuid)
+ public async Task RemoveNodeAsync(string nodeGuid)
{
- currentFlowEnvironment.RemoveNode(nodeGuid);
+ return await currentFlowEnvironment.RemoveNodeAsync(nodeGuid);
}
diff --git a/NodeFlow/Env/MsgControllerOfClient.cs b/NodeFlow/Env/MsgControllerOfClient.cs
index b035cce..8eaeaec 100644
--- a/NodeFlow/Env/MsgControllerOfClient.cs
+++ b/NodeFlow/Env/MsgControllerOfClient.cs
@@ -1,4 +1,5 @@
-using Serein.Library;
+using Newtonsoft.Json;
+using Serein.Library;
using Serein.Library.Network.WebSocketCommunication;
using Serein.Library.Utils;
using System;
@@ -35,13 +36,14 @@ namespace Serein.NodeFlow.Env
///
///
/// 超时触发
- public async Task SendAsync(string signal, object? senddata = null, int debounceTimeInMs = 100)
+ public async Task SendAsync(string signal, object? sendData = null, int overtimeInMs = 100)
{
- if (!DebounceHelper.CanExecute(signal, debounceTimeInMs))
+ //Console.WriteLine($"指令[{signal}],value:{JsonConvert.SerializeObject(sendData)}");
+ if (!DebounceHelper.CanExecute(signal, overtimeInMs))
{
return;
}
- await SendCommandAsync.Invoke(signal, senddata);
+ await SendCommandAsync.Invoke(signal, sendData);
}
///
@@ -49,32 +51,32 @@ namespace Serein.NodeFlow.Env
///
///
/// 超时触发
- public async Task SendAndWaitDataAsync(string signal, object? senddata = null, int debounceTimeInMs = 50)
+ public async Task SendAndWaitDataAsync(string signal, object? sendData = null, int overtimeInMs = 50)
{
- _ = SendCommandAsync.Invoke(signal, senddata);
+ //Console.WriteLine($"指令[{signal}],value:{JsonConvert.SerializeObject(sendData)}");
+ _ = SendCommandAsync.Invoke(signal, sendData);
return await remoteFlowEnvironment.WaitData(signal);
-#if DEBUG
- if (DebounceHelper.CanExecute(signal, debounceTimeInMs))
- {
- _ = SendCommandAsync.Invoke(signal, senddata);
- return await remoteFlowEnvironment.WaitData(signal);
+ //if (DebounceHelper.CanExecute(signal, overtimeInMs))
+ //{
+ // _ = SendCommandAsync.Invoke(signal, sendData);
+ // return await remoteFlowEnvironment.WaitData(signal);
+
+ // //(var type, var result) = await remoteFlowEnvironment.WaitDataWithTimeoutAsync(signal, TimeSpan.FromSeconds(150));
+ // //if (type == TriggerType.Overtime)
+ // //{
+ // // throw new NotImplementedException("超时触发");
+ // //}
+ // //else
+ // //{
+ // // return result;
+ // //}
+ //}
+ //else
+ //{
+ // return default;
+ //}
- //(var type, var result) = await remoteFlowEnvironment.WaitDataWithTimeoutAsync(signal, TimeSpan.FromSeconds(150));
- //if (type == TriggerType.Overtime)
- //{
- // throw new NotImplementedException("超时触发");
- //}
- //else
- //{
- // return result;
- //}
- }
- else
- {
- return default;
- }
-#endif
}
@@ -92,11 +94,6 @@ namespace Serein.NodeFlow.Env
}
- [AutoSocketHandle(ThemeValue = EnvMsgTheme.CreateNode)]
- public void AddInterruptExpression([UseMsgData] NodeInfo nodeInfo)
- {
- remoteFlowEnvironment.TriggerSignal(EnvMsgTheme.CreateNode, nodeInfo);
- }
///
@@ -122,6 +119,35 @@ namespace Serein.NodeFlow.Env
}
+
+ [AutoSocketHandle(ThemeValue = EnvMsgTheme.CreateNode)]
+ public void CreateNode([UseMsgData] NodeInfo nodeInfo)
+ {
+ remoteFlowEnvironment.TriggerSignal(EnvMsgTheme.CreateNode, nodeInfo);
+ }
+
+ [AutoSocketHandle(ThemeValue = EnvMsgTheme.RemoveNode)]
+ public void RemoveNode(bool state)
+ {
+ remoteFlowEnvironment.TriggerSignal(EnvMsgTheme.RemoveNode, state);
+ }
+
+
+ [AutoSocketHandle(ThemeValue = EnvMsgTheme.ConnectNode)]
+ public void ConnectNode(bool state)
+ {
+ remoteFlowEnvironment.TriggerSignal(EnvMsgTheme.ConnectNode, state);
+ }
+
+ [AutoSocketHandle(ThemeValue = EnvMsgTheme.RemoveConnect)]
+ public void RemoveConnect(bool state)
+ {
+ remoteFlowEnvironment.TriggerSignal(EnvMsgTheme.RemoveConnect, state);
+ }
+
+
+
+
#endregion
}
diff --git a/NodeFlow/Env/MsgControllerOfServer.cs b/NodeFlow/Env/MsgControllerOfServer.cs
index 72c18e4..c838bf6 100644
--- a/NodeFlow/Env/MsgControllerOfServer.cs
+++ b/NodeFlow/Env/MsgControllerOfServer.cs
@@ -184,13 +184,14 @@ namespace Serein.NodeFlow.Env
///
/// 从远程环境运行选定的节点
///
- ///
+ ///
///
[AutoSocketHandle(ThemeValue = EnvMsgTheme.StartFlowInSelectNode)]
- private async Task StartAsyncInSelectNode(string startNodeGuid)
+ private async Task StartAsyncInSelectNode(string nodeGuid)
{
- await environment.StartAsyncInSelectNode(startNodeGuid);
+ await environment.StartAsyncInSelectNode(nodeGuid);
}
+
///
/// 结束流程
///
@@ -321,9 +322,15 @@ namespace Serein.NodeFlow.Env
///
///
[AutoSocketHandle(ThemeValue = EnvMsgTheme.RemoveNode)]
- public void RemoveNode(string nodeGuid)
+ public async Task RemoveNode(string nodeGuid)
{
- environment.RemoveNode(nodeGuid);
+ //var result = environment.RemoveNodeAsync(nodeGuid).GetAwaiter().GetResult();
+ var result = await environment.RemoveNodeAsync(nodeGuid);
+ //return result;
+ return new
+ {
+ state = result
+ };
}
@@ -334,9 +341,21 @@ namespace Serein.NodeFlow.Env
/// 目标节点
/// 连接关系
[AutoSocketHandle(ThemeValue = EnvMsgTheme.ConnectNode)]
- public void ConnectNode(string fromNodeGuid, string toNodeGuid, ConnectionType connectionType)
+ public async Task ConnectNode(string fromNodeGuid, string toNodeGuid, string connectionType)
{
- environment.ConnectNodeAsync(fromNodeGuid, toNodeGuid, connectionType);
+ if (!EnumHelper.TryConvertEnum(connectionType, out var tmpConnectionType))
+ {
+ return new
+ {
+ state = false
+ };
+ }
+ //environment.ConnectNodeAsync(fromNodeGuid, toNodeGuid, tmpConnectionType);
+ var result = await environment.ConnectNodeAsync(fromNodeGuid, toNodeGuid, tmpConnectionType);
+ return new
+ {
+ state = result
+ };
}
///
@@ -347,9 +366,21 @@ namespace Serein.NodeFlow.Env
/// 连接关系
///
[AutoSocketHandle(ThemeValue = EnvMsgTheme.RemoveConnect)]
- public void RemoveConnect(string fromNodeGuid, string toNodeGuid, ConnectionType connectionType)
+ public async Task RemoveConnect(string fromNodeGuid, string toNodeGuid, string connectionType)
{
- environment.RemoveConnect(fromNodeGuid, toNodeGuid, connectionType);
+ if (!EnumHelper.TryConvertEnum(connectionType, out var tmpConnectionType))
+ {
+ return new
+ {
+ state = false
+ };
+ }
+
+ var result = await environment.RemoveConnectAsync(fromNodeGuid, toNodeGuid, tmpConnectionType);
+ return new
+ {
+ state = result
+ };
}
///
diff --git a/NodeFlow/Env/RemoteFlowEnvironment.cs b/NodeFlow/Env/RemoteFlowEnvironment.cs
index 17d6581..a15ee0a 100644
--- a/NodeFlow/Env/RemoteFlowEnvironment.cs
+++ b/NodeFlow/Env/RemoteFlowEnvironment.cs
@@ -18,9 +18,11 @@ namespace Serein.NodeFlow.Env
///
/// 连接到远程环境后切换到的环境接口实现
///
- /// 连接到远程环境的客户端
- public RemoteFlowEnvironment(RemoteEnvControl RemoteEnvControl)
+ /// 连接到远程环境后,本地环境自动切换到对应的环境实体
+ /// 远程环境下需要操作UI线程时,所提供的线程上下文封装工具
+ public RemoteFlowEnvironment(RemoteEnvControl RemoteEnvControl, UIContextOperation uIContextOperation)
{
+ this.UIContextOperation = uIContextOperation;
remoteEnvControl = RemoteEnvControl;
msgClient = new MsgControllerOfClient(this, RemoteEnvControl.SendAsync);
RemoteEnvControl.EnvClient.MsgHandleHelper.AddModule(msgClient, (ex, send) =>
@@ -34,9 +36,6 @@ namespace Serein.NodeFlow.Env
private readonly MsgControllerOfClient msgClient;
private readonly ConcurrentDictionary MethodDetailss = [];
-
-
-
///
/// 环境加载的节点集合
/// Node Guid - Node Model
@@ -47,7 +46,7 @@ namespace Serein.NodeFlow.Env
public event ProjectLoadedHandler OnProjectLoaded;
public event NodeConnectChangeHandler OnNodeConnectChange;
public event NodeCreateHandler OnNodeCreate;
- public event NodeRemoteHandler OnNodeRemote;
+ public event NodeRemoveHandler OnNodeRemove;
public event StartNodeChangeHandler OnStartNodeChange;
public event FlowRunCompleteHandler OnFlowRunComplete;
public event MonitorObjectChangeHandler OnMonitorObjectChange;
@@ -72,7 +71,7 @@ namespace Serein.NodeFlow.Env
public RunState FlipFlopState { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public IFlowEnvironment CurrentEnv => this;
-
+ public UIContextOperation UIContextOperation { get; }
public void SetConsoleOut()
{
var logTextWriter = new LogTextWriter(msg =>
@@ -118,8 +117,8 @@ namespace Serein.NodeFlow.Env
FilePath = "Remote",
};
var mdInfos = lib.Mds.ToList();
- OnDllLoad?.Invoke(new LoadDllEventArgs(nodeLibrary, mdInfos)); // 通知UI创建dll面板显示
-
+ //OnDllLoad?.Invoke(new LoadDllEventArgs(nodeLibrary, mdInfos)); // 通知UI创建dll面板显示
+ UIContextOperation?.Invoke(() => OnDllLoad?.Invoke(new LoadDllEventArgs(nodeLibrary, mdInfos))); // 通知UI创建dll面板显示
foreach (var mdInfo in mdInfos)
{
MethodDetailss.TryAdd(mdInfo.MethodName, new MethodDetails(mdInfo)); // 从DLL读取时生成元数据
@@ -160,7 +159,8 @@ namespace Serein.NodeFlow.Env
if (nodeInfo.ChildNodeGuids?.Length > 0)
{
regionChildNodes.Add((nodeModel, nodeInfo.ChildNodeGuids));
- OnNodeCreate?.Invoke(new NodeCreateEventArgs(nodeModel, nodeInfo.Position));
+ UIContextOperation?.Invoke(() => OnNodeCreate?.Invoke(new NodeCreateEventArgs(nodeModel, nodeInfo.Position)));
+ //OnNodeCreate?.Invoke(new NodeCreateEventArgs(nodeModel, nodeInfo.Position));
}
else
{
@@ -181,7 +181,8 @@ namespace Serein.NodeFlow.Env
continue;
}
// 存在节点
- OnNodeCreate?.Invoke(new NodeCreateEventArgs(childNode, true, item.region.Guid));
+ //OnNodeCreate?.Invoke(new NodeCreateEventArgs(childNode, true, item.region.Guid));
+ UIContextOperation?.Invoke(() => OnNodeCreate?.Invoke(new NodeCreateEventArgs(childNode, true, item.region.Guid)));
}
}
@@ -200,7 +201,8 @@ namespace Serein.NodeFlow.Env
}
}
if (IsContinue) continue;
- OnNodeCreate?.Invoke(new NodeCreateEventArgs(item.nodeModel, item.position));
+ //OnNodeCreate?.Invoke(new NodeCreateEventArgs(item.nodeModel, item.position));
+ UIContextOperation?.Invoke(() => OnNodeCreate?.Invoke(new NodeCreateEventArgs(item.nodeModel, item.position)));
}
@@ -208,7 +210,7 @@ namespace Serein.NodeFlow.Env
// 确定节点之间的连接关系
_ = Task.Run(async () =>
{
- await Task.Delay(100);
+ await Task.Delay(250);
foreach (var nodeInfo in projectData.Nodes)
{
if (!Nodes.TryGetValue(nodeInfo.Guid, out NodeModelBase? fromNode))
@@ -234,12 +236,16 @@ namespace Serein.NodeFlow.Env
// 遍历当前类型分支的节点(确认连接关系)
foreach (var toNode in item.toNodes)
{
- OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNode.Guid,
- toNode.Guid,
- item.connectionType,
- NodeConnectChangeEventArgs.ConnectChangeType.Create)); // 通知UI创建节点
- //ConnectNode(fromNode, toNode, item.connectionType); // 加载时确定节点间的连接关系
+ UIContextOperation?.Invoke(() => OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNode.Guid,
+ toNode.Guid,
+ item.connectionType,
+ NodeConnectChangeEventArgs.ConnectChangeType.Create))); // 通知UI连接节点
+ //OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNode.Guid,
+ // toNode.Guid,
+ // item.connectionType,
+ // NodeConnectChangeEventArgs.ConnectChangeType.Create)); //
+
}
}
}
@@ -251,7 +257,7 @@ namespace Serein.NodeFlow.Env
}
private bool TryAddNode(NodeModelBase nodeModel)
{
- nodeModel.Guid ??= Guid.NewGuid().ToString();
+ //nodeModel.Guid ??= Guid.NewGuid().ToString();
Nodes[nodeModel.Guid] = nodeModel;
// 如果是触发器,则需要添加到专属集合中
@@ -375,7 +381,7 @@ namespace Serein.NodeFlow.Env
public async Task StartAsyncInSelectNode(string startNodeGuid)
{
- await msgClient.SendAsync(EnvMsgTheme.StartFlowInSelectNode, new
+ _ = msgClient.SendAsync(EnvMsgTheme.StartFlowInSelectNode, new
{
nodeGuid = startNodeGuid
});
@@ -404,22 +410,24 @@ namespace Serein.NodeFlow.Env
{
nodeGuid
});
+ // UIContextOperation?.Invoke(() => OnStartNodeChange?.Invoke(new StartNodeChangeEventArgs(oldNodeGuid, StartNode.Guid)));
}
public async Task ConnectNodeAsync(string fromNodeGuid, string toNodeGuid, ConnectionType connectionType)
{
- //_ = RemoteEnv.SendAsync(EnvMsgTheme.ConnectNode, new
- //{
- // fromNodeGuid,
- // toNodeGuid,
- // connectionType = connectionType.ToString(),
- //});
var result = await msgClient.SendAndWaitDataAsync(EnvMsgTheme.ConnectNode, new
{
fromNodeGuid,
toNodeGuid,
connectionType = connectionType.ToString(),
});
+ if (result)
+ {
+ OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNodeGuid,
+ toNodeGuid,
+ connectionType,
+ NodeConnectChangeEventArgs.ConnectChangeType.Create)); // 通知UI
+ }
return result;
}
@@ -434,30 +442,47 @@ namespace Serein.NodeFlow.Env
MethodDetailss.TryGetValue(methodDetailsInfo.MethodName, out var methodDetails);// 加载项目时尝试获取方法信息
var nodeModel = FlowFunc.CreateNode(this, nodeControlType, methodDetails); // 远程环境下加载节点
- TryAddNode(nodeModel);
nodeModel.LoadInfo(nodeInfo);
+ TryAddNode(nodeModel);
// 通知UI更改
OnNodeCreate?.Invoke(new NodeCreateEventArgs(nodeModel, position));
return nodeInfo;
}
- public void RemoveConnect(string fromNodeGuid, string toNodeGuid, ConnectionType connectionType)
+ public async Task RemoveConnectAsync(string fromNodeGuid, string toNodeGuid, ConnectionType connectionType)
{
- _ = msgClient.SendAsync(EnvMsgTheme.RemoveConnect, new
+ var result = await msgClient.SendAndWaitDataAsync(EnvMsgTheme.RemoveConnect, new
{
fromNodeGuid,
toNodeGuid,
connectionType = connectionType.ToString(),
});
+ if (result)
+ {
+ OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNodeGuid,
+ toNodeGuid,
+ connectionType,
+ NodeConnectChangeEventArgs.ConnectChangeType.Remote));
+ }
+ return result;
}
- public void RemoveNode(string nodeGuid)
+ public async Task RemoveNodeAsync(string nodeGuid)
{
- _ = msgClient.SendAsync(EnvMsgTheme.RemoveNode, new
+ var result = await msgClient.SendAndWaitDataAsync(EnvMsgTheme.RemoveNode, new
{
nodeGuid
});
+ if (result)
+ {
+ OnNodeRemove?.Invoke(new NodeRemoveEventArgs(nodeGuid));
+ }
+ else
+ {
+ Console.WriteLine("删除失败");
+ }
+ return result;
}
public void ActivateFlipflopNode(string nodeGuid)
@@ -559,14 +584,14 @@ namespace Serein.NodeFlow.Env
public void NodeLocated(string nodeGuid)
{
- Console.WriteLine("远程环境尚未实现的接口:NodeLocated");
+ //Console.WriteLine("远程环境尚未实现的接口:NodeLocated");
+ UIContextOperation?.Invoke(() => OnNodeLocated?.Invoke(new NodeLocatedEventArgs(nodeGuid)));
}
public async Task NotificationNodeValueChangeAsync(string nodeGuid, string path, object value)
{
-
//Console.WriteLine($"通知远程环境修改节点数据:{nodeGuid},name:{path},value:{value}");
- _ = msgClient.SendAsync(EnvMsgTheme.ValueNotification, new
+ _ = msgClient.SendAsync(EnvMsgTheme.ValueNotification, new
{
nodeGuid = nodeGuid,
path = path,
diff --git a/NodeFlow/FlowStarter.cs b/NodeFlow/FlowStarter.cs
index 98e37f7..d74a63c 100644
--- a/NodeFlow/FlowStarter.cs
+++ b/NodeFlow/FlowStarter.cs
@@ -3,7 +3,6 @@ using Serein.Library.Api;
using Serein.Library.Core.NodeFlow;
using Serein.Library.Network.WebSocketCommunication;
using Serein.Library.Web;
-using Serein.Library;
using Serein.NodeFlow.Env;
using Serein.NodeFlow.Model;
using System.Collections.Concurrent;
@@ -284,6 +283,7 @@ namespace Serein.NodeFlow
finally
{
env.FlowState = RunState.Completion;
+ Console.WriteLine($"流程运行完毕{Environment.NewLine}");;
}
#endregion
}
diff --git a/NodeFlow/Serein.NodeFlow.csproj b/NodeFlow/Serein.NodeFlow.csproj
index 5614056..881f2d1 100644
--- a/NodeFlow/Serein.NodeFlow.csproj
+++ b/NodeFlow/Serein.NodeFlow.csproj
@@ -1,7 +1,7 @@
- 1.0.14
+ 1.0.16
net8.0
enable
enable
diff --git a/Serein.Library.MyGenerator/ParameterDetailsPropertyGenerator.cs b/Serein.Library.MyGenerator/ParameterDetailsPropertyGenerator.cs
index 887212c..0e4cbbf 100644
--- a/Serein.Library.MyGenerator/ParameterDetailsPropertyGenerator.cs
+++ b/Serein.Library.MyGenerator/ParameterDetailsPropertyGenerator.cs
@@ -10,7 +10,7 @@ using System.Text;
using System.Threading;
-namespace Serein.Library.MyGenerator
+namespace Serein.Library.NodeGenerator
{
@@ -20,6 +20,7 @@ namespace Serein.Library.MyGenerator
[Generator]
public class MyPropertyGenerator : IIncrementalGenerator
{
+
///
/// 初始化生成器,定义需要执行的生成逻辑。
///
@@ -83,6 +84,17 @@ namespace Serein.Library.MyGenerator
}
});
}
+ private int myProperty;
+
+ public int MyProperty { get => myProperty; set
+ {
+ if(myProperty == null)
+ {
+
+ myProperty = value;
+ }
+ } }
+
@@ -103,20 +115,28 @@ namespace Serein.Library.MyGenerator
// 生成命名空间和类的开始部分
sb.AppendLine($"using System;");
+ sb.AppendLine($"using System.Threading;");
+ sb.AppendLine($"using System.Threading.Tasks;");
+ sb.AppendLine($"using System.Collections.Concurrent;");
sb.AppendLine($"using Serein.Library;");
sb.AppendLine($"using Serein.Library.Api;");
+ sb.AppendLine($"using static Serein.Library.Utils.ChannelFlowInterrupt;");
sb.AppendLine($"");
sb.AppendLine($"namespace {namespaceName}");
sb.AppendLine("{");
- sb.AppendLine($" public partial class {className}");
+ sb.AppendLine($" public partial class {className} : System.ComponentModel.INotifyPropertyChanged");
sb.AppendLine(" {");
var path = classInfo["AutoPropertyAttribute"]["ValuePath"];
+
+ //
+ //
+
// "ParameterDetails";
// "MethodDetails";
-
+
try
@@ -130,35 +150,36 @@ namespace Serein.Library.MyGenerator
continue;
}
- var leadingTrivia = field.GetLeadingTrivia().InsertSummaryComment("(此属性由源生成器生成)").ToString(); // 获取注释
+ var leadingTrivia = field.GetLeadingTrivia().InsertSummaryComment("(此属性为自动生成)").ToString(); // 获取注释
var fieldName = field.Declaration.Variables.First().Identifier.Text; // 获取字段名称
var fieldType = field.Declaration.Type.ToString(); // 获取字段类型
var propertyName = field.ToPropertyName(); // 转为合适的属性名称
var attributeInfo = fieldKV.Value; // 缓存的特性信息
- //if (!attributeInfo.TryGetValue("PropertyInfo",out var tmp) || tmp.Count == 0)
- //{
- // continue;
- //}
-
+ var isProtection = attributeInfo.Search("PropertyInfo", "IsProtection", "true"); // 是否为保护字段
+
// 生成 getter / setter
sb.AppendLine(leadingTrivia);
sb.AppendLine($" public {fieldType} {propertyName}");
sb.AppendLine(" {");
- sb.AppendLine($" get => {fieldName};");
+ sb.AppendLine($" get => {fieldName};"); // getter方法
sb.AppendLine(" set");
sb.AppendLine(" {");
- sb.AppendLine($" if ({fieldName} != value)");
- sb.AppendLine(" {");
+ sb.AppendLine($" if ({fieldName} {(isProtection ? "== default" : "!= value")})"); // 非保护的Setter
+ sb.AppendLine(" {");
if (attributeInfo.Search("PropertyInfo", "IsPrint", "true")) // 是否打印
{
sb.AddCode(5, $"Console.WriteLine({fieldName});");
}
if (attributeInfo.Search("PropertyInfo", "IsNotification", "true")) // 是否通知
{
- if (classInfo.ExitsPath("MethodDetails"))
+ if (classInfo.ExitsPath("NodeModelBase"))
+ {
+ sb.AddCode(5, $"this.env?.NotificationNodeValueChangeAsync(this.Guid, .nameof({propertyName}), value);");
+ }
+ else if (classInfo.ExitsPath("MethodDetails"))
{
sb.AddCode(5, $"nodeModel?.Env?.NotificationNodeValueChangeAsync(nodeModel.Guid, \"MethodDetails.\"+nameof({propertyName}), value);");
}
@@ -166,26 +187,53 @@ namespace Serein.Library.MyGenerator
{
sb.AddCode(5, "nodeModel?.Env?.NotificationNodeValueChangeAsync(nodeModel.Guid, \"MethodDetails.ParameterDetailss[\"+$\"{Index}\"+\"]." + $"\"+nameof({propertyName}),value);");
}
-
+ else if (classInfo.ExitsPath("NodeDebugSetting"))
+ {
+ sb.AddCode(5, $"nodeModel?.Env?.NotificationNodeValueChangeAsync(nodeModel.Guid, \"DebugSetting.\"+nameof({propertyName}), value);");
+ }
}
- sb.AppendLine($" {fieldName} = value;");
+ sb.AppendLine($" {fieldName} = value;");
+ sb.AppendLine($" OnPropertyChanged(); // 先更改属性,然后通知属性发生改变了");
sb.AppendLine(" }");
sb.AppendLine(" }");
- sb.AppendLine(" }");
+ sb.AppendLine(" }"); // 属性的结尾大括号
}
+
+
+ sb.AppendLine(" /// ");
+ sb.AppendLine(" /// 略");
+ sb.AppendLine(" /// 此事件为自动生成");
+ sb.AppendLine(" /// ");
+ sb.AppendLine(" public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;");
+
+ sb.AppendLine(" /// ");
+ sb.AppendLine(" /// 略");
+ sb.AppendLine(" /// 此方法为自动生成");
+ sb.AppendLine(" /// ");
+ sb.AppendLine(" /// ");
+ sb.AppendLine(" ");
+ sb.AppendLine(" protected void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = null)");
+ sb.AppendLine(" {");
+ //sb.AppendLine(" Console.WriteLine(\"测试:\"+ propertyName);");
+ sb.AppendLine(" PropertyChanged?.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));");
+ sb.AppendLine(" }");
+
+
}
finally
{
// 生成类的结束部分
- sb.AppendLine(" }");
- sb.AppendLine("}");
+ sb.AppendLine(" }"); // 类的结尾大括号
+ sb.AppendLine("}"); // 命名空间的结尾大括号
}
-
-
return sb.ToString(); // 返回生成的代码
}
-
+
+
+
+
+
///
/// 获取类所在的命名空间。
///
@@ -198,7 +246,19 @@ namespace Serein.Library.MyGenerator
return namespaceDeclaration?.Name.ToString() ?? "GlobalNamespace";
}
-
+
+
+ private void SetterIsProtection()
+ {
+
+ }
+ private void SetterNotIsProtection()
+ {
+
+ }
+
+
+
}
diff --git a/Serein.Library.MyGenerator/Serein.Library.MyGenerator.csproj b/Serein.Library.MyGenerator/Serein.Library.MyGenerator.csproj
deleted file mode 100644
index f9f1199..0000000
--- a/Serein.Library.MyGenerator/Serein.Library.MyGenerator.csproj
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
- netstandard2.0
- true
-
-
-
-
-
-
-
-
diff --git a/Serein.Library.MyGenerator/Serein.Library.NodeGenerator.csproj b/Serein.Library.MyGenerator/Serein.Library.NodeGenerator.csproj
new file mode 100644
index 0000000..d648318
--- /dev/null
+++ b/Serein.Library.MyGenerator/Serein.Library.NodeGenerator.csproj
@@ -0,0 +1,38 @@
+
+
+
+ netstandard2.0
+ true
+ D:\Project\C#\DynamicControl\SereinFlow\.Output
+ True
+ SereinFow
+ 基础依赖必须添加项,用于生成NodeModel部分的依赖实体代码
+ README.md
+ https://github.com/fhhyyp/serein-flow
+ MIT
+ True
+ true
+
+
+
+
+
+
+
+
+
+ True
+ \
+
+
+ True
+ \
+
+
+
diff --git a/SereinFlow.sln b/SereinFlow.sln
index 7cc108a..92ac60f 100644
--- a/SereinFlow.sln
+++ b/SereinFlow.sln
@@ -24,7 +24,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Serein.Extend.RemoteControl
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Serein.FlowStartTool", "FlowStartTool\Serein.FlowStartTool.csproj", "{38D0FA92-5139-4616-A41E-8186AA4C1532}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Serein.Library.MyGenerator", "Serein.Library.MyGenerator\Serein.Library.MyGenerator.csproj", "{5F7DE0B2-A5D3-492D-AC6C-F0C39EBEF365}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Serein.Library.NodeGenerator", "Serein.Library.MyGenerator\Serein.Library.NodeGenerator.csproj", "{5F7DE0B2-A5D3-492D-AC6C-F0C39EBEF365}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
diff --git a/WorkBench/MainWindow.xaml b/WorkBench/MainWindow.xaml
index c59145c..25379ba 100644
--- a/WorkBench/MainWindow.xaml
+++ b/WorkBench/MainWindow.xaml
@@ -43,7 +43,7 @@
diff --git a/WorkBench/MainWindow.xaml.cs b/WorkBench/MainWindow.xaml.cs
index 2599311..e956b7a 100644
--- a/WorkBench/MainWindow.xaml.cs
+++ b/WorkBench/MainWindow.xaml.cs
@@ -186,7 +186,7 @@ namespace Serein.Workbench
EnvDecorator.OnStartNodeChange += FlowEnvironment_StartNodeChangeEvent;
EnvDecorator.OnNodeConnectChange += FlowEnvironment_NodeConnectChangeEvemt;
EnvDecorator.OnNodeCreate += FlowEnvironment_NodeCreateEvent;
- EnvDecorator.OnNodeRemote += FlowEnvironment_NodeRemoteEvent;
+ EnvDecorator.OnNodeRemove += FlowEnvironment_NodeRemoteEvent;
EnvDecorator.OnFlowRunComplete += FlowEnvironment_OnFlowRunComplete;
@@ -213,7 +213,7 @@ namespace Serein.Workbench
EnvDecorator.OnStartNodeChange -= FlowEnvironment_StartNodeChangeEvent;
EnvDecorator.OnNodeConnectChange -= FlowEnvironment_NodeConnectChangeEvemt;
EnvDecorator.OnNodeCreate -= FlowEnvironment_NodeCreateEvent;
- EnvDecorator.OnNodeRemote -= FlowEnvironment_NodeRemoteEvent;
+ EnvDecorator.OnNodeRemove -= FlowEnvironment_NodeRemoteEvent;
EnvDecorator.OnFlowRunComplete -= FlowEnvironment_OnFlowRunComplete;
@@ -312,47 +312,45 @@ namespace Serein.Workbench
///
private void FlowEnvironment_DllLoadEvent(LoadDllEventArgs eventArgs)
{
- this.Dispatcher.Invoke(() => {
- NodeLibrary nodeLibrary = eventArgs.NodeLibrary;
- List methodDetailss = eventArgs.MethodDetailss;
+ NodeLibrary nodeLibrary = eventArgs.NodeLibrary;
+ List methodDetailss = eventArgs.MethodDetailss;
- var dllControl = new DllControl(nodeLibrary);
+ var dllControl = new DllControl(nodeLibrary);
- foreach (var methodDetailsInfo in methodDetailss)
+ foreach (var methodDetailsInfo in methodDetailss)
+ {
+ if (!EnumHelper.TryConvertEnum(methodDetailsInfo.NodeType, out var nodeType))
{
- if(!EnumHelper.TryConvertEnum(methodDetailsInfo.NodeType, out var nodeType))
- {
- continue;
- }
- switch (nodeType)
- {
- case Library.NodeType.Action:
- dllControl.AddAction(methodDetailsInfo); // 添加动作类型到控件
- break;
- case Library.NodeType.Flipflop:
- dllControl.AddFlipflop(methodDetailsInfo); // 添加触发器方法到控件
- break;
- }
-
+ continue;
}
- var menu = new ContextMenu();
- menu.Items.Add(CreateMenuItem("卸载", (s,e) =>
+ switch (nodeType)
{
- if (this.EnvDecorator.RemoteDll(nodeLibrary.FullName))
- {
- DllStackPanel.Children.Remove(dllControl);
- }
- else
- {
- Console.WriteLine("卸载失败");
- }
- }));
+ case Library.NodeType.Action:
+ dllControl.AddAction(methodDetailsInfo); // 添加动作类型到控件
+ break;
+ case Library.NodeType.Flipflop:
+ dllControl.AddFlipflop(methodDetailsInfo); // 添加触发器方法到控件
+ break;
+ }
- dllControl.ContextMenu = menu;
+ }
+ var menu = new ContextMenu();
+ menu.Items.Add(CreateMenuItem("卸载", (s, e) =>
+ {
+ if (this.EnvDecorator.RemoteDll(nodeLibrary.FullName))
+ {
+ DllStackPanel.Children.Remove(dllControl);
+ }
+ else
+ {
+ Console.WriteLine("卸载失败");
+ }
+ }));
+
+ dllControl.ContextMenu = menu;
+
+ DllStackPanel.Children.Add(dllControl); // 将控件添加到界面上显示
- DllStackPanel.Children.Add(dllControl); // 将控件添加到界面上显示
- });
-
}
///
@@ -370,7 +368,6 @@ namespace Serein.Workbench
}
ConnectionType connectionType = eventArgs.ConnectionType;
- Action? action = null;
if (eventArgs.ChangeType == NodeConnectChangeEventArgs.ConnectChangeType.Create) // 添加连接
{
// 添加连接
@@ -381,59 +378,48 @@ namespace Serein.Workbench
Type = connectionType
};
if (toNode is FlipflopNodeControl flipflopControl
- && flipflopControl?.ViewModel?.Node is NodeModelBase nodeModel) // 某个节点连接到了触发器,尝试从全局触发器视图中移除该触发器
+ && flipflopControl?.ViewModel?.NodeModel is NodeModelBase nodeModel) // 某个节点连接到了触发器,尝试从全局触发器视图中移除该触发器
{
NodeTreeViewer.RemoteGlobalFlipFlop(nodeModel); // 从全局触发器树树视图中移除
}
- action = () => {
- BsControl.Draw(FlowChartCanvas, connection); // 添加贝塞尔曲线显示
- ConfigureLineContextMenu(connection); // 设置连接右键事件
- Connections.Add(connection);
- EndConnection();
- connection.Refresh();
- //UpdateConnections(fromNode);
- // connection.ArrowPath?.InvalidateVisual();
- // connection.BezierPath?.InvalidateVisual();
- };
-
+ BsControl.Draw(FlowChartCanvas, connection); // 添加贝塞尔曲线显示
+ ConfigureLineContextMenu(connection); // 设置连接右键事件
+ Connections.Add(connection);
+ EndConnection();
+ connection.Refresh();
+ //UpdateConnections(fromNode);
+ // connection.ArrowPath?.InvalidateVisual();
+ // connection.BezierPath?.InvalidateVisual();
}
else if (eventArgs.ChangeType == NodeConnectChangeEventArgs.ConnectChangeType.Remote) // 移除连接
{
// 需要移除连接
- var removeConnections = Connections.Where(c => c.Start.ViewModel.Node.Guid.Equals(fromNodeGuid)
- && c.End.ViewModel.Node.Guid.Equals(toNodeGuid))
+ var removeConnections = Connections.Where(c => c.Start.ViewModel.NodeModel.Guid.Equals(fromNodeGuid)
+ && c.End.ViewModel.NodeModel.Guid.Equals(toNodeGuid))
.ToList();
-
- action = () =>
+
+ foreach (var connection in removeConnections)
{
- foreach (var connection in removeConnections)
- {
- connection.RemoveFromCanvas();
- Connections.Remove(connection);
- JudgmentFlipFlopNode(connection.End); // 连接关系变更时判断
- }
- };
+ connection.RemoveFromCanvas();
+ Connections.Remove(connection);
+ JudgmentFlipFlopNode(connection.End); // 连接关系变更时判断
+ }
}
- this.Dispatcher.Invoke(() =>
- {
- action?.Invoke();
- });
-
-
+
}
///
/// 节点移除事件
///
///
- private void FlowEnvironment_NodeRemoteEvent(NodeRemoteEventArgs eventArgs)
+ private void FlowEnvironment_NodeRemoteEvent(NodeRemoveEventArgs eventArgs)
{
var nodeGuid = eventArgs.NodeGuid;
if (!TryGetControl(nodeGuid, out var nodeControl))
@@ -449,24 +435,18 @@ namespace Serein.Workbench
selectNodeControls.Remove(nodeControl);
}
}
- #region 节点树视图
-
- #endregion
- this.Dispatcher.Invoke(() =>
+ if (nodeControl is FlipflopNodeControl flipflopControl) // 判断是否为触发器
{
- if (nodeControl is FlipflopNodeControl flipflopControl) // 判断是否为触发器
+ var node = flipflopControl?.ViewModel?.NodeModel;
+ if (node is not null)
{
- var node = flipflopControl?.ViewModel?.Node;
- if (node is not null)
- {
- NodeTreeViewer.RemoteGlobalFlipFlop(node); // 从全局触发器树树视图中移除
- }
+ NodeTreeViewer.RemoteGlobalFlipFlop(node); // 从全局触发器树树视图中移除
}
+ }
- FlowChartCanvas.Children.Remove(nodeControl);
- NodeControls.Remove(nodeControl.ViewModel.Node.Guid);
- });
+ FlowChartCanvas.Children.Remove(nodeControl);
+ NodeControls.Remove(nodeControl.ViewModel.NodeModel.Guid);
}
///
@@ -476,61 +456,57 @@ namespace Serein.Workbench
///
private void FlowEnvironment_NodeCreateEvent(NodeCreateEventArgs eventArgs)
{
- this.Dispatcher.Invoke(() =>
+ if (eventArgs.NodeModel is not NodeModelBase nodeModelBase)
{
- if (eventArgs.NodeModel is not NodeModelBase nodeModelBase)
+ return;
+ }
+
+ // MethodDetails methodDetailss = eventArgs.MethodDetailss;
+ PositionOfUI position = eventArgs.Position;
+
+ // 创建对应控件
+ NodeControlBase? nodeControl = nodeModelBase.ControlType switch
+ {
+ NodeControlType.Action => CreateNodeControl(nodeModelBase), //typeof(ActionNodeControl),
+ NodeControlType.Flipflop => CreateNodeControl(nodeModelBase),
+ NodeControlType.ExpCondition => CreateNodeControl(nodeModelBase),
+ NodeControlType.ExpOp => CreateNodeControl(nodeModelBase),
+ NodeControlType.ConditionRegion => CreateNodeControl(nodeModelBase),
+ _ => null,
+ };
+ if (nodeControl is null)
+ {
+ return;
+ }
+ NodeControls.TryAdd(nodeModelBase.Guid, nodeControl);
+ if (eventArgs.IsAddInRegion && NodeControls.TryGetValue(eventArgs.RegeionGuid, out NodeControlBase? regionControl))
+ {
+ if (regionControl is not null)
{
- return;
+ TryPlaceNodeInRegion(regionControl, nodeControl);
}
-
- // MethodDetails methodDetailss = eventArgs.MethodDetailss;
- PositionOfUI position = eventArgs.Position;
-
- // 创建对应控件
- NodeControlBase? nodeControl = nodeModelBase.ControlType switch
+ return;
+ }
+ else
+ {
+ if (!TryPlaceNodeInRegion(nodeControl, position)) // 将节点放置在区域中
{
- NodeControlType.Action => CreateNodeControl(nodeModelBase), //typeof(ActionNodeControl),
- NodeControlType.Flipflop => CreateNodeControl(nodeModelBase),
- NodeControlType.ExpCondition => CreateNodeControl(nodeModelBase),
- NodeControlType.ExpOp => CreateNodeControl(nodeModelBase),
- NodeControlType.ConditionRegion => CreateNodeControl(nodeModelBase),
- _ => null,
- };
- if (nodeControl is null)
- {
- return;
+ PlaceNodeOnCanvas(nodeControl, position.X, position.Y); // 将节点放置在画布上
}
- NodeControls.TryAdd(nodeModelBase.Guid, nodeControl);
- if (eventArgs.IsAddInRegion && NodeControls.TryGetValue(eventArgs.RegeionGuid, out NodeControlBase? regionControl))
+ }
+
+
+ #region 节点树视图
+ if (nodeModelBase.ControlType == NodeControlType.Flipflop)
+ {
+ var node = nodeControl?.ViewModel?.NodeModel;
+ if (node is not null)
{
- if (regionControl is not null)
- {
- TryPlaceNodeInRegion(regionControl, nodeControl);
- }
- return;
- }
- else
- {
- if (!TryPlaceNodeInRegion(nodeControl, position)) // 将节点放置在区域中
- {
- PlaceNodeOnCanvas(nodeControl, position.X, position.Y); // 将节点放置在画布上
- }
+ NodeTreeViewer.AddGlobalFlipFlop(EnvDecorator, node); // 新增的触发器节点添加到全局触发器
}
+ }
+ #endregion
-
- #region 节点树视图
- if (nodeModelBase.ControlType == NodeControlType.Flipflop)
- {
- var node = nodeControl?.ViewModel?.Node;
- if(node is not null)
- {
- NodeTreeViewer.AddGlobalFlipFlop(EnvDecorator, node); // 新增的触发器节点添加到全局触发器
- }
- }
- #endregion
-
-
- });
}
///
@@ -540,26 +516,23 @@ namespace Serein.Workbench
///
private void FlowEnvironment_StartNodeChangeEvent(StartNodeChangeEventArgs eventArgs)
{
- this.Dispatcher.Invoke(() =>
+ string oldNodeGuid = eventArgs.OldNodeGuid;
+ string newNodeGuid = eventArgs.NewNodeGuid;
+ if (!TryGetControl(newNodeGuid, out var newStartNodeControl)) return;
+ if (!string.IsNullOrEmpty(oldNodeGuid))
{
- string oldNodeGuid = eventArgs.OldNodeGuid;
- string newNodeGuid = eventArgs.NewNodeGuid;
- if (!TryGetControl(newNodeGuid, out var newStartNodeControl)) return;
- if (!string.IsNullOrEmpty(oldNodeGuid))
- {
- if (!TryGetControl(oldNodeGuid, out var oldStartNodeControl)) return;
- oldStartNodeControl.BorderBrush = Brushes.Black;
- oldStartNodeControl.BorderThickness = new Thickness(0);
- }
+ if (!TryGetControl(oldNodeGuid, out var oldStartNodeControl)) return;
+ oldStartNodeControl.BorderBrush = Brushes.Black;
+ oldStartNodeControl.BorderThickness = new Thickness(0);
+ }
- newStartNodeControl.BorderBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#04FC10"));
- newStartNodeControl.BorderThickness = new Thickness(2);
- var node = newStartNodeControl?.ViewModel?.Node;
- if (node is not null)
- {
- NodeTreeViewer.LoadNodeTreeOfStartNode(EnvDecorator, node);
- }
- });
+ newStartNodeControl.BorderBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#04FC10"));
+ newStartNodeControl.BorderThickness = new Thickness(2);
+ var node = newStartNodeControl?.ViewModel?.NodeModel;
+ if (node is not null)
+ {
+ NodeTreeViewer.LoadNodeTreeOfStartNode(EnvDecorator, node);
+ }
}
@@ -578,24 +551,21 @@ namespace Serein.Workbench
};
//NodeControlBase nodeControl = GuidToControl(nodeGuid);
- ViewObjectViewer.Dispatcher.Invoke(() => {
- if (ViewObjectViewer.MonitorObj is null) // 如果没有加载过对象
+ if (ViewObjectViewer.MonitorObj is null) // 如果没有加载过对象
+ {
+ ViewObjectViewer.LoadObjectInformation(monitorKey, eventArgs.NewData); // 加载对象 ViewObjectViewerControl.MonitorType.Obj
+ }
+ else
+ {
+ if (monitorKey.Equals(ViewObjectViewer.MonitorKey)) // 相同对象
{
- ViewObjectViewer.LoadObjectInformation(monitorKey, eventArgs.NewData); // 加载对象 ViewObjectViewerControl.MonitorType.Obj
- }
+ ViewObjectViewer.RefreshObjectTree(eventArgs.NewData); // 刷新
+ }
else
{
- if (monitorKey.Equals(ViewObjectViewer.MonitorKey)) // 相同对象
- {
- ViewObjectViewer.RefreshObjectTree(eventArgs.NewData); // 刷新
- }
- else
- {
- ViewObjectViewer.LoadObjectInformation(monitorKey, eventArgs.NewData); // 加载对象
- }
+ ViewObjectViewer.LoadObjectInformation(monitorKey, eventArgs.NewData); // 加载对象
}
- });
-
+ }
}
@@ -607,35 +577,31 @@ namespace Serein.Workbench
{
string nodeGuid = eventArgs.NodeGuid;
if (!TryGetControl(nodeGuid, out var nodeControl)) return;
-
- this.Dispatcher.Invoke(() =>
+ if (eventArgs.Class == InterruptClass.None)
{
- if (eventArgs.Class == InterruptClass.None)
- {
- nodeControl.ViewModel.IsInterrupt = false;
+ nodeControl.ViewModel.IsInterrupt = false;
- }
- else
- {
- nodeControl.ViewModel.IsInterrupt = true;
- }
+ }
+ else
+ {
+ nodeControl.ViewModel.IsInterrupt = true;
+ }
- foreach (var menuItem in nodeControl.ContextMenu.Items)
+ foreach (var menuItem in nodeControl.ContextMenu.Items)
+ {
+ if (menuItem is MenuItem menu)
{
- if (menuItem is MenuItem menu)
+ if ("取消中断".Equals(menu.Header))
{
- if ("取消中断".Equals(menu.Header))
- {
- menu.Header = "在此中断";
- }
- else if ("在此中断".Equals(menu.Header))
- {
- menu.Header = "取消中断";
- }
-
+ menu.Header = "在此中断";
}
+ else if ("在此中断".Equals(menu.Header))
+ {
+ menu.Header = "取消中断";
+ }
+
}
- });
+ }
}
@@ -665,10 +631,8 @@ namespace Serein.Workbench
///
private void FlowEnvironment_OnIOCMembersChanged(IOCMembersChangedEventArgs eventArgs)
{
- this.Dispatcher.Invoke(() =>
- {
- IOCObjectViewer.AddDependenciesInstance(eventArgs.Key, eventArgs.Instance);
- });
+ IOCObjectViewer.AddDependenciesInstance(eventArgs.Key, eventArgs.Instance);
+
}
///
@@ -678,56 +642,52 @@ namespace Serein.Workbench
///
private void FlowEnvironment_OnNodeLocate(NodeLocatedEventArgs eventArgs)
{
- this.Dispatcher.Invoke(() =>
- {
- if (!TryGetControl(eventArgs.NodeGuid, out var nodeControl)) return;
- //scaleTransform.ScaleX = 1;
- //scaleTransform.ScaleY = 1;
- // 获取控件在 FlowChartCanvas 上的相对位置
- Rect controlBounds = VisualTreeHelper.GetDescendantBounds(nodeControl);
- Point controlPosition = nodeControl.TransformToAncestor(FlowChartCanvas).Transform(new Point(0, 0));
+ if (!TryGetControl(eventArgs.NodeGuid, out var nodeControl)) return;
+ //scaleTransform.ScaleX = 1;
+ //scaleTransform.ScaleY = 1;
+ // 获取控件在 FlowChartCanvas 上的相对位置
+ Rect controlBounds = VisualTreeHelper.GetDescendantBounds(nodeControl);
+ Point controlPosition = nodeControl.TransformToAncestor(FlowChartCanvas).Transform(new Point(0, 0));
- // 获取控件在画布上的中心点
- double controlCenterX = controlPosition.X + controlBounds.Width / 2;
- double controlCenterY = controlPosition.Y + controlBounds.Height / 2;
+ // 获取控件在画布上的中心点
+ double controlCenterX = controlPosition.X + controlBounds.Width / 2;
+ double controlCenterY = controlPosition.Y + controlBounds.Height / 2;
- // 考虑缩放因素计算目标位置的中心点
- double scaledCenterX = controlCenterX * scaleTransform.ScaleX;
- double scaledCenterY = controlCenterY * scaleTransform.ScaleY;
+ // 考虑缩放因素计算目标位置的中心点
+ double scaledCenterX = controlCenterX * scaleTransform.ScaleX;
+ double scaledCenterY = controlCenterY * scaleTransform.ScaleY;
- //// 计算画布的可视区域大小
- //double visibleAreaLeft = scaledCenterX;
- //double visibleAreaTop = scaledCenterY;
- //double visibleAreaRight = scaledCenterX + FlowChartStackGrid.ActualWidth;
- //double visibleAreaBottom = scaledCenterY + FlowChartStackGrid.ActualHeight;
- //// 检查控件中心点是否在可视区域内
- //bool isInView = scaledCenterX >= visibleAreaLeft && scaledCenterX <= visibleAreaRight &&
- // scaledCenterY >= visibleAreaTop && scaledCenterY <= visibleAreaBottom;
+ //// 计算画布的可视区域大小
+ //double visibleAreaLeft = scaledCenterX;
+ //double visibleAreaTop = scaledCenterY;
+ //double visibleAreaRight = scaledCenterX + FlowChartStackGrid.ActualWidth;
+ //double visibleAreaBottom = scaledCenterY + FlowChartStackGrid.ActualHeight;
+ //// 检查控件中心点是否在可视区域内
+ //bool isInView = scaledCenterX >= visibleAreaLeft && scaledCenterX <= visibleAreaRight &&
+ // scaledCenterY >= visibleAreaTop && scaledCenterY <= visibleAreaBottom;
- //Console.WriteLine($"isInView :{isInView}");
+ //Console.WriteLine($"isInView :{isInView}");
- //if (!isInView)
- //{
- //}
- // 计算平移偏移量,使得控件在可视区域的中心
- double translateX = scaledCenterX - FlowChartStackGrid.ActualWidth / 2;
- double translateY = scaledCenterY - FlowChartStackGrid.ActualHeight / 2;
+ //if (!isInView)
+ //{
+ //}
+ // 计算平移偏移量,使得控件在可视区域的中心
+ double translateX = scaledCenterX - FlowChartStackGrid.ActualWidth / 2;
+ double translateY = scaledCenterY - FlowChartStackGrid.ActualHeight / 2;
- var translate = this.translateTransform;
- // 应用平移变换
- translate.X = 0;
- translate.Y = 0;
- translate.X -= translateX;
- translate.Y -= translateY;
+ var translate = this.translateTransform;
+ // 应用平移变换
+ translate.X = 0;
+ translate.Y = 0;
+ translate.X -= translateX;
+ translate.Y -= translateY;
- // 设置RenderTransform以实现移动效果
- TranslateTransform translateTransform = new TranslateTransform();
- nodeControl.RenderTransform = translateTransform;
- ElasticAnimation(nodeControl, translateTransform, 4, 1, 0.5);
+ // 设置RenderTransform以实现移动效果
+ TranslateTransform translateTransform = new TranslateTransform();
+ nodeControl.RenderTransform = translateTransform;
+ ElasticAnimation(nodeControl, translateTransform, 4, 1, 0.5);
- });
-
}
///
@@ -775,23 +735,20 @@ namespace Serein.Workbench
var newLeft = eventArgs.X;
var newTop = eventArgs.Y;
- this.Dispatcher.Invoke(() => {
- // 限制控件不超出FlowChartCanvas的边界
- if (newLeft >= 0 && newLeft + nodeControl.ActualWidth <= FlowChartCanvas.ActualWidth)
- {
- Canvas.SetLeft(nodeControl, newLeft);
+ // 限制控件不超出FlowChartCanvas的边界
+ if (newLeft >= 0 && newLeft + nodeControl.ActualWidth <= FlowChartCanvas.ActualWidth)
+ {
+ Canvas.SetLeft(nodeControl, newLeft);
- }
- if (newTop >= 0 && newTop + nodeControl.ActualHeight <= FlowChartCanvas.ActualHeight)
- {
- Canvas.SetTop(nodeControl, newTop);
+ }
+ if (newTop >= 0 && newTop + nodeControl.ActualHeight <= FlowChartCanvas.ActualHeight)
+ {
+ Canvas.SetTop(nodeControl, newTop);
- }
- UpdateConnections(nodeControl);
- });
+ }
+ UpdateConnections(nodeControl);
-
//Canvas.SetLeft(nodeControl,);
//Canvas.SetTop(nodeControl, );
}
@@ -892,16 +849,13 @@ namespace Serein.Workbench
///
private void PlaceNodeOnCanvas(NodeControlBase nodeControl, double x, double y)
{
- FlowChartCanvas.Dispatcher.Invoke(() =>
- {
- // 添加控件到画布
- FlowChartCanvas.Children.Add(nodeControl);
- Canvas.SetLeft(nodeControl, x);
- Canvas.SetTop(nodeControl, y);
-
- ConfigureContextMenu(nodeControl); // 配置节点右键菜单
- ConfigureNodeEvents(nodeControl); // 配置节点事件
- });
+ // 添加控件到画布
+ FlowChartCanvas.Children.Add(nodeControl);
+ Canvas.SetLeft(nodeControl, x);
+ Canvas.SetTop(nodeControl, y);
+
+ ConfigureContextMenu(nodeControl); // 配置节点右键菜单
+ ConfigureNodeEvents(nodeControl); // 配置节点事件
}
///
@@ -957,10 +911,10 @@ namespace Serein.Workbench
{
var contextMenu = new ContextMenu();
- var nodeGuid = nodeControl.ViewModel?.Node?.Guid;
+ var nodeGuid = nodeControl.ViewModel?.NodeModel?.Guid;
#region 触发器节点
- if(nodeControl.ViewModel?.Node.ControlType == NodeControlType.Flipflop)
+ if(nodeControl.ViewModel?.NodeModel.ControlType == NodeControlType.Flipflop)
{
contextMenu.Items.Add(CreateMenuItem("启动触发器", (s, e) =>
{
@@ -984,7 +938,7 @@ namespace Serein.Workbench
#endregion
- if (nodeControl.ViewModel?.Node?.MethodDetails?.ReturnType is Type returnType && returnType != typeof(void))
+ if (nodeControl.ViewModel?.NodeModel?.MethodDetails?.ReturnType is Type returnType && returnType != typeof(void))
{
contextMenu.Items.Add(CreateMenuItem("查看返回类型", (s, e) =>
{
@@ -998,7 +952,7 @@ namespace Serein.Workbench
{
if ((s is MenuItem menuItem) && menuItem is not null)
{
- if (nodeControl?.ViewModel?.Node?.DebugSetting?.InterruptClass == InterruptClass.None)
+ if (nodeControl?.ViewModel?.NodeModel?.DebugSetting?.InterruptClass == InterruptClass.None)
{
await EnvDecorator.SetNodeInterruptAsync(nodeGuid, InterruptClass.Branch);
@@ -1017,7 +971,7 @@ namespace Serein.Workbench
contextMenu.Items.Add(CreateMenuItem("设为起点", (s, e) => EnvDecorator.SetStartNode(nodeGuid)));
- contextMenu.Items.Add(CreateMenuItem("删除", (s, e) => EnvDecorator.RemoveNode(nodeGuid)));
+ contextMenu.Items.Add(CreateMenuItem("删除", (s, e) => EnvDecorator.RemoveNodeAsync(nodeGuid)));
contextMenu.Items.Add(CreateMenuItem("添加 真分支", (s, e) => StartConnection(nodeControl, ConnectionType.IsSucceed)));
contextMenu.Items.Add(CreateMenuItem("添加 假分支", (s, e) => StartConnection(nodeControl, ConnectionType.IsFail)));
@@ -1092,9 +1046,9 @@ namespace Serein.Workbench
return;
}
// 获取起始节点与终止节点,消除映射关系
- var fromNodeGuid = connectionToRemove.Start.ViewModel.Node.Guid;
- var toNodeGuid = connectionToRemove.End.ViewModel.Node.Guid;
- EnvDecorator.RemoveConnect(fromNodeGuid, toNodeGuid, connection.Type);
+ var fromNodeGuid = connectionToRemove.Start.ViewModel.NodeModel.Guid;
+ var toNodeGuid = connectionToRemove.End.ViewModel.NodeModel.Guid;
+ EnvDecorator.RemoveConnectAsync(fromNodeGuid, toNodeGuid, connection.Type);
}
///
@@ -1293,7 +1247,7 @@ namespace Serein.Workbench
if (hitTestResult != null && hitTestResult.VisualHit is UIElement hitElement)
{
// 准备放置条件表达式控件
- if (nodeControl.ViewModel.Node.ControlType == NodeControlType.ExpCondition)
+ if (nodeControl.ViewModel.NodeModel.ControlType == NodeControlType.ExpCondition)
{
ConditionRegionControl? conditionRegion = GetParentOfType(hitElement);
if (conditionRegion is not null)
@@ -1317,7 +1271,7 @@ namespace Serein.Workbench
private void TryPlaceNodeInRegion(NodeControlBase regionControl, NodeControlBase nodeControl)
{
// 准备放置条件表达式控件
- if (nodeControl.ViewModel.Node.ControlType == NodeControlType.ExpCondition)
+ if (nodeControl.ViewModel.NodeModel.ControlType == NodeControlType.ExpCondition)
{
ConditionRegionControl? conditionRegion = regionControl as ConditionRegionControl;
if (conditionRegion is not null)
@@ -1355,7 +1309,7 @@ namespace Serein.Workbench
if(sender is NodeControlBase nodeControl)
{
ChangeViewerObjOfNode(nodeControl);
- if (nodeControl?.ViewModel?.Node?.MethodDetails?.IsProtectionParameter == true) return;
+ if (nodeControl?.ViewModel?.NodeModel?.MethodDetails?.IsProtectionParameter == true) return;
IsControlDragging = true;
startControlDragPoint = e.GetPosition(FlowChartCanvas); // 记录鼠标按下时的位置
((UIElement)sender).CaptureMouse(); // 捕获鼠标
@@ -1395,7 +1349,7 @@ namespace Serein.Workbench
var newLeft = oldLeft + deltaX;
var newTop = oldTop + deltaY;
- this.EnvDecorator.MoveNode(nodeControlMain.ViewModel.Node.Guid, newLeft, newTop); // 移动节点
+ this.EnvDecorator.MoveNode(nodeControlMain.ViewModel.NodeModel.Guid, newLeft, newTop); // 移动节点
// 计算控件实际移动的距离
var actualDeltaX = newLeft - oldLeft;
@@ -1408,7 +1362,7 @@ namespace Serein.Workbench
{
var otherNewLeft = Canvas.GetLeft(nodeControl) + actualDeltaX;
var otherNewTop = Canvas.GetTop(nodeControl) + actualDeltaY;
- this.EnvDecorator.MoveNode(nodeControl.ViewModel.Node.Guid, otherNewLeft, otherNewTop); // 移动节点
+ this.EnvDecorator.MoveNode(nodeControl.ViewModel.NodeModel.Guid, otherNewLeft, otherNewTop); // 移动节点
}
}
@@ -1428,7 +1382,7 @@ namespace Serein.Workbench
double deltaY = currentPosition.Y - startControlDragPoint.Y; // 计算Y轴方向的偏移量
double newLeft = Canvas.GetLeft(nodeControl) + deltaX; // 新的左边距
double newTop = Canvas.GetTop(nodeControl) + deltaY; // 新的上边距
- this.EnvDecorator.MoveNode(nodeControl.ViewModel.Node.Guid, newLeft, newTop); // 移动节点
+ this.EnvDecorator.MoveNode(nodeControl.ViewModel.NodeModel.Guid, newLeft, newTop); // 移动节点
UpdateConnections(nodeControl);
}
startControlDragPoint = currentPosition; // 更新起始点位置
@@ -1440,7 +1394,7 @@ namespace Serein.Workbench
private void ChangeViewerObjOfNode(NodeControlBase nodeControl)
{
- var node = nodeControl.ViewModel.Node;
+ var node = nodeControl.ViewModel.NodeModel;
//if (node is not null && (node.MethodDetails is null || node.MethodDetails.ReturnType != typeof(void))
if (node is not null && node.MethodDetails?.ReturnType != typeof(void))
{
@@ -1493,8 +1447,8 @@ namespace Serein.Workbench
if (IsConnecting)
{
- var formNodeGuid = startConnectNodeControl?.ViewModel.Node.Guid;
- var toNodeGuid = (sender as NodeControlBase)?.ViewModel.Node.Guid;
+ var formNodeGuid = startConnectNodeControl?.ViewModel.NodeModel.Guid;
+ var toNodeGuid = (sender as NodeControlBase)?.ViewModel.NodeModel.Guid;
if (string.IsNullOrEmpty(formNodeGuid) || string.IsNullOrEmpty(toNodeGuid))
{
return;
@@ -1914,10 +1868,10 @@ namespace Serein.Workbench
{
foreach (var node in selectNodeControls.ToArray())
{
- var guid = node?.ViewModel?.Node?.Guid;
+ var guid = node?.ViewModel?.NodeModel?.Guid;
if (!string.IsNullOrEmpty(guid))
{
- EnvDecorator.RemoveNode(guid);
+ EnvDecorator.RemoveNodeAsync(guid);
}
}
}
@@ -1943,7 +1897,7 @@ namespace Serein.Workbench
//Console.WriteLine($"一共选取了{selectNodeControls.Count}个控件");
foreach (var node in selectNodeControls)
{
- node.ViewModel.Selected();
+ node.ViewModel.IsSelect =true;
// node.ViewModel.CancelSelect();
node.BorderBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#FFC700"));
node.BorderThickness = new Thickness(4);
@@ -1954,10 +1908,10 @@ namespace Serein.Workbench
IsSelectControl = false;
foreach (var nodeControl in selectNodeControls)
{
- nodeControl.ViewModel.CancelSelect();
+ nodeControl.ViewModel.IsSelect = false;
nodeControl.BorderBrush = Brushes.Black;
nodeControl.BorderThickness = new Thickness(0);
- if (nodeControl.ViewModel.Node.IsStart)
+ if (nodeControl.ViewModel.NodeModel.IsStart)
{
nodeControl.BorderBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#04FC10"));
nodeControl.BorderThickness = new Thickness(2);
@@ -2364,7 +2318,7 @@ namespace Serein.Workbench
private void JudgmentFlipFlopNode(NodeControlBase nodeControl)
{
if (nodeControl is FlipflopNodeControl flipflopControl
- && flipflopControl?.ViewModel?.Node is NodeModelBase nodeModel) // 判断是否为触发器
+ && flipflopControl?.ViewModel?.NodeModel is NodeModelBase nodeModel) // 判断是否为触发器
{
int count = 0;
foreach (var ct in NodeStaticConfig.ConnectionTypes)
@@ -2449,7 +2403,7 @@ namespace Serein.Workbench
}
else
{
- await this.EnvDecorator.StartAsyncInSelectNode(selectNodeControls[0].ViewModel.Node.Guid);
+ await this.EnvDecorator.StartAsyncInSelectNode(selectNodeControls[0].ViewModel.NodeModel.Guid);
}
}
diff --git a/WorkBench/Node/NodeControlViewModelBase.cs b/WorkBench/Node/NodeControlViewModelBase.cs
index 4c61e17..00890e3 100644
--- a/WorkBench/Node/NodeControlViewModelBase.cs
+++ b/WorkBench/Node/NodeControlViewModelBase.cs
@@ -6,16 +6,18 @@ namespace Serein.Workbench.Node.ViewModel
{
public abstract class NodeControlViewModelBase : INotifyPropertyChanged
{
- public NodeControlViewModelBase(NodeModelBase node)
+ public NodeControlViewModelBase(NodeModelBase nodeModel)
{
- Node = node;
- MethodDetails = Node.MethodDetails;
+ NodeModel = nodeModel;
+ MethodDetails = NodeModel.MethodDetails;
+
+ // 订阅来自 NodeModel 的通知事件
}
///
/// 对应的节点实体类
///
- internal NodeModelBase Node { get; }
+ internal NodeModelBase NodeModel { get; }
private bool isSelect;
@@ -37,12 +39,12 @@ namespace Serein.Workbench.Node.ViewModel
///
public NodeDebugSetting DebugSetting
{
- get => Node.DebugSetting;
+ get => NodeModel.DebugSetting;
set
{
if (value != null)
{
- Node.DebugSetting = value;
+ NodeModel.DebugSetting = value;
OnPropertyChanged();
}
}
@@ -53,12 +55,12 @@ namespace Serein.Workbench.Node.ViewModel
///
public MethodDetails MethodDetails
{
- get => Node.MethodDetails;
+ get => NodeModel.MethodDetails;
set
{
if(value != null)
{
- Node.MethodDetails = value;
+ NodeModel.MethodDetails = value;
OnPropertyChanged();
}
}
@@ -78,35 +80,12 @@ namespace Serein.Workbench.Node.ViewModel
}
}
- ///
- ///
- ///
public event PropertyChangedEventHandler? PropertyChanged;
- ///
- ///
- ///
- ///
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
- ///
- ///
- ///
- public void Selected()
- {
- IsSelect = true;
- }
- ///
- ///
- ///
- public void CancelSelect()
- {
- IsSelect = false;
- }
-
-
}
}
diff --git a/WorkBench/Node/View/ConditionRegionControl.xaml.cs b/WorkBench/Node/View/ConditionRegionControl.xaml.cs
index 24f8e03..d31c69b 100644
--- a/WorkBench/Node/View/ConditionRegionControl.xaml.cs
+++ b/WorkBench/Node/View/ConditionRegionControl.xaml.cs
@@ -34,7 +34,7 @@ namespace Serein.Workbench.Node.View
///
public void AddCondition(NodeControlBase node)
{
- ((CompositeConditionNode)ViewModel.Node).AddNode((SingleConditionNode)node.ViewModel.Node);
+ ((CompositeConditionNode)ViewModel.NodeModel).AddNode((SingleConditionNode)node.ViewModel.NodeModel);
this.Width += node.Width;
this.Height += node.Height;