mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-03 00:00:49 +08:00
实现了远程属性更改、数据交互。
This commit is contained in:
Binary file not shown.
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<AssemblyName>project</AssemblyName>
|
||||
<AssemblyName>starter</AssemblyName>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net8.0|AnyCPU'">
|
||||
|
||||
@@ -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
|
||||
/// </summary>
|
||||
/// <param name="eventArgs"></param>
|
||||
|
||||
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; }
|
||||
|
||||
/// <summary>
|
||||
/// 拓展功能时,如需订阅事件,则需要使用该属性
|
||||
/// 表示当前环境
|
||||
/// </summary>
|
||||
IFlowEnvironment CurrentEnv { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 由运行环境提供的UI线程上下文操作,用于类库中需要在UI线程中操作视觉元素的场景
|
||||
/// </summary>
|
||||
UIContextOperation UIContextOperation { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region 事件
|
||||
@@ -509,7 +515,7 @@ namespace Serein.Library.Api
|
||||
/// <summary>
|
||||
/// 移除节点事件
|
||||
/// </summary>
|
||||
event NodeRemoteHandler OnNodeRemote;
|
||||
event NodeRemoveHandler OnNodeRemove;
|
||||
|
||||
/// <summary>
|
||||
/// 起始节点变化事件
|
||||
@@ -674,13 +680,13 @@ namespace Serein.Library.Api
|
||||
/// <param name="fromNodeGuid">起始节点</param>
|
||||
/// <param name="toNodeGuid">目标节点</param>
|
||||
/// <param name="connectionType">连接类型</param>
|
||||
void RemoveConnect(string fromNodeGuid, string toNodeGuid, ConnectionType connectionType);
|
||||
Task<bool> RemoveConnectAsync(string fromNodeGuid, string toNodeGuid, ConnectionType connectionType);
|
||||
|
||||
/// <summary>
|
||||
/// 移除节点/区域/基础控件
|
||||
/// </summary>
|
||||
/// <param name="nodeGuid">待移除的节点Guid</param>
|
||||
void RemoveNode(string nodeGuid);
|
||||
Task<bool> RemoveNodeAsync(string nodeGuid);
|
||||
|
||||
/// <summary>
|
||||
/// 激活未启动的全局触发器
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace Serein.Library
|
||||
{
|
||||
public bool IsNotification = false;
|
||||
public bool IsPrint = false;
|
||||
public bool IsProtection = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,27 +9,41 @@ namespace Serein.Library
|
||||
/// <summary>
|
||||
/// 节点调试设置,用于中断节点的运行
|
||||
/// </summary>
|
||||
public class NodeDebugSetting
|
||||
[AutoProperty(ValuePath = nameof(NodeDebugSetting))]
|
||||
public partial class NodeDebugSetting
|
||||
{
|
||||
private readonly NodeModelBase nodeModel;
|
||||
/// <summary>
|
||||
/// 创建属于某个节点的调试设置
|
||||
/// </summary>
|
||||
/// <param name="nodeModel"></param>
|
||||
public NodeDebugSetting(NodeModelBase nodeModel)
|
||||
{
|
||||
this.nodeModel = nodeModel;
|
||||
}
|
||||
/// <summary>
|
||||
/// 是否使能
|
||||
/// </summary>
|
||||
public bool IsEnable { get; set; } = true;
|
||||
[PropertyInfo(IsNotification = true)]
|
||||
private bool _isEnable = true;
|
||||
|
||||
/// <summary>
|
||||
/// 中断级别,暂时停止继续执行后继分支。
|
||||
/// </summary>
|
||||
public InterruptClass InterruptClass { get; set; } = InterruptClass.None;
|
||||
[PropertyInfo]
|
||||
private InterruptClass _interruptClass = InterruptClass.None;
|
||||
|
||||
/// <summary>
|
||||
/// 取消中断的回调函数
|
||||
/// </summary>
|
||||
public Action CancelInterruptCallback { get; set; }
|
||||
[PropertyInfo]
|
||||
private Action _cancelInterruptCallback;
|
||||
|
||||
/// <summary>
|
||||
/// 中断Task(用来取消中断)
|
||||
/// 中断Task(用来中断)
|
||||
/// </summary>
|
||||
public Func<Task<CancelType>> GetInterruptTask { get; set; }
|
||||
[PropertyInfo]
|
||||
private Func<Task<CancelType>> _getInterruptTask;
|
||||
}
|
||||
|
||||
|
||||
@@ -53,3 +67,6 @@ namespace Serein.Library
|
||||
Global,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 节点基类(数据):条件控件,动作控件,条件区域,动作区域
|
||||
/// </summary>
|
||||
[AutoProperty(ValuePath = nameof(NodeModelBase))] // 是否更名为 NodeProperty?
|
||||
public abstract partial class NodeModelBase : IDynamicFlowNode
|
||||
{
|
||||
|
||||
|
||||
[PropertyInfo(IsProtection = true)]
|
||||
private IFlowEnvironment _env;
|
||||
|
||||
/// <summary>
|
||||
/// 在画布中的位置
|
||||
/// </summary>
|
||||
[PropertyInfo(IsProtection = true)]
|
||||
private PositionOfUI _position ;
|
||||
|
||||
/// <summary>
|
||||
/// 附加的调试功能
|
||||
/// </summary>
|
||||
[PropertyInfo(IsProtection = true)]
|
||||
private NodeDebugSetting _debugSetting ;
|
||||
|
||||
/// <summary>
|
||||
/// 描述节点对应的控件类型
|
||||
/// </summary>
|
||||
[PropertyInfo(IsProtection = true)]
|
||||
private NodeControlType _controlType ;
|
||||
|
||||
/// <summary>
|
||||
/// 方法描述。不包含Method与委托,需要通过MethodName从环境中获取委托进行调用。
|
||||
/// </summary>
|
||||
[PropertyInfo(IsProtection = true)]
|
||||
private MethodDetails _methodDetails ;
|
||||
|
||||
/// <summary>
|
||||
/// 标识节点对象全局唯一
|
||||
/// </summary>
|
||||
[PropertyInfo(IsProtection = true)]
|
||||
private string _guid ;
|
||||
|
||||
/// <summary>
|
||||
/// 显示名称
|
||||
/// </summary>
|
||||
[PropertyInfo]
|
||||
private string _displayName ;
|
||||
|
||||
/// <summary>
|
||||
/// 是否为起点控件
|
||||
/// </summary>
|
||||
[PropertyInfo]
|
||||
private bool _isStart ;
|
||||
|
||||
/// <summary>
|
||||
/// 运行时的上一节点
|
||||
/// </summary>
|
||||
[PropertyInfo]
|
||||
private NodeModelBase _previousNode ;
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 当前节点执行完毕后需要执行的下一个分支的类别
|
||||
/// </summary>
|
||||
[PropertyInfo]
|
||||
private ConnectionType _nextOrientation = ConnectionType.None;
|
||||
|
||||
/// <summary>
|
||||
/// 运行时的异常信息(仅在 FlowState 为 Error 时存在对应值)
|
||||
/// </summary>
|
||||
[PropertyInfo]
|
||||
private Exception _runingException ;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public abstract partial class NodeModelBase : IDynamicFlowNode
|
||||
{
|
||||
public NodeModelBase(IFlowEnvironment environment)
|
||||
{
|
||||
PreviousNodes = new Dictionary<ConnectionType, List<NodeModelBase>>();
|
||||
@@ -21,75 +97,19 @@ namespace Serein.Library
|
||||
PreviousNodes[ctType] = new List<NodeModelBase>();
|
||||
SuccessorNodes[ctType] = new List<NodeModelBase>();
|
||||
}
|
||||
DebugSetting = new NodeDebugSetting();
|
||||
DebugSetting = new NodeDebugSetting(this);
|
||||
this.Env = environment;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 节点保留对环境的引用,因为需要在属性更改时通知
|
||||
/// </summary>
|
||||
public IFlowEnvironment Env { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 在画布中的位置
|
||||
/// </summary>
|
||||
public PositionOfUI Position { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 附加的调试功能
|
||||
/// </summary>
|
||||
public NodeDebugSetting DebugSetting { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 描述节点对应的控件类型
|
||||
/// </summary>
|
||||
public NodeControlType ControlType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 方法描述但不包含Method与委托,需要通过MethodName从环境中获取委托进行调用。
|
||||
/// </summary>
|
||||
public MethodDetails MethodDetails { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 标识节点对象全局唯一
|
||||
/// </summary>
|
||||
public string Guid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 显示名称
|
||||
/// </summary>
|
||||
public string DisplayName { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 是否为起点控件
|
||||
/// </summary>
|
||||
public bool IsStart { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 运行时的上一节点
|
||||
/// </summary>
|
||||
public NodeModelBase PreviousNode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 不同分支的父节点
|
||||
/// </summary>
|
||||
public Dictionary<ConnectionType,List<NodeModelBase>> PreviousNodes { get; }
|
||||
|
||||
public Dictionary<ConnectionType, List<NodeModelBase>> PreviousNodes { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 不同分支的子节点
|
||||
/// </summary>
|
||||
public Dictionary<ConnectionType,List<NodeModelBase>> SuccessorNodes { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前节点执行完毕后需要执行的下一个分支的类别
|
||||
/// </summary>
|
||||
public ConnectionType NextOrientation { get; set; } = ConnectionType.None;
|
||||
|
||||
/// <summary>
|
||||
/// 运行时的异常信息(仅在 FlowState 为 Error 时存在对应值)
|
||||
/// </summary>
|
||||
public Exception RuningException { get; set; } = null;
|
||||
|
||||
public Dictionary<ConnectionType, List<NodeModelBase>> SuccessorNodes { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 控制FlowData在同一时间只会被同一个线程更改。
|
||||
@@ -126,11 +146,75 @@ namespace Serein.Library
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
/// <summary>
|
||||
/// 节点基类(数据):条件控件,动作控件,条件区域,动作区域
|
||||
/// </summary>
|
||||
public abstract partial class NodeModelBase : IDynamicFlowNode
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 节点保留对环境的引用,因为需要在属性更改时通知
|
||||
/// </summary>
|
||||
public IFlowEnvironment Env { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 在画布中的位置
|
||||
/// </summary>
|
||||
public PositionOfUI Position { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 附加的调试功能
|
||||
/// </summary>
|
||||
public NodeDebugSetting DebugSetting { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 描述节点对应的控件类型
|
||||
/// </summary>
|
||||
public NodeControlType ControlType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 方法描述。不包含Method与委托,需要通过MethodName从环境中获取委托进行调用。
|
||||
/// </summary>
|
||||
public MethodDetails MethodDetails { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 标识节点对象全局唯一
|
||||
/// </summary>
|
||||
public string Guid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 显示名称
|
||||
/// </summary>
|
||||
public string DisplayName { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 是否为起点控件
|
||||
/// </summary>
|
||||
public bool IsStart { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 运行时的上一节点
|
||||
/// </summary>
|
||||
public NodeModelBase PreviousNode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前节点执行完毕后需要执行的下一个分支的类别
|
||||
/// </summary>
|
||||
public ConnectionType NextOrientation { get; set; } = ConnectionType.None;
|
||||
|
||||
/// <summary>
|
||||
/// 运行时的异常信息(仅在 FlowState 为 Error 时存在对应值)
|
||||
/// </summary>
|
||||
public Exception RuningException { get; set; } = null;
|
||||
|
||||
|
||||
}*/
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
@@ -156,7 +240,7 @@ namespace Serein.Library
|
||||
// this.FlowData = builder.FlowData;
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
||||
// /// <summary>
|
||||
// /// 节点对应的控件类型
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -212,6 +212,8 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
|
||||
if (EmitMethodType == EmitHelper.EmitMethodType.HasResultTask && EmitDelegate is Func<object, object[], Task<object>> hasResultTask)
|
||||
{
|
||||
result = await hasResultTask(Instance, args);
|
||||
//Console.WriteLine(result);
|
||||
// why not data?
|
||||
}
|
||||
else if (EmitMethodType == EmitHelper.EmitMethodType.Task && EmitDelegate is Func<object, object[], Task> task)
|
||||
{
|
||||
@@ -241,12 +243,23 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
|
||||
//sw.Stop();
|
||||
//Console.WriteLine($"Emit Invoke:{sw.ElapsedTicks * 1000000F / Stopwatch.Frequency:n3}μs");
|
||||
|
||||
if(Module.IsReturnValue && result != null && result.GetType().IsClass)
|
||||
if(result is null)
|
||||
{
|
||||
//var reusltJsonText = JsonConvert.SerializeObject(result);
|
||||
_ = SendAsync.Invoke(result);
|
||||
//_ = SendAsync.Invoke($"{reusltJsonText}");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Module.IsReturnValue)
|
||||
{
|
||||
_ = SendAsync.Invoke(result);
|
||||
}
|
||||
}
|
||||
//if( && result != null && result.GetType().IsClass)
|
||||
//{
|
||||
// //var reusltJsonText = JsonConvert.SerializeObject(result);
|
||||
|
||||
// //_ = SendAsync.Invoke($"{reusltJsonText}");
|
||||
//}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<Version>1.0.15</Version>
|
||||
<Version>1.0.17</Version>
|
||||
<TargetFrameworks>net8.0;net462</TargetFrameworks>
|
||||
<!--<TargetFrameworks>net8.0</TargetFrameworks>-->
|
||||
<BaseOutputPath>D:\Project\C#\DynamicControl\SereinFlow\.Output</BaseOutputPath>
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
<ProjectReference Include="..\Serein.Library.MyGenerator\Serein.Library.MyGenerator.csproj" OutputItemType="Analyzer"/>
|
||||
<ProjectReference Include="..\Serein.Library.MyGenerator\Serein.Library.NodeGenerator.csproj" OutputItemType="Analyzer" />
|
||||
<!--ReferenceOutputAssembly="false"-->
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="System.Reactive" Version="6.0.1" />
|
||||
|
||||
@@ -75,7 +75,6 @@ namespace Serein.Library.Utils
|
||||
/// 创建信号,直到手动触发(异步方法)
|
||||
/// </summary>
|
||||
/// <param name="signal">信号标识符</param>
|
||||
/// <param name="outTime">超时时间</param>
|
||||
/// <returns>等待任务</returns>
|
||||
public async Task<CancelType> GetOrCreateChannelAsync(string signal)
|
||||
{
|
||||
|
||||
@@ -48,8 +48,6 @@ namespace Serein.Library.Utils.SereinExpression
|
||||
/// <exception cref="NotSupportedException"></exception>
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@ using System.Threading.Tasks;
|
||||
namespace Serein.Library.Utils
|
||||
{
|
||||
/// <summary>
|
||||
/// 为类库提供了在UI线程上下文操作的方法
|
||||
/// 为类库提供了在UI线程上下文操作的方法,如果你在Windows平台上运行,不必手动实例化该类
|
||||
/// </summary>
|
||||
public class UIContextOperation
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 运行环境
|
||||
/// </summary>
|
||||
@@ -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
|
||||
/// <summary>
|
||||
/// 移除节点事件
|
||||
/// </summary>
|
||||
public event NodeRemoteHandler? OnNodeRemote;
|
||||
public event NodeRemoveHandler? OnNodeRemove;
|
||||
|
||||
/// <summary>
|
||||
/// 起始节点变化事件
|
||||
@@ -190,10 +194,15 @@ namespace Serein.NodeFlow.Env
|
||||
|
||||
#region 属性
|
||||
|
||||
/// <summary>
|
||||
/// 当前环境
|
||||
/// </summary>
|
||||
public IFlowEnvironment CurrentEnv { get => this; }
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// UI线程操作类
|
||||
/// </summary>
|
||||
public UIContextOperation UIContextOperation { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
@@ -245,11 +254,7 @@ namespace Serein.NodeFlow.Env
|
||||
/// </summary>
|
||||
public ConcurrentDictionary<string, MethodDetails> MethodDetailss { get; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// UI线程操作类
|
||||
/// </summary>
|
||||
private readonly UIContextOperation uiContextOperation;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 容器管理
|
||||
/// </summary>
|
||||
@@ -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
|
||||
/// 激活全局触发器
|
||||
/// </summary>
|
||||
/// <param name="nodeGuid"></param>
|
||||
[AutoSocketHandle]
|
||||
// [AutoSocketHandle]
|
||||
public void ActivateFlipflopNode(string nodeGuid)
|
||||
{
|
||||
var nodeModel = GuidToModel(nodeGuid);
|
||||
@@ -455,7 +471,7 @@ namespace Serein.NodeFlow.Env
|
||||
/// 关闭全局触发器
|
||||
/// </summary>
|
||||
/// <param name="nodeGuid"></param>
|
||||
[AutoSocketHandle]
|
||||
// [AutoSocketHandle]
|
||||
public void TerminateFlipflopNode(string nodeGuid)
|
||||
{
|
||||
var nodeModel = GuidToModel(nodeGuid);
|
||||
@@ -470,7 +486,7 @@ namespace Serein.NodeFlow.Env
|
||||
/// 获取当前环境信息(远程连接)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[AutoSocketHandle]
|
||||
// [AutoSocketHandle]
|
||||
public async Task<FlowEnvInfo> GetEnvInfoAsync()
|
||||
{
|
||||
Dictionary<NodeLibrary, List<MethodDetailsInfo>> 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
|
||||
/// 序列化当前项目的依赖信息、节点信息
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<SereinProjectData> GetProjectInfoAsync()
|
||||
public Task<SereinProjectData> 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
|
||||
/// </summary>
|
||||
/// <param name="dllPath"></param>
|
||||
/// <returns></returns>
|
||||
[AutoSocketHandle]
|
||||
// [AutoSocketHandle]
|
||||
public void LoadDll(string dllPath)
|
||||
{
|
||||
LoadDllNodeInfo(dllPath);
|
||||
@@ -766,11 +785,10 @@ namespace Serein.NodeFlow.Env
|
||||
/// <param name="nodeControlType"></param>
|
||||
/// <param name="position"></param>
|
||||
/// <param name="methodDetailsInfo">如果是表达式节点条件节点,该项为null</param>
|
||||
public async Task<NodeInfo?> CreateNodeAsync(NodeControlType nodeControlType, PositionOfUI position, MethodDetailsInfo? methodDetailsInfo = null)
|
||||
public Task<NodeInfo> 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<NodeInfo>(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
|
||||
/// </summary>
|
||||
/// <param name="nodeGuid"></param>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
public void RemoveNode(string nodeGuid)
|
||||
public async Task<bool> 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -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
|
||||
/// <param name="toNodeGuid">目标节点Guid</param>
|
||||
/// <param name="connectionType">连接关系</param>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
public void RemoveConnect(string fromNodeGuid, string toNodeGuid, ConnectionType connectionType)
|
||||
public async Task<bool> 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)));
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -978,12 +1002,13 @@ namespace Serein.NodeFlow.Env
|
||||
/// <param name="nodeGuid">被中断的目标节点Guid</param>
|
||||
/// <param name="interruptClass">中断级别</param>
|
||||
/// <returns>操作是否成功</returns>
|
||||
public async Task<bool> SetNodeInterruptAsync(string nodeGuid, InterruptClass interruptClass)
|
||||
public Task<bool> 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
|
||||
/// <param name="key">如果是节点,传入Guid;如果是对象,传入类型FullName</param>
|
||||
/// <param name="expression">合法的条件表达式</param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> AddInterruptExpressionAsync(string key, string expression)
|
||||
public Task<bool> 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<string>();
|
||||
exps.Add(expression);
|
||||
dictMonitorObjExpInterrupt.TryAdd(key, exps);
|
||||
return true;
|
||||
}
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1073,19 +1103,41 @@ namespace Serein.NodeFlow.Env
|
||||
/// <param name="key"></param>
|
||||
/// <param name="exps"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<(bool, string[])> CheckObjMonitorStateAsync(string key)
|
||||
public Task<(bool, string[])> CheckObjMonitorStateAsync(string key)
|
||||
{
|
||||
if (string.IsNullOrEmpty(key))
|
||||
return (false, Array.Empty<string>());
|
||||
var isMonitor = dictMonitorObjExpInterrupt.TryGetValue(key, out var exps);
|
||||
if (exps is null)
|
||||
{
|
||||
return (isMonitor, Array.Empty<string>());
|
||||
var data = (false, Array.Empty<string>());
|
||||
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<string>());
|
||||
return Task.FromResult(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
var data = (isMonitor, exps.ToArray());
|
||||
return Task.FromResult(data);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
//if (exps is null)
|
||||
//{
|
||||
// var data = (isMonitor, Array.Empty<string>());
|
||||
// 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
|
||||
/// <param name="toNodeGuid">目标节点Model</param>
|
||||
/// <param name="connectionType">连接关系</param>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
private void RemoteConnect(NodeModelBase fromNode, NodeModelBase toNode, ConnectionType connectionType)
|
||||
private async Task<bool> 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<RegisterSequence, List<Type>>, List<MethodDetails>) LoadAssembly(string dllPath)
|
||||
@@ -1377,11 +1448,11 @@ namespace Serein.NodeFlow.Env
|
||||
/// <param name="fromNode">起始节点</param>
|
||||
/// <param name="toNode">目标节点</param>
|
||||
/// <param name="connectionType">连接关系</param>
|
||||
private Task<bool> ConnectNode(NodeModelBase fromNode, NodeModelBase toNode, ConnectionType connectionType)
|
||||
private async Task<bool> 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -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)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1465,7 +1543,11 @@ namespace Serein.NodeFlow.Env
|
||||
/// <param name="msg"></param>
|
||||
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
|
||||
/// <param name="nodeGuid"></param>
|
||||
public void NodeLocated(string nodeGuid)
|
||||
{
|
||||
OnNodeLocated?.Invoke(new NodeLocatedEventArgs(nodeGuid));
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
UIContextOperation?.Invoke(() => OnNodeLocated?.Invoke(new NodeLocatedEventArgs(nodeGuid)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -67,6 +67,7 @@ namespace Serein.NodeFlow.Env
|
||||
/// </summary>
|
||||
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<bool> 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<bool> RemoveNodeAsync(string nodeGuid)
|
||||
{
|
||||
currentFlowEnvironment.RemoveNode(nodeGuid);
|
||||
return await currentFlowEnvironment.RemoveNodeAsync(nodeGuid);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException">超时触发</exception>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -49,32 +51,32 @@ namespace Serein.NodeFlow.Env
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException">超时触发</exception>
|
||||
public async Task<TResult> SendAndWaitDataAsync<TResult>(string signal, object? senddata = null, int debounceTimeInMs = 50)
|
||||
public async Task<TResult> SendAndWaitDataAsync<TResult>(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<TResult>(signal);
|
||||
#if DEBUG
|
||||
|
||||
if (DebounceHelper.CanExecute(signal, debounceTimeInMs))
|
||||
{
|
||||
_ = SendCommandAsync.Invoke(signal, senddata);
|
||||
return await remoteFlowEnvironment.WaitData<TResult>(signal);
|
||||
//if (DebounceHelper.CanExecute(signal, overtimeInMs))
|
||||
//{
|
||||
// _ = SendCommandAsync.Invoke(signal, sendData);
|
||||
// return await remoteFlowEnvironment.WaitData<TResult>(signal);
|
||||
|
||||
// //(var type, var result) = await remoteFlowEnvironment.WaitDataWithTimeoutAsync<TResult>(signal, TimeSpan.FromSeconds(150));
|
||||
// //if (type == TriggerType.Overtime)
|
||||
// //{
|
||||
// // throw new NotImplementedException("超时触发");
|
||||
// //}
|
||||
// //else
|
||||
// //{
|
||||
// // return result;
|
||||
// //}
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// return default;
|
||||
//}
|
||||
|
||||
//(var type, var result) = await remoteFlowEnvironment.WaitDataWithTimeoutAsync<TResult>(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);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
@@ -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
|
||||
|
||||
}
|
||||
|
||||
@@ -184,13 +184,14 @@ namespace Serein.NodeFlow.Env
|
||||
/// <summary>
|
||||
/// 从远程环境运行选定的节点
|
||||
/// </summary>
|
||||
/// <param name="startNodeGuid"></param>
|
||||
/// <param name="nodeGuid"></param>
|
||||
/// <returns></returns>
|
||||
[AutoSocketHandle(ThemeValue = EnvMsgTheme.StartFlowInSelectNode)]
|
||||
private async Task StartAsyncInSelectNode(string startNodeGuid)
|
||||
private async Task StartAsyncInSelectNode(string nodeGuid)
|
||||
{
|
||||
await environment.StartAsyncInSelectNode(startNodeGuid);
|
||||
await environment.StartAsyncInSelectNode(nodeGuid);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 结束流程
|
||||
/// </summary>
|
||||
@@ -321,9 +322,15 @@ namespace Serein.NodeFlow.Env
|
||||
/// <param name="nodeGuid"></param>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
[AutoSocketHandle(ThemeValue = EnvMsgTheme.RemoveNode)]
|
||||
public void RemoveNode(string nodeGuid)
|
||||
public async Task<object> 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
|
||||
/// <param name="toNodeGuid">目标节点</param>
|
||||
/// <param name="connectionType">连接关系</param>
|
||||
[AutoSocketHandle(ThemeValue = EnvMsgTheme.ConnectNode)]
|
||||
public void ConnectNode(string fromNodeGuid, string toNodeGuid, ConnectionType connectionType)
|
||||
public async Task<object> ConnectNode(string fromNodeGuid, string toNodeGuid, string connectionType)
|
||||
{
|
||||
environment.ConnectNodeAsync(fromNodeGuid, toNodeGuid, connectionType);
|
||||
if (!EnumHelper.TryConvertEnum<ConnectionType>(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
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -347,9 +366,21 @@ namespace Serein.NodeFlow.Env
|
||||
/// <param name="connectionType">连接关系</param>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
[AutoSocketHandle(ThemeValue = EnvMsgTheme.RemoveConnect)]
|
||||
public void RemoveConnect(string fromNodeGuid, string toNodeGuid, ConnectionType connectionType)
|
||||
public async Task<object> RemoveConnect(string fromNodeGuid, string toNodeGuid, string connectionType)
|
||||
{
|
||||
environment.RemoveConnect(fromNodeGuid, toNodeGuid, connectionType);
|
||||
if (!EnumHelper.TryConvertEnum<ConnectionType>(connectionType, out var tmpConnectionType))
|
||||
{
|
||||
return new
|
||||
{
|
||||
state = false
|
||||
};
|
||||
}
|
||||
|
||||
var result = await environment.RemoveConnectAsync(fromNodeGuid, toNodeGuid, tmpConnectionType);
|
||||
return new
|
||||
{
|
||||
state = result
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -18,9 +18,11 @@ namespace Serein.NodeFlow.Env
|
||||
/// <summary>
|
||||
/// 连接到远程环境后切换到的环境接口实现
|
||||
/// </summary>
|
||||
/// <param name="webSocketClient">连接到远程环境的客户端</param>
|
||||
public RemoteFlowEnvironment(RemoteEnvControl RemoteEnvControl)
|
||||
/// <param name="RemoteEnvControl">连接到远程环境后,本地环境自动切换到对应的环境实体</param>
|
||||
/// <param name="uIContextOperation">远程环境下需要操作UI线程时,所提供的线程上下文封装工具</param>
|
||||
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<string, MethodDetails> MethodDetailss = [];
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 环境加载的节点集合
|
||||
/// 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<bool> ConnectNodeAsync(string fromNodeGuid, string toNodeGuid, ConnectionType connectionType)
|
||||
{
|
||||
//_ = RemoteEnv.SendAsync(EnvMsgTheme.ConnectNode, new
|
||||
//{
|
||||
// fromNodeGuid,
|
||||
// toNodeGuid,
|
||||
// connectionType = connectionType.ToString(),
|
||||
//});
|
||||
var result = await msgClient.SendAndWaitDataAsync<bool>(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<bool> RemoveConnectAsync(string fromNodeGuid, string toNodeGuid, ConnectionType connectionType)
|
||||
{
|
||||
_ = msgClient.SendAsync(EnvMsgTheme.RemoveConnect, new
|
||||
var result = await msgClient.SendAndWaitDataAsync<bool>(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<bool> RemoveNodeAsync(string nodeGuid)
|
||||
{
|
||||
_ = msgClient.SendAsync(EnvMsgTheme.RemoveNode, new
|
||||
var result = await msgClient.SendAndWaitDataAsync<bool>(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,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<Version>1.0.14</Version>
|
||||
<Version>1.0.16</Version>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 初始化生成器,定义需要执行的生成逻辑。
|
||||
/// </summary>
|
||||
@@ -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(" /// <summary>");
|
||||
sb.AppendLine(" /// 略");
|
||||
sb.AppendLine(" /// <para>此事件为自动生成</para>");
|
||||
sb.AppendLine(" /// </summary>");
|
||||
sb.AppendLine(" public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;");
|
||||
|
||||
sb.AppendLine(" /// <summary>");
|
||||
sb.AppendLine(" /// 略");
|
||||
sb.AppendLine(" /// <para>此方法为自动生成</para>");
|
||||
sb.AppendLine(" /// </summary>");
|
||||
sb.AppendLine(" /// <param name=\"propertyName\"></param>");
|
||||
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(); // 返回生成的代码
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取类所在的命名空间。
|
||||
/// </summary>
|
||||
@@ -198,7 +246,19 @@ namespace Serein.Library.MyGenerator
|
||||
return namespaceDeclaration?.Name.ToString() ?? "GlobalNamespace";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private void SetterIsProtection()
|
||||
{
|
||||
|
||||
}
|
||||
private void SetterNotIsProtection()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<IsRoslynComponent>true</IsRoslynComponent>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.11.0" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
<!--<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.11.0" />
|
||||
</ItemGroup>-->
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,38 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<IsRoslynComponent>true</IsRoslynComponent>
|
||||
<BaseOutputPath>D:\Project\C#\DynamicControl\SereinFlow\.Output</BaseOutputPath>
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
<Title>SereinFow</Title>
|
||||
<Description>基础依赖必须添加项,用于生成NodeModel部分的依赖实体代码</Description>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
<RepositoryUrl>https://github.com/fhhyyp/serein-flow</RepositoryUrl>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.11.0" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
<!--<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.11.0" />
|
||||
</ItemGroup>-->
|
||||
<ItemGroup>
|
||||
<None Include="..\LICENSE">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath>\</PackagePath>
|
||||
</None>
|
||||
<None Include="..\README.md">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath>\</PackagePath>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -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
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
</MenuItem>
|
||||
<MenuItem Header="调试">
|
||||
<MenuItem Header="运行(从起始节点)" Click="ButtonDebugRun_Click"></MenuItem>
|
||||
<MenuItem Header="运行(从选定节点)" Click="ButtonDebugFlipflopNode_Click"></MenuItem>
|
||||
<MenuItem Header="运行(从选定节点)" Click="ButtonStartFlowInSelectNode_Click"></MenuItem>
|
||||
<MenuItem Header="结束流程" Click="ButtonDebugFlipflopNode_Click"></MenuItem>
|
||||
</MenuItem>
|
||||
<MenuItem Header="视图">
|
||||
|
||||
@@ -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
|
||||
/// </summary>
|
||||
private void FlowEnvironment_DllLoadEvent(LoadDllEventArgs eventArgs)
|
||||
{
|
||||
this.Dispatcher.Invoke(() => {
|
||||
NodeLibrary nodeLibrary = eventArgs.NodeLibrary;
|
||||
List<MethodDetailsInfo> methodDetailss = eventArgs.MethodDetailss;
|
||||
NodeLibrary nodeLibrary = eventArgs.NodeLibrary;
|
||||
List<MethodDetailsInfo> 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<Library.NodeType>(methodDetailsInfo.NodeType, out var nodeType))
|
||||
{
|
||||
if(!EnumHelper.TryConvertEnum<Library.NodeType>(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); // 将控件添加到界面上显示
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -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();
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 节点移除事件
|
||||
/// </summary>
|
||||
/// <param name="eventArgs"></param>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -476,61 +456,57 @@ namespace Serein.Workbench
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
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<ActionNodeControl, ActionNodeControlViewModel>(nodeModelBase), //typeof(ActionNodeControl),
|
||||
NodeControlType.Flipflop => CreateNodeControl<FlipflopNodeControl, FlipflopNodeControlViewModel>(nodeModelBase),
|
||||
NodeControlType.ExpCondition => CreateNodeControl<ConditionNodeControl, ConditionNodeControlViewModel>(nodeModelBase),
|
||||
NodeControlType.ExpOp => CreateNodeControl<ExpOpNodeControl, ExpOpNodeViewModel>(nodeModelBase),
|
||||
NodeControlType.ConditionRegion => CreateNodeControl<ConditionRegionControl, ConditionRegionNodeControlViewModel>(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<ActionNodeControl, ActionNodeControlViewModel>(nodeModelBase), //typeof(ActionNodeControl),
|
||||
NodeControlType.Flipflop => CreateNodeControl<FlipflopNodeControl, FlipflopNodeControlViewModel>(nodeModelBase),
|
||||
NodeControlType.ExpCondition => CreateNodeControl<ConditionNodeControl, ConditionNodeControlViewModel>(nodeModelBase),
|
||||
NodeControlType.ExpOp => CreateNodeControl<ExpOpNodeControl, ExpOpNodeViewModel>(nodeModelBase),
|
||||
NodeControlType.ConditionRegion => CreateNodeControl<ConditionRegionControl, ConditionRegionNodeControlViewModel>(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
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -540,26 +516,23 @@ namespace Serein.Workbench
|
||||
/// <param name="newNodeGuid"></param>
|
||||
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
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
private void FlowEnvironment_OnIOCMembersChanged(IOCMembersChangedEventArgs eventArgs)
|
||||
{
|
||||
this.Dispatcher.Invoke(() =>
|
||||
{
|
||||
IOCObjectViewer.AddDependenciesInstance(eventArgs.Key, eventArgs.Instance);
|
||||
});
|
||||
IOCObjectViewer.AddDependenciesInstance(eventArgs.Key, eventArgs.Instance);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -678,56 +642,52 @@ namespace Serein.Workbench
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
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);
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -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
|
||||
/// <param name="position"></param>
|
||||
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); // 配置节点事件
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -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<ConditionRegionControl>(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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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 的通知事件
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 对应的节点实体类
|
||||
/// </summary>
|
||||
internal NodeModelBase Node { get; }
|
||||
internal NodeModelBase NodeModel { get; }
|
||||
|
||||
|
||||
private bool isSelect;
|
||||
@@ -37,12 +39,12 @@ namespace Serein.Workbench.Node.ViewModel
|
||||
/// </summary>
|
||||
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
|
||||
/// </summary>
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="propertyName"></param>
|
||||
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public void Selected()
|
||||
{
|
||||
IsSelect = true;
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public void CancelSelect()
|
||||
{
|
||||
IsSelect = false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace Serein.Workbench.Node.View
|
||||
/// <param name="node"></param>
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user