优化了节点连接

This commit is contained in:
fengjiayi
2024-10-28 15:21:08 +08:00
parent f20cfb755c
commit 561b6d764f
28 changed files with 295 additions and 165 deletions

View File

@@ -517,13 +517,12 @@ namespace Serein.Library.Api
/// <para>表示是否正在控制远程</para>
/// <para>Local control remote env</para>
/// </summary>
bool IsLcR { get; }
bool IsControlRemoteEnv { get; }
/// <summary>
/// <para>表示是否受到远程控制</para>
/// <para>Remote control local env</para>
/// 是否运行在控制台上
/// </summary>
bool IsRcL { get; }
// bool IsRuningOnConsole { get; }
/// <summary>
/// 流程运行状态

View File

@@ -2,6 +2,7 @@
using Serein.Library.Utils;
using System;
using System.Linq;
using System.Text;
namespace Serein.Library
{
@@ -12,7 +13,7 @@ namespace Serein.Library
[NodeProperty(ValuePath = NodeValuePath.Method)]
public partial class MethodDetails
{
private readonly IFlowEnvironment env;
// private readonly IFlowEnvironment env;
/// <summary>
/// 对应的节点
@@ -58,10 +59,10 @@ namespace Serein.Library
/// <summary>
/// 方法说明
/// 方法别名
/// </summary>
[PropertyInfo]
private string _methodTips;
private string _methodAnotherName;
/// <summary>
@@ -109,7 +110,7 @@ namespace Serein.Library
throw new ArgumentException("无效的节点类型");
}
MethodName = Info.MethodName;
MethodTips = Info.MethodTips;
MethodAnotherName = Info.MethodAnotherName;
MethodDynamicType = nodeType;
ReturnType = Type.GetType(Info.ReturnTypeFullName);
ParameterDetailss = Info.ParameterDetailsInfos.Select(pinfo => new ParameterDetails(pinfo)).ToArray();
@@ -121,10 +122,12 @@ namespace Serein.Library
/// <returns></returns>
public MethodDetailsInfo ToInfo()
{
return new MethodDetailsInfo
{
MethodName = MethodName,
MethodTips = MethodTips,
MethodAnotherName = MethodAnotherName,
NodeType = MethodDynamicType.ToString(),
ParameterDetailsInfos = ParameterDetailss.Select(p => p.ToInfo()).ToArray(),
ReturnTypeFullName = ReturnType.FullName,
@@ -142,7 +145,7 @@ namespace Serein.Library
ActingInstance = this.ActingInstance,
ActingInstanceType = this.ActingInstanceType,
MethodDynamicType = this.MethodDynamicType,
MethodTips = this.MethodTips,
MethodAnotherName = this.MethodAnotherName,
ReturnType = this.ReturnType,
MethodName = this.MethodName,
MethodLockName = this.MethodLockName,
@@ -152,9 +155,23 @@ namespace Serein.Library
return md;
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.AppendLine($"方法别名:{this.MethodAnotherName}");
sb.AppendLine($"方法名称:{this.MethodName}");
sb.AppendLine($"需要实例:{this.ActingInstanceType.FullName}");
sb.AppendLine($"");
sb.AppendLine($"入参参数信息:");
foreach (var arg in this.ParameterDetailss)
{
sb.AppendLine($" {arg.ToString()}");
}
sb.AppendLine($"");
sb.AppendLine($"返回值信息:");
sb.AppendLine($" {this.ReturnType.FullName}");
return sb.ToString();
}
///// <summary>
///// 每个节点有独自的MethodDetails实例

View File

@@ -29,7 +29,7 @@ namespace Serein.Library
/// <summary>
/// 方法说明
/// </summary>
public string MethodTips { get; set; }
public string MethodAnotherName { get; set; }
/// <summary>
/// 参数内容

View File

@@ -12,12 +12,6 @@ namespace Serein.Library
[NodeProperty(ValuePath = NodeValuePath.DebugSetting)]
public partial class NodeDebugSetting
{
/// <summary>
/// 对应的节点
/// </summary>
[PropertyInfo(IsProtection = true)]
private NodeModelBase _nodeModel;
/// <summary>
/// 创建属于某个节点的调试设置
/// </summary>
@@ -26,6 +20,13 @@ namespace Serein.Library
{
NodeModel = nodeModel;
}
/// <summary>
/// 对应的节点
/// </summary>
[PropertyInfo(IsProtection = true)]
private NodeModelBase _nodeModel;
/// <summary>
/// 是否使能
/// </summary>
@@ -41,11 +42,9 @@ namespace Serein.Library
/// <summary>
/// 中断级别,暂时停止继续执行后继分支。
/// </summary>
[PropertyInfo(IsNotification = true, CustomCode = "NodeModel?.Env?.SetNodeInterruptAsync(NodeModel?.Guid, value);")]
[PropertyInfo(IsNotification = true)] // CustomCode = "NodeModel?.Env?.SetNodeInterruptAsync(NodeModel?.Guid, value);"
private bool _isInterrupt = false;
//private const string MyInteruptCode = "NodeModel?.Env?.SetNodeInterruptAsync(NodeModel?.Guid, value);"; // 添加到中断的自定义代码
/// <summary>
/// 取消中断的回调函数
/// </summary>

View File

@@ -81,7 +81,6 @@ namespace Serein.Library
[PropertyInfo]
private Exception _runingException ;
}

View File

@@ -53,7 +53,7 @@ namespace Serein.Library
{
Guid = Guid,
MethodName = MethodDetails?.MethodName,
Label = DisplayName ?? "",
Label = MethodDetails?.MethodAnotherName,
Type = this.GetType().ToString(),
TrueNodes = trueNodes.ToArray(),
FalseNodes = falseNodes.ToArray(),

View File

@@ -68,7 +68,6 @@ namespace Serein.Library
[PropertyInfo]
private string _argDataSourceNodeGuid;
/// <summary>
/// 方法入参需要的类型。
/// </summary>
@@ -128,7 +127,6 @@ namespace Serein.Library
ExplicitType = Type.GetType(info.ExplicitTypeFullName);
ExplicitTypeName = info.ExplicitTypeName;
Items = info.Items;
}
/// <summary>
@@ -171,6 +169,19 @@ namespace Serein.Library
};
return pd;
}
public override string ToString()
{
if(_convertor is null)
{
return $"[{this.Index}] {this.Name} : {this.DataType.FullName}";
}
else
{
}
return $"[{this.Index}] {this.Name} : {this.ExplicitType.FullName} -> {this.DataType.FullName}";
}
}

View File

@@ -123,7 +123,10 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
catch (Exception ex)
{
Console.WriteLine($"error in ws : {ex.Message}{Environment.NewLine}json value:{jsonObject}");
return;
}
finally
{
context.Handle = true;
}
}

View File

@@ -11,7 +11,7 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
/// <summary>
/// 消息处理上下文
/// </summary>
public class WebSocketMsgContext : IDisposable
public class WebSocketMsgContext /*: IDisposable*/
{
public WebSocketMsgContext(Func<string, Task> sendAsync)
{
@@ -31,7 +31,14 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
/// <summary>
/// 标记是否已经处理,如果是,则提前退出
/// </summary>
public bool Handle { get; set; }
public bool Handle { get => _handle; set{
if(value)
{
Dispose();
_handle = value;
}
} }
public bool _handle = false;
/// <summary>
/// 消息本体JObject

View File

@@ -201,13 +201,18 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
/// </summary>
/// <param name="context">此次请求的上下文</param>
/// <returns></returns>
public async Task HandleAsync(WebSocketMsgContext context)
public void Handle(WebSocketMsgContext context)
{
foreach (var module in MyHandleModuleDict.Values)
{
await module.HandleAsync(context);
if (context.Handle)
{
return;
}
_ = module.HandleAsync(context);
}
}

View File

@@ -11,23 +11,25 @@ using System.Threading.Tasks;
namespace Serein.Library.Network.WebSocketCommunication
{
public class MsgQueueUtil
/// <summary>
/// 消息处理工具
/// </summary>
public class MsgHandleUtil
{
public ConcurrentQueue<string> Msgs = new ConcurrentQueue<string>();
private readonly Channel<string> _msgChannel;
public MsgQueueUtil()
{
_msgChannel = CreateChannel();
}
private Channel<string> CreateChannel()
/// <summary>
/// 初始化优先容器
/// </summary>
/// <param name="capacity"></param>
public MsgHandleUtil(int capacity = 100)
{
return Channel.CreateBounded<string>(new BoundedChannelOptions(100)
_msgChannel = Channel.CreateBounded<string>(new BoundedChannelOptions(capacity)
{
FullMode = BoundedChannelFullMode.Wait
});
}
/// <summary>
/// 等待消息
@@ -35,27 +37,45 @@ namespace Serein.Library.Network.WebSocketCommunication
/// <returns></returns>
public async Task<string> WaitMsgAsync()
{
var state = await _msgChannel.Reader.ReadAsync();
return state;
}
public void WriteMsg(string msg)
{
//Msgs.Enqueue(msg);
Console.WriteLine($"{DateTime.Now}{msg}{Environment.NewLine}");
_ = _msgChannel.Writer.WriteAsync(msg);
// 检查是否可以读取消息
if (await _msgChannel.Reader.WaitToReadAsync())
{
return await _msgChannel.Reader.ReadAsync();
}
return null; // 若通道关闭则返回null
}
public bool TryGetMsg(out string msg)
/// <summary>
/// 写入消息
/// </summary>
/// <param name="msg">消息内容</param>
/// <returns>是否写入成功</returns>
public async Task<bool> WriteMsgAsync(string msg)
{
return Msgs.TryDequeue(out msg);
try
{
await _msgChannel.Writer.WriteAsync(msg);
return true;
}
catch (ChannelClosedException)
{
// Channel 已关闭
return false;
}
}
/// <summary>
/// 尝试关闭通道,停止写入消息
/// </summary>
public void CloseChannel()
{
_msgChannel.Writer.Complete();
}
}
public class SocketExtension
{
/// <summary>

View File

@@ -76,7 +76,7 @@ namespace Serein.Library.Network.WebSocketCommunication
private async Task ReceiveAsync()
{
var msgQueueUtil = new MsgQueueUtil();
var msgQueueUtil = new MsgHandleUtil();
_ = Task.Run(async () =>
{
await HandleMsgAsync(_client, msgQueueUtil);
@@ -102,7 +102,7 @@ namespace Serein.Library.Network.WebSocketCommunication
} while (!result.EndOfMessage); // 判断是否已经收到完整消息
var message = receivedMessage.ToString();
msgQueueUtil.WriteMsg(message);
await msgQueueUtil.WriteMsgAsync(message);
receivedMessage.Clear(); // 清空 StringBuilder 为下一条消息做准备
// 处理收到的完整消息
if (result.MessageType == WebSocketMessageType.Close)
@@ -126,8 +126,7 @@ namespace Serein.Library.Network.WebSocketCommunication
}
public async Task HandleMsgAsync(WebSocket webSocket,
MsgQueueUtil msgQueueUtil)
public async Task HandleMsgAsync(WebSocket webSocket, MsgHandleUtil msgQueueUtil)
{
async Task sendasync(string text)
{
@@ -136,11 +135,15 @@ namespace Serein.Library.Network.WebSocketCommunication
while (true)
{
var message = await msgQueueUtil.WaitMsgAsync(); // 有消息时通知
using (var context = new WebSocketMsgContext(sendasync))
{
context.JsonObject = JObject.Parse(message);
await MsgHandleHelper.HandleAsync(context); // 处理消息
}
var context = new WebSocketMsgContext(sendasync);
context.JsonObject = JObject.Parse(message);
MsgHandleHelper.Handle(context); // 处理消息
//using (var context = new WebSocketMsgContext(sendasync))
//{
// context.JsonObject = JObject.Parse(message);
// await MsgHandleHelper.HandleAsync(context); // 处理消息
//}
//_ = Task.Run(() => {
// JObject json = JObject.Parse(message);

View File

@@ -180,7 +180,7 @@ namespace Serein.Library.Network.WebSocketCommunication
return;
}
var msgQueueUtil = new MsgQueueUtil();
var msgQueueUtil = new MsgHandleUtil();
_ = Task.Run(async () =>
{
await HandleMsgAsync(webSocket,msgQueueUtil, authorizedHelper);
@@ -219,7 +219,7 @@ namespace Serein.Library.Network.WebSocketCommunication
// 完整消息已经接收到,准备处理
var message = receivedMessage.ToString(); // 获取消息文本
receivedMessage.Clear(); // 清空 StringBuilder 为下一条消息做准备
msgQueueUtil.WriteMsg(message); // 处理消息
await msgQueueUtil.WriteMsgAsync(message); // 处理消息
}
catch (Exception ex)
{
@@ -231,7 +231,7 @@ namespace Serein.Library.Network.WebSocketCommunication
public async Task HandleMsgAsync(WebSocket webSocket,
MsgQueueUtil msgQueueUtil,
MsgHandleUtil msgQueueUtil,
WebSocketAuthorizedHelper authorizedHelper)
{
async Task sendasync(string text)
@@ -254,18 +254,21 @@ namespace Serein.Library.Network.WebSocketCommunication
return;
}
}
var context = new WebSocketMsgContext(sendasync);
context.JsonObject = JObject.Parse(message);
MsgHandleHelper.Handle(context); // 处理消息
using (var context = new WebSocketMsgContext(sendasync))
{
context.JsonObject = JObject.Parse(message);
await MsgHandleHelper.HandleAsync(context); // 处理消息
}
//using (var context = new WebSocketMsgContext(sendasync))
//{
// context.JsonObject = JObject.Parse(message);
// await MsgHandleHelper.Handle(context); // 处理消息
//}
//_ = Task.Run(() => {
//});
//});
}
}

View File

@@ -91,7 +91,7 @@ namespace Serein.Library
{
Scan = scan;
MethodDynamicType = methodDynamicType;
MethodTips = methodTips;
AnotherName = methodTips;
LockName = lockName;
}
/// <summary>
@@ -101,7 +101,7 @@ namespace Serein.Library
/// <summary>
/// 类似于注释的效果
/// </summary>
public string MethodTips;
public string AnotherName;
/// <summary>
/// 标记节点行为
/// </summary>

View File

@@ -63,13 +63,7 @@ namespace Serein.NodeFlow.Env
/// <para>表示是否正在控制远程</para>
/// <para>Local control remote env</para>
/// </summary>
public bool IsLcR { get; set; }
/// <summary>
/// <para>表示是否受到远程控制</para>
/// <para>Remote control local env</para>
/// </summary>
public bool IsRcL { get; set; }
public bool IsControlRemoteEnv { get; set; }
/// <summary>
@@ -81,6 +75,7 @@ namespace Serein.NodeFlow.Env
if (clientMsgManage is null)
{
clientMsgManage = new MsgControllerOfServer(this);
//clientMsgManage = new MsgControllerOfServer(this,"123456");
}
_ = clientMsgManage.StartRemoteServerAsync(port);
}
@@ -657,7 +652,7 @@ namespace Serein.NodeFlow.Env
&& NodeModels.TryGetValue(pd.ArgDataSourceNodeGuid, out var fromNode))
{
ConnectGerResultOfNode(fromNode, toNode, pd.ArgDataSourceType, pd.Index);
await ConnectArgSourceOfNodeAsync(fromNode, toNode, pd.ArgDataSourceType, pd.Index);
}
}
}
@@ -678,7 +673,7 @@ namespace Serein.NodeFlow.Env
/// <param name="token">密码</param>
public async Task<(bool, RemoteMsgUtil)> ConnectRemoteEnv(string addres, int port, string token)
{
if (IsLcR)
if (IsControlRemoteEnv)
{
await Console.Out.WriteLineAsync($"当前已经连接远程环境");
return (false, null);
@@ -702,7 +697,7 @@ namespace Serein.NodeFlow.Env
return (false, null);
}
await Console.Out.WriteLineAsync("连接成功开始验证Token");
IsLcR = true;
IsControlRemoteEnv = true;
return (true, remoteMsgUtil);
}
@@ -711,7 +706,7 @@ namespace Serein.NodeFlow.Env
/// </summary>
public void ExitRemoteEnv()
{
IsLcR = false;
IsControlRemoteEnv = false;
}
/// <summary>
@@ -916,7 +911,7 @@ namespace Serein.NodeFlow.Env
var fromNode = GuidToModel(fromNodeGuid);
var toNode = GuidToModel(toNodeGuid);
if (fromNode is null || toNode is null) return false;
(var type,var state) = CheckConnect(fromNode, toNode, fromNodeJunctionType, toNodeJunctionType);
(var type, var state) = CheckConnect(fromNode, toNode, fromNodeJunctionType, toNodeJunctionType);
if (!state)
{
Console.WriteLine("出现非预期的连接行为");
@@ -977,7 +972,7 @@ namespace Serein.NodeFlow.Env
}
// 确定方法入参关系
state = ConnectGerResultOfNode(fromNode, toNode, connectionArgSourceType, argIndex); // 本地环境进行连接
state = await ConnectArgSourceOfNodeAsync(fromNode, toNode, connectionArgSourceType, argIndex); // 本地环境进行连接
}
return state;
@@ -1291,21 +1286,36 @@ namespace Serein.NodeFlow.Env
{
var nodeModel = GuidToModel(nodeGuid);
if (nodeModel is null) return;
if (NodeValueChangeLogger.Remove((nodeGuid, path, value)))
{
// 说明存在过重复的修改
return;
}
NodeValueChangeLogger.Add((nodeGuid, path, value));
var setExp = $"@Set .{path} = {value}"; // 生成 set 表达式
//var getExp = $"@Get .{path}";
SerinExpressionEvaluator.Evaluate(setExp, nodeModel, out _); // 更改对应的数据
//var getResult = SerinExpressionEvaluator.Evaluate(getExp, nodeModel, out _);
//Console.WriteLine($"Set表达式{setExp},result : {getResult}");
SerinExpressionEvaluator.Evaluate($"@Set .{path} = {value}", nodeModel, out _); // 更改对应的数据
//if (NodeValueChangeLogger.Remove((nodeGuid, path, value)))
//{
// // 说明存在过重复的修改
// return;
//}
//NodeValueChangeLogger.Add((nodeGuid, path, value));
//lock (NodeValueChangeLogger)
//{
// Interlocked.Add(ref i, 1);
// Console.WriteLine(i);
// var getExp = $"@Get .{path}";
// var setExp = $"@Set .{path} = {value}"; // 生成 set 表达式
// var oldValue = SerinExpressionEvaluator.Evaluate(getExp, nodeModel, out _);
// if(oldValue != value)
// {
// Console.WriteLine($"旧值:{getExp},result : {oldValue}");
// SerinExpressionEvaluator.Evaluate(setExp, nodeModel, out _); // 更改对应的数据
// Console.WriteLine($"新值:{getExp},result : {SerinExpressionEvaluator.Evaluate(getExp, nodeModel, out _)}");
// }
//}
}
@@ -1487,7 +1497,7 @@ namespace Serein.NodeFlow.Env
Console.WriteLine($"无法加载方法信息:{assemblyName}-{type}-{method}");
continue;
}
md.MethodTips = flowName + md.MethodTips;
md.MethodAnotherName = flowName + md.MethodAnotherName;
if (MethodDelegates.TryAdd(md.MethodName, del))
{
methodDetails.Add(md);
@@ -1702,14 +1712,23 @@ namespace Serein.NodeFlow.Env
/// <param name="connectionArgSourceType"></param>
/// <param name="argIndex"></param>
/// <returns></returns>
private bool ConnectGerResultOfNode(NodeModelBase fromNode,
private async Task<bool> ConnectArgSourceOfNodeAsync(NodeModelBase fromNode,
NodeModelBase toNode,
ConnectionArgSourceType connectionArgSourceType,
int argIndex)
{
if (!string.IsNullOrEmpty(toNode.MethodDetails.ParameterDetailss[argIndex].ArgDataSourceNodeGuid))
{
//if(toNode.MethodDetails.ParameterDetailss[argIndex].ArgDataSourceType == connectionArgSourceType)
//{
// return ;
//}
await RemoteConnectAsync(fromNode,toNode,argIndex); // 已经存在连接,将其移除
}
toNode.MethodDetails.ParameterDetailss[argIndex].ArgDataSourceNodeGuid = fromNode.Guid;
toNode.MethodDetails.ParameterDetailss[argIndex].ArgDataSourceType = connectionArgSourceType;
UIContextOperation?.Invoke(() =>
await UIContextOperation.InvokeAsync(() =>
OnNodeConnectChange?.Invoke(
new NodeConnectChangeEventArgs(
fromNode.Guid, // 从哪个节点开始

View File

@@ -34,6 +34,7 @@ namespace Serein.NodeFlow.Env
private IFlowEnvironment currentFlowEnvironment;
private int _loadingProjectFlag = 0; // 使用原子自增代替锁
/// <summary>
/// 传入false时将停止数据通知。传入true时
@@ -68,9 +69,8 @@ namespace Serein.NodeFlow.Env
public bool IsGlobalInterrupt => currentFlowEnvironment.IsGlobalInterrupt;
public bool IsLcR => currentFlowEnvironment.IsLcR;
public bool IsControlRemoteEnv => currentFlowEnvironment.IsControlRemoteEnv;
public bool IsRcL => currentFlowEnvironment.IsRcL;
public RunState FlowState { get => currentFlowEnvironment.FlowState; set => currentFlowEnvironment.FlowState = value; }
public RunState FlipFlopState { get => currentFlowEnvironment.FlipFlopState; set => currentFlowEnvironment.FlipFlopState = value; }
@@ -404,14 +404,23 @@ namespace Serein.NodeFlow.Env
currentFlowEnvironment.WriteLineObjToJson(obj);
}
/// <summary>
/// (用于远程)通知节点属性变更
/// </summary>
/// <param name="nodeGuid">节点Guid</param>
/// <param name="path">属性路径</param>
/// <param name="value">属性值</param>
/// <returns></returns>
public async Task NotificationNodeValueChangeAsync(string nodeGuid, string path, object value)
{
if (!IsLoadingProject())
{
return;
}
await currentFlowEnvironment.NotificationNodeValueChangeAsync(nodeGuid, path, value);
if (currentFlowEnvironment.IsControlRemoteEnv)
{
await currentFlowEnvironment.NotificationNodeValueChangeAsync(nodeGuid, path, value);
}
}

View File

@@ -53,7 +53,7 @@ namespace Serein.NodeFlow.Env
methodDetails = new MethodDetails();
}
var md = methodDetails.CloneOfNode(nodeModel.Env, nodeModel);
nodeModel.DisplayName = md.MethodTips;
nodeModel.DisplayName = md.MethodAnotherName;
nodeModel.MethodDetails = md;

View File

@@ -55,6 +55,7 @@ namespace Serein.NodeFlow.Env
/// <summary>
/// 启动带token验证的远程服务
/// </summary>
/// <param name="environment"></param>
/// <param name="token"></param>
public MsgControllerOfServer(IFlowEnvironment environment, string token)
{
@@ -567,6 +568,7 @@ namespace Serein.NodeFlow.Env
environment.SetMonitorObjState(key, isMonitor);
}
/// <summary>
/// 节点数据更改
/// </summary>
@@ -576,6 +578,7 @@ namespace Serein.NodeFlow.Env
[AutoSocketHandle(ThemeValue = EnvMsgTheme.ValueNotification)]
public async Task ValueNotification(string nodeGuid, string path, string value)
{
await environment.NotificationNodeValueChangeAsync(nodeGuid, path, value);
}

View File

@@ -64,9 +64,8 @@ namespace Serein.NodeFlow.Env
public bool IsGlobalInterrupt => false;
public bool IsLcR => true;
public bool IsControlRemoteEnv => true;
public bool IsRcL => false;
public RunState FlowState { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public RunState FlipFlopState { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
@@ -78,6 +77,10 @@ namespace Serein.NodeFlow.Env
/// 标示是否正在加载项目
/// </summary>
private bool IsLoadingProject = false;
/// <summary>
/// 表示是否正在加载节点
/// </summary>
private bool IsLoadingNode = false;
public void SetConsoleOut()
{
@@ -666,13 +669,14 @@ namespace Serein.NodeFlow.Env
/// <param name="methodDetailsInfo">节点绑定的方法说明</param>
public async Task<NodeInfo> CreateNodeAsync(NodeControlType nodeControlType, PositionOfUI position, MethodDetailsInfo methodDetailsInfo = null)
{
IsLoadingNode = true;
var nodeInfo = await msgClient.SendAndWaitDataAsync<NodeInfo>(EnvMsgTheme.CreateNode, new
{
nodeType = nodeControlType.ToString(),
position = position,
mdInfo = methodDetailsInfo,
});
MethodDetails? methodDetails = null;
if (!string.IsNullOrEmpty(nodeInfo.MethodName))
{
@@ -683,6 +687,7 @@ namespace Serein.NodeFlow.Env
var nodeModel = FlowFunc.CreateNode(this, nodeControlType, methodDetails); // 远程环境下加载节点
nodeModel.LoadInfo(nodeInfo);
TryAddNode(nodeModel);
IsLoadingNode = false;
// 通知UI更改
UIContextOperation.Invoke(() =>
@@ -816,14 +821,18 @@ namespace Serein.NodeFlow.Env
public async Task NotificationNodeValueChangeAsync(string nodeGuid, string path, object value)
{
//Console.WriteLine($"通知远程环境修改节点数据:{nodeGuid},name:{path},value:{value}");
if(IsLoadingProject || IsLoadingNode)
{
return;
}
Console.WriteLine($"通知远程环境修改节点数据:{nodeGuid},name:{path},value:{value}");
//_ = msgClient.SendAsync(EnvMsgTheme.ValueNotification, new
//{
// nodeGuid = nodeGuid,
// path = path,
// value = value.ToString(),
//});
_ = msgClient.SendAsync(EnvMsgTheme.ValueNotification, new
{
nodeGuid = nodeGuid,
path = path,
value = value.ToString(),
});
}
}

View File

@@ -104,7 +104,7 @@ namespace Serein.NodeFlow.Model
{
Guid = Guid,
MethodName = MethodDetails?.MethodName,
Label = DisplayName ?? "",
Label = MethodDetails?.MethodAnotherName,
Type = this.GetType().ToString(),
TrueNodes = trueNodes.ToArray(),
FalseNodes = falseNodes.ToArray(),

View File

@@ -83,14 +83,14 @@ public static class NodeMethodDetailsHelper
returnType = method.ReturnType;
}
if (string.IsNullOrEmpty(attribute.MethodTips)){
attribute.MethodTips = method.Name;
if (string.IsNullOrEmpty(attribute.AnotherName)){
attribute.AnotherName = method.Name;
}
var asyncPrefix = "[异步]"; // IsGenericTask(returnType) ? "[async]" : ;
var methodTips = isTask ? asyncPrefix + attribute.MethodTips : attribute.MethodTips;
var methodMethodAnotherName = isTask ? asyncPrefix + attribute.AnotherName : attribute.AnotherName;
@@ -101,7 +101,7 @@ public static class NodeMethodDetailsHelper
MethodName = dllTypeMethodName,
MethodDynamicType = attribute.MethodDynamicType,
MethodLockName = attribute.LockName,
MethodTips = methodTips,
MethodAnotherName = methodMethodAnotherName,
ParameterDetailss = explicitDataOfParameters,
ReturnType = returnType,
};

View File

@@ -183,20 +183,32 @@ namespace Serein.Library.NodeGenerator
{
if (classInfo.ExitsPath(nameof(NodeValuePath.Node))) // 节点 or 自定义节点
{
sb.AddCode(5, $"((NodeModelBase)this).Env?.NotificationNodeValueChangeAsync(this.Guid, nameof({propertyName}), value); // 通知远程环境属性发生改变了");
sb.AddCode(5, $"if (this?.Env?.IsControlRemoteEnv == true) // 正在控制远程环境时才触发");
sb.AddCode(5, $"{{");
sb.AddCode(6, $"this.Env?.NotificationNodeValueChangeAsync(this.Guid, nameof({propertyName}), value); // 通知远程环境属性发生改变了");
sb.AddCode(5, $"}}");
}
else if (classInfo.ExitsPath(nameof(NodeValuePath.Method))) // 节点方法详情
else
{
sb.AddCode(5, $"NodeModel?.Env?.NotificationNodeValueChangeAsync(NodeModel.Guid, \"MethodDetails.\"+nameof({propertyName}), value); // 通知远程环境属性发生改变了");
}
else if (classInfo.ExitsPath(nameof(NodeValuePath.Parameter))) // 节点方法入参参数描述
{
sb.AddCode(5, "NodeModel?.Env?.NotificationNodeValueChangeAsync(NodeModel.Guid, \"MethodDetails.ParameterDetailss[\"+$\"{Index}\"+\"]." + $"\"+nameof({propertyName}),value); // 通知远程环境属性发生改变了");
}
else if (classInfo.ExitsPath(nameof(NodeValuePath.DebugSetting))) // 节点的调试信息
{
sb.AddCode(5, $"NodeModel?.Env?.NotificationNodeValueChangeAsync(NodeModel.Guid, \"DebugSetting.\"+nameof({propertyName}), value); // 通知远程环境属性发生改变了");
sb.AddCode(5, $"if (NodeModel?.Env?.IsControlRemoteEnv == true) // 正在控制远程环境时才触发");
sb.AddCode(5, $"{{");
if (classInfo.ExitsPath(nameof(NodeValuePath.Method))) // 节点方法详情
{
sb.AddCode(6, $"NodeModel?.Env?.NotificationNodeValueChangeAsync(NodeModel.Guid, \"MethodDetails.\"+nameof({propertyName}), value); // 通知远程环境属性发生改变了");
}
else if (classInfo.ExitsPath(nameof(NodeValuePath.Parameter))) // 节点方法入参参数描述
{
sb.AddCode(6, "NodeModel?.Env?.NotificationNodeValueChangeAsync(NodeModel.Guid, \"MethodDetails.ParameterDetailss[\"+$\"{Index}\"+\"]." + $"\"+nameof({propertyName}),value); // 通知远程环境属性发生改变了");
}
else if (classInfo.ExitsPath(nameof(NodeValuePath.DebugSetting))) // 节点的调试信息
{
sb.AddCode(6, $"NodeModel?.Env?.NotificationNodeValueChangeAsync(NodeModel.Guid, \"DebugSetting.\"+nameof({propertyName}), value); // 通知远程环境属性发生改变了");
}
sb.AddCode(5, $"}}");
}
}
if (attributeInfo.Search(nameof(PropertyInfo), nameof(PropertyInfo.CustomCode), value => !string.IsNullOrEmpty(value))) // 是否打印
{

View File

@@ -89,14 +89,15 @@
<!--<Button Grid.Row="0" Content="卸载清空" Click="UnloadAllButton_Click" HorizontalAlignment="Right" Margin="5,5,5,5"/>--><!--
</Grid>-->
<ScrollViewer Grid.Row="0" HorizontalScrollBarVisibility="Auto">
<!--暂时隐藏基础面板-->
<ScrollViewer Grid.Row="0" Visibility="Collapsed" HorizontalScrollBarVisibility="Auto">
<StackPanel Orientation="Horizontal">
<nodeView:ExpOpNodeControl x:Name="ExpOpNodeControl" Margin="10" AllowDrop="True" PreviewMouseMove="BaseNodeControl_PreviewMouseMove"/>
<nodeView:ConditionNodeControl x:Name="ConditionNodeControl" Margin="10" AllowDrop="True" PreviewMouseMove="BaseNodeControl_PreviewMouseMove"/>
<nodeView:ConditionRegionControl x:Name="ConditionRegionControl" Margin="10" AllowDrop="True" PreviewMouseMove="BaseNodeControl_PreviewMouseMove"/>
</StackPanel>
</ScrollViewer>
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto" MaxHeight="400" Grid.RowSpan="2">
<ScrollViewer VerticalAlignment="Top" Grid.Row="1" VerticalScrollBarVisibility="Auto" MaxHeight="400" Grid.RowSpan="2">
<StackPanel x:Name="DllStackPanel" Margin="5"/>
</ScrollViewer>
<!--<GridSplitter Grid.Row="3" Height="5" HorizontalAlignment="Stretch" VerticalAlignment="Center" ResizeBehavior="PreviousAndNext" Background="Gray"/>-->
@@ -209,21 +210,21 @@ Canvas.Top="{Binding ActualHeight, ElementName=FlowChartCanvas, Mode=OneWay, Con
</StackPanel>
<StackPanel>
<StackPanel x:Name="CreateNodeInvoke"
Margin="14" Width="auto" HorizontalAlignment="Left" Background="White" Opacity="0.7"
Margin="14" Width="auto" HorizontalAlignment="Left" Background="White" Opacity="0.8"
Visibility="{Binding IsConnectionInvokeNode,
Converter={StaticResource InvertedBoolConverter},ConverterParameter=Normal}" >
<TextBlock Margin="8,2,8,0" Foreground="#FF2727" FontSize="14" Text="正在设置调用关系"/>
<TextBlock Margin="8,2,8,0" Foreground="#FF2727" FontSize="14" Text="正在设置方法调用关系 按 Ecs 退出连线状态 )"/>
<TextBlock Margin="8,0,8,0" Foreground="#4A82E4" FontSize="14" Text=" 按 1 切换:上游分支(运行本节点前,优先执行目标节点)"/>
<TextBlock Margin="8,0,8,0" Foreground="#04FC10" FontSize="14" Text=" 按 2 切换Succeed 分支(本节点运行完成,将会运行目标节点)"/>
<TextBlock Margin="8,0,8,0" Foreground="#F18905" FontSize="14" Text=" 按 3 切换Fail 分支条件节点的false分支"/>
<TextBlock Margin="8,0,8,2" Foreground="#FE1343" FontSize="14" Text=" 按 4 切换:异常分支(本节点运行发生异常时执行目标节点)"/>
</StackPanel>
<StackPanel Margin="14" Width="auto" HorizontalAlignment="Left" Background="White" Opacity="0.9"
<StackPanel Margin="14" Width="auto" HorizontalAlignment="Left" Background="White" Opacity="0.8"
Visibility="{Binding IsConnectionArgSourceNode,
Converter={StaticResource InvertedBoolConverter},ConverterParameter=Normal}" >
<TextBlock Margin="8,2,8,0" Foreground="#FF2727" FontSize="14" Text="正在设置参数传递关系"/>
<TextBlock Margin="8,0,8,0" Foreground="#56CEF6" FontSize="14" Text=" 按 1 切换:入参使用目标节点返回值"/>
<TextBlock Margin="8,0,8,2" Foreground="#B06BBB" FontSize="14" Text=" 按 2 切换:立刻调用目标节点,其返回值作为入参参数"/>
<TextBlock Margin="8,2,8,0" Foreground="#FF2727" FontSize="14" Text="正在设置参数传递关系 按 Ecs 退出连线状态 )"/>
<TextBlock Margin="8,0,8,0" Foreground="#56CEF6" FontSize="14" Text=" 按 1 切换:使用返回值作为当前上下文的入参参数当前上下文下如果未曾运行过该节点将会返回null"/>
<TextBlock Margin="8,0,8,2" Foreground="#B06BBB" FontSize="14" Text=" 按 2 切换:立刻调用节点,其返回值作为当前上下文的入参参数"/>
</StackPanel>
</StackPanel>
</Grid>

View File

@@ -368,8 +368,9 @@ namespace Serein.Workbench
if (eventArgs.JunctionOfConnectionType == JunctionOfConnectionType.Invoke)
{
#region /
ConnectionInvokeType connectionType = eventArgs.ConnectionInvokeType;
#region /
#region
if (eventArgs.ChangeType == NodeConnectChangeEventArgs.ConnectChangeType.Create) // 添加连接
{
if (fromNodeControl is not INodeJunction IFormJunction || toNodeControl is not INodeJunction IToJunction)
@@ -383,10 +384,10 @@ namespace Serein.Workbench
// 添加连接
var connection = new ConnectionControl(
FlowChartCanvas,
FlowChartCanvas,
connectionType,
startJunction,
endJunction,
endJunction,
() => EnvDecorator.RemoveConnectInvokeAsync(fromNodeGuid, toNodeGuid, connectionType)
);
@@ -403,11 +404,16 @@ namespace Serein.Workbench
}
#endregion
#region
else if (eventArgs.ChangeType == NodeConnectChangeEventArgs.ConnectChangeType.Remote) // 移除连接
{
// 需要移除连接
var removeConnections = Connections.Where(c => c.Start.MyNode.Guid.Equals(fromNodeGuid)
&& c.End.MyNode.Guid.Equals(toNodeGuid))
var removeConnections = Connections.Where(c =>
c.Start.MyNode.Guid.Equals(fromNodeGuid)
&& c.End.MyNode.Guid.Equals(toNodeGuid)
&& (c.Start.JunctionType.ToConnectyionType() == JunctionOfConnectionType.Invoke
|| c.End.JunctionType.ToConnectyionType() == JunctionOfConnectionType.Invoke))
.ToList();
@@ -417,18 +423,20 @@ namespace Serein.Workbench
Connections.Remove(connection);
fromNodeControl.RemoveCnnection(connection);
toNodeControl.RemoveCnnection(connection);
if(NodeControls.TryGetValue(connection.End.MyNode.Guid, out var control))
if (NodeControls.TryGetValue(connection.End.MyNode.Guid, out var control))
{
JudgmentFlipFlopNode(control); // 连接关系变更时判断
}
}
}
}
#endregion
#endregion
}
else
{
#region /
ConnectionArgSourceType connectionArgSourceType = eventArgs.ConnectionArgSourceType;
#region /
#region
if (eventArgs.ChangeType == NodeConnectChangeEventArgs.ConnectChangeType.Create) // 添加连接
{
if (fromNodeControl is not INodeJunction IFormJunction || toNodeControl is not INodeJunction IToJunction)
@@ -471,6 +479,8 @@ namespace Serein.Workbench
}
#endregion
#region
else if (eventArgs.ChangeType == NodeConnectChangeEventArgs.ConnectChangeType.Remote) // 移除连接
{
// 需要移除连接
@@ -478,11 +488,11 @@ namespace Serein.Workbench
&& c.End.MyNode.Guid.Equals(toNodeGuid))
.ToList(); // 获取这两个节点之间的所有连接关系
foreach (var connection in removeConnections)
{
if(connection.End is ArgJunctionControl junctionControl && junctionControl.ArgIndex == eventArgs.ArgIndex)
if (connection.End is ArgJunctionControl junctionControl && junctionControl.ArgIndex == eventArgs.ArgIndex)
{
// 找到符合删除条件的连接线
connection.DeleteConnection(); // 从UI层面上移除
@@ -491,13 +501,14 @@ namespace Serein.Workbench
toNodeControl.RemoveCnnection(connection); // 从节点持有的记录移除
}
//if (NodeControls.TryGetValue(connection.End.MyNode.Guid, out var control))
//{
// JudgmentFlipFlopNode(control); // 连接关系变更时判断
//}
}
}
}
#endregion
#endregion
}

View File

@@ -20,7 +20,7 @@
<Border BorderBrush="#8DE9FD" BorderThickness="4">
<Grid>
<Grid.ToolTip>
<ToolTip Background="LightYellow" Foreground="#071042" Content="{Binding NodeModel.MethodDetails.MethodTips}" />
<ToolTip Background="LightYellow" Foreground="#071042" Content="{Binding NodeModel.MethodDetails}" />
</Grid.ToolTip>
<!--<TextBlock Text="{Binding NodelModel.DebugSetting.IsInterrupt}}"></TextBlock>-->
@@ -66,7 +66,7 @@
<local:ExecuteJunctionControl Grid.Column="0" MyNode="{Binding NodeModel}" x:Name="ExecuteJunctionControl" HorizontalAlignment="Left" Grid.RowSpan="2"/>
<StackPanel Grid.Column="1" Grid.RowSpan="2" >
<TextBlock Text="{Binding NodeModel.MethodDetails.MethodTips, Mode=TwoWay}" HorizontalAlignment="Center"/>
<TextBlock Text="{Binding NodeModel.DisplayName, Mode=TwoWay}" HorizontalAlignment="Center"/>
</StackPanel>
<local:NextStepJunctionControl Grid.Column="2" MyNode="{Binding NodeModel}" x:Name="NextStepJunctionControl" HorizontalAlignment="Right" Grid.RowSpan="2"/>

View File

@@ -66,14 +66,14 @@ namespace Serein.Workbench.Node.View
/// <summary>
/// 向指定面板添加类型的文本块
/// </summary>
/// <param name="type">要添加的类型</param>
/// <param name="panel">要添加到的面板</param>
/// <param name="mdInfo">要添加的方法信息</param>
/// <param name="listBox">要添加到的面板</param>
private void AddTypeToListBox(MethodDetailsInfo mdInfo, ListBox listBox)
{
// 创建一个新的 TextBlock 并设置其属性
TextBlock typeText = new TextBlock
{
Text = $"{mdInfo.MethodTips}",
Text = $"{mdInfo.MethodAnotherName} - {mdInfo.MethodName}",
Margin = new Thickness(10, 2, 0, 0),
Tag = mdInfo
};

View File

@@ -22,7 +22,7 @@
<Grid>
<Grid.ToolTip>
<ToolTip Background="LightYellow" Foreground="#071042" Content="{Binding NodeModel.MethodDetails.MethodName, UpdateSourceTrigger=PropertyChanged}" />
<ToolTip Background="LightYellow" Foreground="#071042" Content="{Binding NodeModel.MethodDetails, UpdateSourceTrigger=PropertyChanged}" />
</Grid.ToolTip>
<Grid.RowDefinitions>
@@ -47,7 +47,7 @@
<local:ExecuteJunctionControl Grid.Column="0" MyNode="{Binding NodeModel}" x:Name="ExecuteJunctionControl" HorizontalAlignment="Left" Grid.RowSpan="2"/>
<StackPanel Grid.Column="1" Grid.RowSpan="2" >
<TextBlock Text="{Binding NodeModel.MethodDetails.MethodTips, Mode=TwoWay}" HorizontalAlignment="Center"/>
<TextBlock Text="{Binding NodeModel.DisplayName, Mode=TwoWay}" HorizontalAlignment="Center"/>
</StackPanel>
<local:NextStepJunctionControl Grid.Column="2" MyNode="{Binding NodeModel}" x:Name="NextStepJunctionControl" HorizontalAlignment="Right" Grid.RowSpan="2"/>

View File

@@ -56,7 +56,7 @@ namespace Serein.Workbench.Themes
{ConnectionInvokeType.IsError, []},
}
};
string? itemName = rootNodeModel.MethodDetails?.MethodTips;
string? itemName = rootNodeModel.MethodDetails?.MethodAnotherName;
if (string.IsNullOrEmpty(itemName))
{
itemName = rootNodeModel.ControlType.ToString();
@@ -123,7 +123,7 @@ namespace Serein.Workbench.Themes
RootNode = child,
ChildNodes = child.SuccessorNodes,
};
string? itemName = child?.MethodDetails?.MethodTips;
string? itemName = child?.MethodDetails?.MethodAnotherName;
if (string.IsNullOrEmpty(itemName))
{
itemName = child?.ControlType.ToString();
@@ -186,7 +186,7 @@ namespace Serein.Workbench.Themes
ChildNodes = childNodeModel.SuccessorNodes,
};
string? itemName = childNodeModel?.MethodDetails?.MethodTips;
string? itemName = childNodeModel?.MethodDetails?.MethodAnotherName;
if (string.IsNullOrEmpty(itemName))
{
itemName = childNodeModel?.ControlType.ToString();