mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-05-03 05:41:27 +08:00
修改了很多
This commit is contained in:
@@ -1,13 +1,10 @@
|
|||||||
|
|
||||||
using Serein.Library;
|
using Serein.Library;
|
||||||
using Serein.Library.Api;
|
using Serein.Library.Api;
|
||||||
using Serein.Library.Attributes;
|
|
||||||
using Serein.Library.Enums;
|
|
||||||
using Serein.Library.Network.WebSocketCommunication;
|
using Serein.Library.Network.WebSocketCommunication;
|
||||||
using System.Security.Cryptography.X509Certificates;
|
using System.Security.Cryptography.X509Certificates;
|
||||||
using Serein.NodeFlow;
|
using Serein.NodeFlow;
|
||||||
using Serein.Library.Core.NodeFlow;
|
using Serein.Library.Core.NodeFlow;
|
||||||
using Serein.Library.NodeFlow.Tool;
|
|
||||||
using Serein.Library.Utils;
|
using Serein.Library.Utils;
|
||||||
using Serein.FlowRemoteManagement.Model;
|
using Serein.FlowRemoteManagement.Model;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|||||||
@@ -13,6 +13,11 @@ namespace Serein.FlowStartTool
|
|||||||
{
|
{
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
|
#if true
|
||||||
|
args = [@"F:\临时\project\linux\project.dnf"];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
Console.WriteLine("Hello :) ");
|
Console.WriteLine("Hello :) ");
|
||||||
Console.WriteLine($"args : {string.Join(" , ", args)}");
|
Console.WriteLine($"args : {string.Join(" , ", args)}");
|
||||||
string filePath;
|
string filePath;
|
||||||
@@ -57,10 +62,10 @@ namespace Serein.FlowStartTool
|
|||||||
}
|
}
|
||||||
|
|
||||||
IsRuning = true;
|
IsRuning = true;
|
||||||
StartFlow(flowProjectData, fileDataPath).GetAwaiter().GetResult();
|
_ = StartFlow(flowProjectData, fileDataPath);
|
||||||
while (IsRuning)
|
while (IsRuning)
|
||||||
{
|
{
|
||||||
|
Console.ReadKey();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,13 +93,12 @@ namespace Serein.FlowStartTool
|
|||||||
// this.window = window;
|
// this.window = window;
|
||||||
//}
|
//}
|
||||||
|
|
||||||
Env = new FlowEnvironmentDecorator(uIContextOperation); // Linux 环境下没有线程上下文(暂时没有写)
|
Env = new FlowEnvironmentDecorator(uIContextOperation);
|
||||||
Env.LoadProject(new FlowEnvInfo { Project = flowProjectData }, fileDataPath); // 加载项目
|
Env.LoadProject(new FlowEnvInfo { Project = flowProjectData }, fileDataPath); // 加载项目
|
||||||
await Env.StartRemoteServerAsync(7525); // 启动 web socket 监听远程请求
|
await Env.StartRemoteServerAsync(7525); // 启动 web socket 监听远程请求
|
||||||
|
|
||||||
//await Env.StartAsync();
|
//await Env.StartAsync();
|
||||||
|
|
||||||
|
|
||||||
IsRuning = false;
|
IsRuning = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"profiles": {
|
"profiles": {
|
||||||
"Serein.FlowStartTool": {
|
|
||||||
"commandName": "Project"
|
|
||||||
},
|
|
||||||
"配置文件 1": {
|
"配置文件 1": {
|
||||||
"commandName": "DebugRoslynComponent"
|
"commandName": "DebugRoslynComponent"
|
||||||
|
},
|
||||||
|
"Serein.FlowStartTool": {
|
||||||
|
"commandName": "Project"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9,34 +9,34 @@
|
|||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<AssemblyName>starter</AssemblyName>
|
<AssemblyName>starter</AssemblyName>
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
<!--<IsRoslynComponent>true</IsRoslynComponent>-->
|
<!--<IsRoslynComponent>true</IsRoslynComponent>-->
|
||||||
<!--<GenerateDocumentationFile>true</GenerateDocumentationFile>-->
|
<!--<GenerateDocumentationFile>true</GenerateDocumentationFile>-->
|
||||||
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net8.0|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net8.0|AnyCPU'">
|
||||||
|
<Optimize>False</Optimize>
|
||||||
|
<GenerateAssemblyInfo>True</GenerateAssemblyInfo>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net8.0|AnyCPU'">
|
||||||
|
<Optimize>False</Optimize>
|
||||||
|
<GenerateAssemblyInfo>True</GenerateAssemblyInfo>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Library.Core\Serein.Library.Core.csproj" />
|
||||||
|
<ProjectReference Include="..\Library\Serein.Library.csproj" />
|
||||||
|
<ProjectReference Include="..\NodeFlow\Serein.NodeFlow.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!--<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net8.0|AnyCPU'">
|
||||||
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
|
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net8.0|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net8.0|AnyCPU'">
|
||||||
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
|
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
|
||||||
</PropertyGroup>
|
</PropertyGroup>-->
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup><!--<ProjectReference Include="..\Library\Serein.Library.csproj" />
|
|
||||||
<ProjectReference Include="..\NodeFlow\Serein.NodeFlow.csproj" />-->
|
|
||||||
|
|
||||||
<PackageReference Include="Serein.Library" Version="1.0.17" />
|
|
||||||
<PackageReference Include="Serein.Library.NodeGenerator" Version="1.0.0" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<!--<ProjectReference Include="..\Serein.Library.MyGenerator\Serein.Library.NodeGenerator.csproj" OutputItemType="Analyzer" />-->
|
|
||||||
|
|
||||||
<ProjectReference Include="..\NodeFlow\Serein.NodeFlow.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -47,6 +47,10 @@ namespace Serein.Library.Core.NodeFlow
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public object? GetFlowData(string nodeGuid)
|
public object? GetFlowData(string nodeGuid)
|
||||||
{
|
{
|
||||||
|
if (string.IsNullOrEmpty(nodeGuid))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
if(dictNodeFlowData.TryGetValue(nodeGuid,out var data))
|
if(dictNodeFlowData.TryGetValue(nodeGuid,out var data))
|
||||||
{
|
{
|
||||||
return data;
|
return data;
|
||||||
@@ -70,8 +74,18 @@ namespace Serein.Library.Core.NodeFlow
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 结束流程
|
/// 结束流程
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void EndCurrentBranch()
|
public void Exit()
|
||||||
{
|
{
|
||||||
|
foreach (var nodeObj in dictNodeFlowData.Values)
|
||||||
|
{
|
||||||
|
if (nodeObj is not null)
|
||||||
|
{
|
||||||
|
if (typeof(IDisposable).IsAssignableFrom(nodeObj?.GetType()) && nodeObj is IDisposable disposable)
|
||||||
|
{
|
||||||
|
disposable?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
this.dictNodeFlowData?.Clear();
|
this.dictNodeFlowData?.Clear();
|
||||||
RunState = RunState.Completion;
|
RunState = RunState.Completion;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Version>1.0.14</Version>
|
<Version>1.0.15</Version>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Serein.Library.Api;
|
using Serein.Library.Api;
|
||||||
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
|
|
||||||
namespace Serein.Library.Framework.NodeFlow
|
namespace Serein.Library.Framework.NodeFlow
|
||||||
@@ -46,8 +47,6 @@ namespace Serein.Library.Framework.NodeFlow
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public object GetFlowData(string nodeGuid)
|
public object GetFlowData(string nodeGuid)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
if (dictNodeFlowData.TryGetValue(nodeGuid, out var data))
|
if (dictNodeFlowData.TryGetValue(nodeGuid, out var data))
|
||||||
{
|
{
|
||||||
return data;
|
return data;
|
||||||
@@ -71,8 +70,18 @@ namespace Serein.Library.Framework.NodeFlow
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 结束流程
|
/// 结束流程
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void EndCurrentBranch()
|
public void Exit()
|
||||||
{
|
{
|
||||||
|
foreach (var nodeObj in dictNodeFlowData.Values)
|
||||||
|
{
|
||||||
|
if (nodeObj != null)
|
||||||
|
{
|
||||||
|
if (typeof(IDisposable).IsAssignableFrom(nodeObj?.GetType()) && nodeObj is IDisposable disposable)
|
||||||
|
{
|
||||||
|
disposable?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
this.dictNodeFlowData?.Clear();
|
this.dictNodeFlowData?.Clear();
|
||||||
RunState = RunState.Completion;
|
RunState = RunState.Completion;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,5 +34,5 @@ using System.Runtime.InteropServices;
|
|||||||
//通过使用 "*",如下所示:
|
//通过使用 "*",如下所示:
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
[assembly: AssemblyVersion("1.0.1.4")]
|
[assembly: AssemblyVersion("1.0.1.4")]
|
||||||
[assembly: AssemblyFileVersion("1.0.1.4")]
|
[assembly: AssemblyFileVersion("1.0.1.5")]
|
||||||
[assembly: NeutralResourcesLanguage("")]
|
[assembly: NeutralResourcesLanguage("")]
|
||||||
|
|||||||
@@ -42,7 +42,8 @@ namespace Serein.Library.Api
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 用以提前结束分支运行
|
/// 用以提前结束分支运行
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void EndCurrentBranch();
|
void Exit();
|
||||||
|
|
||||||
|
|
||||||
/*/// <summary>
|
/*/// <summary>
|
||||||
/// 定时循环触发
|
/// 定时循环触发
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
|
|
||||||
|
|
||||||
|
using Serein.Library.FlowNode;
|
||||||
using Serein.Library.Utils;
|
using Serein.Library.Utils;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -176,6 +177,15 @@ namespace Serein.Library.Api
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
Remote,
|
Remote,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 更改方法调用关系
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fromNodeGuid"></param>
|
||||||
|
/// <param name="toNodeGuid"></param>
|
||||||
|
/// <param name="junctionOfConnectionType"></param>
|
||||||
|
/// <param name="connectionInvokeType"></param>
|
||||||
|
/// <param name="changeType"></param>
|
||||||
public NodeConnectChangeEventArgs(string fromNodeGuid,
|
public NodeConnectChangeEventArgs(string fromNodeGuid,
|
||||||
string toNodeGuid,
|
string toNodeGuid,
|
||||||
JunctionOfConnectionType junctionOfConnectionType, // 指示需要创建什么类型的连接线
|
JunctionOfConnectionType junctionOfConnectionType, // 指示需要创建什么类型的连接线
|
||||||
@@ -189,6 +199,15 @@ namespace Serein.Library.Api
|
|||||||
this.JunctionOfConnectionType = junctionOfConnectionType;
|
this.JunctionOfConnectionType = junctionOfConnectionType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 更改参数传递关系
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fromNodeGuid"></param>
|
||||||
|
/// <param name="toNodeGuid"></param>
|
||||||
|
/// <param name="junctionOfConnectionType"></param>
|
||||||
|
/// <param name="argIndex"></param>
|
||||||
|
/// <param name="connectionArgSourceType"></param>
|
||||||
|
/// <param name="changeType"></param>
|
||||||
public NodeConnectChangeEventArgs(string fromNodeGuid,
|
public NodeConnectChangeEventArgs(string fromNodeGuid,
|
||||||
string toNodeGuid,
|
string toNodeGuid,
|
||||||
JunctionOfConnectionType junctionOfConnectionType, // 指示需要创建什么类型的连接线
|
JunctionOfConnectionType junctionOfConnectionType, // 指示需要创建什么类型的连接线
|
||||||
@@ -228,6 +247,9 @@ namespace Serein.Library.Api
|
|||||||
/// 节点对应的方法入参所需参数来源
|
/// 节点对应的方法入参所需参数来源
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ConnectionArgSourceType ConnectionArgSourceType { get; protected set; }
|
public ConnectionArgSourceType ConnectionArgSourceType { get; protected set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 第几个参数
|
||||||
|
/// </summary>
|
||||||
public int ArgIndex { get; protected set; }
|
public int ArgIndex { get; protected set; }
|
||||||
|
|
||||||
|
|
||||||
@@ -350,17 +372,19 @@ namespace Serein.Library.Api
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class NodeInterruptStateChangeEventArgs : FlowEventArgs
|
public class NodeInterruptStateChangeEventArgs : FlowEventArgs
|
||||||
{
|
{
|
||||||
public NodeInterruptStateChangeEventArgs(string nodeGuid, InterruptClass @class)
|
public NodeInterruptStateChangeEventArgs(string nodeGuid,bool isInterrupt)
|
||||||
{
|
{
|
||||||
NodeGuid = nodeGuid;
|
NodeGuid = nodeGuid;
|
||||||
Class = @class;
|
// Class = @class;
|
||||||
|
IsInterrupt = isInterrupt;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 中断的节点Guid
|
/// 中断的节点Guid
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string NodeGuid { get; protected set; }
|
public string NodeGuid { get; protected set; }
|
||||||
public InterruptClass Class { get; protected set; }
|
public bool IsInterrupt { get; protected set; }
|
||||||
|
// public InterruptClass Class { get; protected set; }
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 节点触发了中断事件参数
|
/// 节点触发了中断事件参数
|
||||||
@@ -638,7 +662,7 @@ namespace Serein.Library.Api
|
|||||||
/// <param name="addres">远程环境地址</param>
|
/// <param name="addres">远程环境地址</param>
|
||||||
/// <param name="port">远程环境端口</param>
|
/// <param name="port">远程环境端口</param>
|
||||||
/// <param name="token">密码</param>
|
/// <param name="token">密码</param>
|
||||||
Task<(bool, RemoteEnvControl)> ConnectRemoteEnv(string addres,int port, string token);
|
Task<(bool, RemoteMsgUtil)> ConnectRemoteEnv(string addres,int port, string token);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 退出远程环境
|
/// 退出远程环境
|
||||||
@@ -705,30 +729,53 @@ namespace Serein.Library.Api
|
|||||||
/// <param name="toNodeGuid">目标节点Guid</param>
|
/// <param name="toNodeGuid">目标节点Guid</param>
|
||||||
/// <param name="fromNodeJunctionType">起始节点控制点</param>
|
/// <param name="fromNodeJunctionType">起始节点控制点</param>
|
||||||
/// <param name="toNodeJunctionType">目标节点控制点</param>
|
/// <param name="toNodeJunctionType">目标节点控制点</param>
|
||||||
/// <param name="connectionType">决定了方法执行后的后继行为</param>
|
/// <param name="invokeType">决定了方法执行后的后继行为</param>
|
||||||
/// <param name="argIndex">决定了方法入参来源</param>
|
Task<bool> ConnectInvokeNodeAsync(string fromNodeGuid,
|
||||||
Task<bool> ConnectNodeAsync(string fromNodeGuid,
|
|
||||||
string toNodeGuid,
|
string toNodeGuid,
|
||||||
JunctionType fromNodeJunctionType,
|
JunctionType fromNodeJunctionType,
|
||||||
JunctionType toNodeJunctionType,
|
JunctionType toNodeJunctionType,
|
||||||
ConnectionInvokeType connectionType,
|
ConnectionInvokeType invokeType);
|
||||||
int argIndex);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
/// 在两个节点之间创建连接关系
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fromNodeGuid">起始节点Guid</param>
|
||||||
|
/// <param name="toNodeGuid">目标节点Guid</param>
|
||||||
|
/// <param name="fromNodeJunctionType">起始节点控制点</param>
|
||||||
|
/// <param name="toNodeJunctionType">目标节点控制点</param>
|
||||||
|
/// <param name="argSourceType">决定了方法参数来源</param>
|
||||||
|
/// <param name="argIndex">设置第几个参数</param>
|
||||||
|
Task<bool> ConnectArgSourceNodeAsync(string fromNodeGuid,
|
||||||
|
string toNodeGuid,
|
||||||
|
JunctionType fromNodeJunctionType,
|
||||||
|
JunctionType toNodeJunctionType,
|
||||||
|
ConnectionArgSourceType argSourceType,
|
||||||
|
int argIndex);
|
||||||
|
/// <summary>
|
||||||
/// 创建节点/区域/基础控件
|
/// 创建节点/区域/基础控件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="nodeType">节点/区域/基础控件类型</param>
|
/// <param name="nodeType">节点/区域/基础控件类型</param>
|
||||||
/// <param name="position">节点在画布上的位置(</param>
|
/// <param name="position">节点在画布上的位置(</param>
|
||||||
/// <param name="methodDetailsInfo">节点绑定的方法说明(</param>
|
/// <param name="methodDetailsInfo">节点绑定的方法说明</param>
|
||||||
Task<NodeInfo> CreateNodeAsync(NodeControlType nodeType, PositionOfUI position, MethodDetailsInfo methodDetailsInfo = null);
|
Task<NodeInfo> CreateNodeAsync(NodeControlType nodeType, PositionOfUI position, MethodDetailsInfo methodDetailsInfo = null);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 移除两个节点之间的连接关系
|
/// 移除两个节点之间的方法调用关系
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="fromNodeGuid">起始节点</param>
|
/// <param name="fromNodeGuid">起始节点</param>
|
||||||
/// <param name="toNodeGuid">目标节点</param>
|
/// <param name="toNodeGuid">目标节点</param>
|
||||||
/// <param name="connectionType">连接类型</param>
|
/// <param name="connectionType">连接类型</param>
|
||||||
Task<bool> RemoveConnectAsync(string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType);
|
Task<bool> RemoveConnectInvokeAsync(string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 移除连接节点之间参数传递的关系
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fromNodeGuid">起始节点Guid</param>
|
||||||
|
/// <param name="toNodeGuid">目标节点Guid</param>
|
||||||
|
/// <param name="argIndex">连接到第几个参数</param>
|
||||||
|
/// <param name="connectionArgSourceType">参数来源类型</param>
|
||||||
|
Task<bool> RemoveConnectArgSourceAsync(string fromNodeGuid, string toNodeGuid, int argIndex);
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 移除节点/区域/基础控件
|
/// 移除节点/区域/基础控件
|
||||||
@@ -750,12 +797,12 @@ namespace Serein.Library.Api
|
|||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 设置节点中断级别
|
/// 设置节点中断
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="nodeGuid">被中断的节点Guid</param>
|
/// <param name="nodeGuid">更改中断状态的节点Guid</param>
|
||||||
/// <param name="interruptClass">新的中断级别</param>
|
/// <param name="isInterrup">是否中断</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<bool> SetNodeInterruptAsync(string nodeGuid, InterruptClass interruptClass);
|
Task<bool> SetNodeInterruptAsync(string nodeGuid,bool isInterrup);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 添加作用于某个对象的中断表达式
|
/// 添加作用于某个对象的中断表达式
|
||||||
|
|||||||
78
Library/Extension/SereinExtension.cs
Normal file
78
Library/Extension/SereinExtension.cs
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Serein.Library
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 拓展方法
|
||||||
|
/// </summary>
|
||||||
|
public static partial class SereinExtension
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 判断连接类型
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="start"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static JunctionOfConnectionType ToConnectyionType(this JunctionType start)
|
||||||
|
{
|
||||||
|
if (start == JunctionType.Execute
|
||||||
|
|| start == JunctionType.NextStep)
|
||||||
|
{
|
||||||
|
return JunctionOfConnectionType.Invoke;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return JunctionOfConnectionType.Arg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 判断是否运行连接
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="start"></param>
|
||||||
|
/// <param name="end"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static bool IsCanConnection(this JunctionType start,JunctionType end)
|
||||||
|
{
|
||||||
|
if(start == end)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var startType = start.ToConnectyionType();
|
||||||
|
if (startType == JunctionOfConnectionType.Invoke)
|
||||||
|
{
|
||||||
|
return (end == JunctionType.Execute && start == JunctionType.NextStep)
|
||||||
|
|| (start == JunctionType.Execute && end == JunctionType.NextStep);
|
||||||
|
}
|
||||||
|
else // if (startType == JunctionOfConnectionType.Arg)
|
||||||
|
{
|
||||||
|
return (end == JunctionType.ArgData && start == JunctionType.ReturnData)
|
||||||
|
|| (start == JunctionType.ArgData && end == JunctionType.ReturnData);
|
||||||
|
}
|
||||||
|
|
||||||
|
//var endType = end.ToConnectyionType();
|
||||||
|
//if (startType != endType
|
||||||
|
// || startType == JunctionOfConnectionType.None
|
||||||
|
// || endType == JunctionOfConnectionType.None)
|
||||||
|
//{
|
||||||
|
// return false;
|
||||||
|
//}
|
||||||
|
//else
|
||||||
|
//{
|
||||||
|
// if (startType == JunctionOfConnectionType.Invoke)
|
||||||
|
// {
|
||||||
|
|
||||||
|
// return end == JunctionType.NextStep;
|
||||||
|
// }
|
||||||
|
// else // if (startType == JunctionOfConnectionType.Arg)
|
||||||
|
// {
|
||||||
|
// return end == JunctionType.ReturnData;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using static Serein.Library.Utils.EmitHelper;
|
using static Serein.Library.Utils.EmitHelper;
|
||||||
@@ -14,6 +15,17 @@ namespace Serein.Library
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class DelegateDetails
|
public class DelegateDetails
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 根据方法信息构建Emit委托
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="methodInfo"></param>
|
||||||
|
public DelegateDetails(MethodInfo methodInfo)
|
||||||
|
{
|
||||||
|
var emitMethodType = EmitHelper.CreateDynamicMethod(methodInfo, out var emitDelegate);
|
||||||
|
_emitMethodType = emitMethodType;
|
||||||
|
_emitDelegate = emitDelegate;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 记录Emit委托
|
/// 记录Emit委托
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -21,8 +33,8 @@ namespace Serein.Library
|
|||||||
/// <param name="EmitDelegate"></param>
|
/// <param name="EmitDelegate"></param>
|
||||||
public DelegateDetails(EmitMethodType EmitMethodType, Delegate EmitDelegate)
|
public DelegateDetails(EmitMethodType EmitMethodType, Delegate EmitDelegate)
|
||||||
{
|
{
|
||||||
this._emitMethodType = EmitMethodType;
|
_emitMethodType = EmitMethodType;
|
||||||
this._emitDelegate = EmitDelegate;
|
_emitDelegate = EmitDelegate;
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 更新委托方法
|
/// 更新委托方法
|
||||||
@@ -56,7 +68,7 @@ namespace Serein.Library
|
|||||||
/// <returns>void方法自动返回null</returns>
|
/// <returns>void方法自动返回null</returns>
|
||||||
public async Task<object> InvokeAsync(object instance, object[] args)
|
public async Task<object> InvokeAsync(object instance, object[] args)
|
||||||
{
|
{
|
||||||
if(args is null)
|
if (args is null)
|
||||||
{
|
{
|
||||||
args = Array.Empty<object>();
|
args = Array.Empty<object>();
|
||||||
}
|
}
|
||||||
@@ -35,15 +35,16 @@ namespace Serein.Library
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 中断级别,暂时停止继续执行后继分支。
|
/// 中断级别,暂时停止继续执行后继分支。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[PropertyInfo]
|
//[PropertyInfo]
|
||||||
private InterruptClass _interruptClass = InterruptClass.None;
|
//private InterruptClass _interruptClass = InterruptClass.None;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 中断级别,暂时停止继续执行后继分支。
|
/// 中断级别,暂时停止继续执行后继分支。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[PropertyInfo(IsNotification = true)]
|
[PropertyInfo(IsNotification = true, CustomCode = "NodeModel?.Env?.SetNodeInterruptAsync(NodeModel?.Guid, value);")]
|
||||||
private bool _isInterrupt = false;
|
private bool _isInterrupt = false;
|
||||||
|
|
||||||
|
//private const string MyInteruptCode = "NodeModel?.Env?.SetNodeInterruptAsync(NodeModel?.Guid, value);"; // 添加到中断的自定义代码
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 取消中断的回调函数
|
/// 取消中断的回调函数
|
||||||
@@ -56,29 +57,30 @@ namespace Serein.Library
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[PropertyInfo]
|
[PropertyInfo]
|
||||||
private Func<Task<CancelType>> _getInterruptTask;
|
private Func<Task<CancelType>> _getInterruptTask;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 中断级别,暂时停止继续执行后继分支。
|
||||||
|
/// </summary>
|
||||||
|
//public enum InterruptClass
|
||||||
|
//{
|
||||||
|
// /// <summary>
|
||||||
|
// /// 不中断
|
||||||
|
// /// </summary>
|
||||||
|
// None,
|
||||||
|
// /// <summary>
|
||||||
|
// /// 分支中断,中断进入当前节点的分支。
|
||||||
|
// /// </summary>
|
||||||
|
// Branch,
|
||||||
|
// /// <summary>
|
||||||
|
// /// 全局中断,中断全局所有节点的运行。(暂未实现相关)
|
||||||
|
// /// </summary>
|
||||||
|
// Global,
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 中断级别,暂时停止继续执行后继分支。
|
|
||||||
/// </summary>
|
|
||||||
public enum InterruptClass
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 不中断
|
|
||||||
/// </summary>
|
|
||||||
None,
|
|
||||||
/// <summary>
|
|
||||||
/// 分支中断,中断进入当前节点的分支。
|
|
||||||
/// </summary>
|
|
||||||
Branch,
|
|
||||||
/// <summary>
|
|
||||||
/// 全局中断,中断全局所有节点的运行。(暂未实现相关)
|
|
||||||
/// </summary>
|
|
||||||
Global,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -85,9 +85,6 @@ namespace Serein.Library
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public abstract partial class NodeModelBase : IDynamicFlowNode
|
public abstract partial class NodeModelBase : IDynamicFlowNode
|
||||||
{
|
{
|
||||||
public NodeModelBase(IFlowEnvironment environment)
|
public NodeModelBase(IFlowEnvironment environment)
|
||||||
@@ -119,39 +116,40 @@ namespace Serein.Library
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 控制FlowData在同一时间只会被同一个线程更改。
|
/// 控制FlowData在同一时间只会被同一个线程更改。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly ReaderWriterLockSlim _flowDataLock = new ReaderWriterLockSlim();
|
//private readonly ReaderWriterLockSlim _flowDataLock = new ReaderWriterLockSlim();
|
||||||
private object _flowData;
|
//private object _flowData;
|
||||||
/// <summary>
|
///// <summary>
|
||||||
/// 当前传递数据(执行了节点对应的方法,才会存在值)。
|
///// 当前传递数据(执行了节点对应的方法,才会存在值)。
|
||||||
/// </summary>
|
///// </summary>
|
||||||
protected object FlowData
|
//protected object FlowData
|
||||||
{
|
//{
|
||||||
get
|
// get
|
||||||
{
|
// {
|
||||||
_flowDataLock.EnterReadLock();
|
// _flowDataLock.EnterReadLock();
|
||||||
try
|
// try
|
||||||
{
|
// {
|
||||||
return _flowData;
|
// return _flowData;
|
||||||
}
|
// }
|
||||||
finally
|
// finally
|
||||||
{
|
// {
|
||||||
_flowDataLock.ExitReadLock();
|
// _flowDataLock.ExitReadLock();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
set
|
// set
|
||||||
{
|
// {
|
||||||
_flowDataLock.EnterWriteLock();
|
// _flowDataLock.EnterWriteLock();
|
||||||
try
|
// try
|
||||||
{
|
// {
|
||||||
_flowData = value;
|
// _flowData = value;
|
||||||
}
|
// }
|
||||||
finally
|
// finally
|
||||||
{
|
// {
|
||||||
_flowDataLock.ExitWriteLock();
|
// _flowDataLock.ExitWriteLock();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -319,5 +317,5 @@ namespace Serein.Library
|
|||||||
//}
|
//}
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ namespace Serein.Library
|
|||||||
/// 获取节点参数
|
/// 获取节点参数
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public abstract Parameterdata[] GetParameterdatas();
|
public abstract ParameterData[] GetParameterdatas();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 导出为节点信息
|
/// 导出为节点信息
|
||||||
@@ -47,7 +47,7 @@ namespace Serein.Library
|
|||||||
var upstreamNodes = SuccessorNodes[ConnectionInvokeType.Upstream].Select(item => item.Guid);// 上游分支
|
var upstreamNodes = SuccessorNodes[ConnectionInvokeType.Upstream].Select(item => item.Guid);// 上游分支
|
||||||
|
|
||||||
// 生成参数列表
|
// 生成参数列表
|
||||||
Parameterdata[] parameterData = GetParameterdatas();
|
ParameterData[] parameterData = GetParameterdatas();
|
||||||
|
|
||||||
return new NodeInfo
|
return new NodeInfo
|
||||||
{
|
{
|
||||||
@@ -82,9 +82,13 @@ namespace Serein.Library
|
|||||||
{
|
{
|
||||||
for (int i = 0; i < nodeInfo.ParameterData.Length; i++)
|
for (int i = 0; i < nodeInfo.ParameterData.Length; i++)
|
||||||
{
|
{
|
||||||
Parameterdata pd = nodeInfo.ParameterData[i];
|
var mdPd = this.MethodDetails.ParameterDetailss[i];
|
||||||
this.MethodDetails.ParameterDetailss[i].IsExplicitData = pd.State;
|
ParameterData pd = nodeInfo.ParameterData[i];
|
||||||
this.MethodDetails.ParameterDetailss[i].DataValue = pd.Value;
|
mdPd.IsExplicitData = pd.State;
|
||||||
|
mdPd.DataValue = pd.Value;
|
||||||
|
mdPd.ArgDataSourceType = EnumHelper.ConvertEnum<ConnectionArgSourceType>(pd.SourceType);
|
||||||
|
mdPd.ArgDataSourceNodeGuid = pd.SourceNodeGuid;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
@@ -93,13 +97,12 @@ namespace Serein.Library
|
|||||||
|
|
||||||
#region 调试中断
|
#region 调试中断
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 不再中断
|
/// 不再中断
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void CancelInterrupt()
|
public void CancelInterrupt()
|
||||||
{
|
{
|
||||||
this.DebugSetting.InterruptClass = InterruptClass.None;
|
this.DebugSetting.IsInterrupt = false;
|
||||||
DebugSetting.CancelInterruptCallback?.Invoke();
|
DebugSetting.CancelInterruptCallback?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,7 +168,7 @@ namespace Serein.Library
|
|||||||
NodeModelBase upstreamNode = upstreamNodes[index];
|
NodeModelBase upstreamNode = upstreamNodes[index];
|
||||||
if (!(upstreamNode is null) && upstreamNode.DebugSetting.IsEnable)
|
if (!(upstreamNode is null) && upstreamNode.DebugSetting.IsEnable)
|
||||||
{
|
{
|
||||||
if (upstreamNode.DebugSetting.InterruptClass != InterruptClass.None) // 执行触发前
|
if (upstreamNode.DebugSetting.IsInterrupt) // 执行触发前
|
||||||
{
|
{
|
||||||
var cancelType = await upstreamNode.DebugSetting.GetInterruptTask();
|
var cancelType = await upstreamNode.DebugSetting.GetInterruptTask();
|
||||||
await Console.Out.WriteLineAsync($"[{upstreamNode.MethodDetails?.MethodName}]中断已{cancelType},开始执行后继分支");
|
await Console.Out.WriteLineAsync($"[{upstreamNode.MethodDetails?.MethodName}]中断已{cancelType},开始执行后继分支");
|
||||||
@@ -220,7 +223,7 @@ namespace Serein.Library
|
|||||||
{
|
{
|
||||||
#region 调试中断
|
#region 调试中断
|
||||||
|
|
||||||
if (DebugSetting.InterruptClass != InterruptClass.None) // 执行触发检查是否需要中断
|
if (DebugSetting.IsInterrupt) // 执行触发检查是否需要中断
|
||||||
{
|
{
|
||||||
var cancelType = await this.DebugSetting.GetInterruptTask(); // 等待中断结束
|
var cancelType = await this.DebugSetting.GetInterruptTask(); // 等待中断结束
|
||||||
await Console.Out.WriteLineAsync($"[{this.MethodDetails?.MethodName}]中断已{cancelType},开始执行后继分支");
|
await Console.Out.WriteLineAsync($"[{this.MethodDetails?.MethodName}]中断已{cancelType},开始执行后继分支");
|
||||||
@@ -312,8 +315,9 @@ namespace Serein.Library
|
|||||||
}
|
}
|
||||||
|
|
||||||
object[] parameters = new object[md.ParameterDetailss.Length];
|
object[] parameters = new object[md.ParameterDetailss.Length];
|
||||||
var previousFlowData = nodeModel.PreviousNode?.FlowData; // 当前传递的数据
|
|
||||||
var previousDataType = previousFlowData?.GetType(); // 当前传递数据的类型
|
//var previousFlowData = nodeModel.PreviousNode?.FlowData; // 当前传递的数据
|
||||||
|
|
||||||
|
|
||||||
for (int i = 0; i < parameters.Length; i++)
|
for (int i = 0; i < parameters.Length; i++)
|
||||||
{
|
{
|
||||||
@@ -336,41 +340,48 @@ namespace Serein.Library
|
|||||||
object inputParameter; // 存放解析的临时参数
|
object inputParameter; // 存放解析的临时参数
|
||||||
if (ed.IsExplicitData) // 判断是否使用显示的输入参数
|
if (ed.IsExplicitData) // 判断是否使用显示的输入参数
|
||||||
{
|
{
|
||||||
if (ed.DataValue.StartsWith("@get", StringComparison.OrdinalIgnoreCase) && !(previousFlowData is null))
|
if (ed.DataValue.StartsWith("@get", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
|
var previousFlowData = context.GetFlowData(nodeModel?.PreviousNode?.Guid); // 当前传递的数据
|
||||||
// 执行表达式从上一节点获取对象
|
// 执行表达式从上一节点获取对象
|
||||||
inputParameter = SerinExpressionEvaluator.Evaluate(ed.DataValue, previousFlowData, out _);
|
inputParameter = SerinExpressionEvaluator.Evaluate(ed.DataValue, previousFlowData, out _);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// 使用输入的固定值
|
// 使用输入的固定值
|
||||||
inputParameter = ed.DataValue;
|
inputParameter = ed.DataValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (ed.ArgDataSourceType == ConnectionArgSourceType.GetPreviousNodeData)
|
if (ed.ArgDataSourceType == ConnectionArgSourceType.GetPreviousNodeData)
|
||||||
{
|
{
|
||||||
inputParameter = previousFlowData; // 使用运行时上一节点的返回值
|
inputParameter = context.GetFlowData(nodeModel?.PreviousNode?.Guid); // 当前传递的数据
|
||||||
}
|
}
|
||||||
else if (ed.ArgDataSourceType == ConnectionArgSourceType.GetPreviousNodeData)
|
else if (ed.ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeData)
|
||||||
{
|
{
|
||||||
// 获取指定节点的数据
|
// 获取指定节点的数据
|
||||||
// 如果指定节点没有被执行,会返回null
|
// 如果指定节点没有被执行,会返回null
|
||||||
// 如果执行过,会获取上一次执行结果作为预入参数据
|
// 如果执行过,会获取上一次执行结果作为预入参数据
|
||||||
inputParameter = ed.ArgDataSourceNodeMoels[i].FlowData;
|
inputParameter = context.GetFlowData(ed.ArgDataSourceNodeGuid);
|
||||||
}
|
}
|
||||||
else if (ed.ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeDataOfInvoke)
|
else if (ed.ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeDataOfInvoke)
|
||||||
{
|
{
|
||||||
// 立刻调用对应节点获取数据。
|
// 立刻调用对应节点获取数据。
|
||||||
var result = await ed.ArgDataSourceNodeMoels[i].InvokeAsync(nodeModel.Env);
|
|
||||||
|
var result = await context.Env.InvokeNodeAsync(ed.ArgDataSourceNodeGuid);
|
||||||
inputParameter = result;
|
inputParameter = result;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new Exception("节点执行方法获取入参参数时,ConnectionArgSourceType枚举是意外的枚举值");
|
throw new Exception("节点执行方法获取入参参数时,ConnectionArgSourceType枚举是意外的枚举值");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (inputParameter is null)
|
||||||
|
{
|
||||||
|
throw new Exception($"[arg{ed.Index}][{ed.Name}][{ed.DataType}]参数不能为null");
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 入参存在取值转换器,调用对应的转换器获取入参数据
|
#region 入参存在取值转换器,调用对应的转换器获取入参数据
|
||||||
@@ -418,7 +429,7 @@ namespace Serein.Library
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 对入参数据尝试进行转换
|
#region 对入参数据尝试进行转换
|
||||||
|
|
||||||
if (inputParameter.GetType() == ed.DataType)
|
if (inputParameter.GetType() == ed.DataType)
|
||||||
{
|
{
|
||||||
parameters[i] = inputParameter; // 类型一致无需转换,直接装入入参数组
|
parameters[i] = inputParameter; // 类型一致无需转换,直接装入入参数组
|
||||||
@@ -506,8 +517,8 @@ namespace Serein.Library
|
|||||||
{
|
{
|
||||||
await MonitorObjExpInterrupt(context, nodeModel, newData, 0); // 首先监视对象
|
await MonitorObjExpInterrupt(context, nodeModel, newData, 0); // 首先监视对象
|
||||||
await MonitorObjExpInterrupt(context, nodeModel, newData, 1); // 然后监视节点
|
await MonitorObjExpInterrupt(context, nodeModel, newData, 1); // 然后监视节点
|
||||||
nodeModel.FlowData = newData; // 替换数据
|
//nodeModel.FlowData = newData; // 替换数据
|
||||||
context.AddOrUpdate(guid, nodeModel); // 上下文中更新数据
|
context.AddOrUpdate(guid, newData); // 上下文中更新数据
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -548,12 +559,13 @@ namespace Serein.Library
|
|||||||
|
|
||||||
if (isExpInterrupt) // 触发中断
|
if (isExpInterrupt) // 触发中断
|
||||||
{
|
{
|
||||||
InterruptClass interruptClass = InterruptClass.Branch; // 分支中断
|
nodeModel.DebugSetting.IsInterrupt = true;
|
||||||
if (await context.Env.SetNodeInterruptAsync(nodeModel.Guid, interruptClass))
|
if (await context.Env.SetNodeInterruptAsync(nodeModel.Guid,true))
|
||||||
{
|
{
|
||||||
context.Env.TriggerInterrupt(nodeModel.Guid, exp, InterruptTriggerEventArgs.InterruptTriggerType.Exp);
|
context.Env.TriggerInterrupt(nodeModel.Guid, exp, InterruptTriggerEventArgs.InterruptTriggerType.Exp);
|
||||||
var cancelType = await nodeModel.DebugSetting.GetInterruptTask();
|
var cancelType = await nodeModel.DebugSetting.GetInterruptTask();
|
||||||
await Console.Out.WriteLineAsync($"[{data}]中断已{cancelType},开始执行后继分支");
|
await Console.Out.WriteLineAsync($"[{data}]中断已{cancelType},开始执行后继分支");
|
||||||
|
nodeModel.DebugSetting.IsInterrupt = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -561,26 +573,26 @@ namespace Serein.Library
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
///// <summary>
|
||||||
/// 释放对象
|
///// 释放对象
|
||||||
/// </summary>
|
///// </summary>
|
||||||
public void ReleaseFlowData()
|
//public void ReleaseFlowData()
|
||||||
{
|
//{
|
||||||
if (typeof(IDisposable).IsAssignableFrom(FlowData?.GetType()) && FlowData is IDisposable disposable)
|
// if (typeof(IDisposable).IsAssignableFrom(FlowData?.GetType()) && FlowData is IDisposable disposable)
|
||||||
{
|
// {
|
||||||
disposable?.Dispose();
|
// disposable?.Dispose();
|
||||||
}
|
// }
|
||||||
this.FlowData = null;
|
// this.FlowData = null;
|
||||||
}
|
//}
|
||||||
|
|
||||||
/// <summary>
|
///// <summary>
|
||||||
/// 获取节点数据
|
///// 获取节点数据
|
||||||
/// </summary>
|
///// </summary>
|
||||||
/// <returns></returns>
|
///// <returns></returns>
|
||||||
public object GetFlowData()
|
//public object GetFlowData()
|
||||||
{
|
//{
|
||||||
return this.FlowData;
|
// return this.FlowData;
|
||||||
}
|
//}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Serein.Library.Api;
|
using Serein.Library.Api;
|
||||||
|
using Serein.Library.Utils;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
@@ -62,11 +63,10 @@ namespace Serein.Library
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 当 ArgDataSourceType 不为 GetPreviousNodeData 时(从运行时上一节点获取数据)。
|
/// 当 ArgDataSourceType 不为 GetPreviousNodeData 时(从运行时上一节点获取数据)。
|
||||||
/// 则通过该集合对应的节点,获取其 FlowData 作为预处理的入参参数。
|
/// 则通过当前上下文,获取该Guid对应的数据作为预处理的入参参数。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[PropertyInfo(IsProtection = true)]
|
[PropertyInfo]
|
||||||
public NodeModelBase[] _argDataSourceNodeMoels;
|
private string _argDataSourceNodeGuid;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -97,6 +97,16 @@ namespace Serein.Library
|
|||||||
|
|
||||||
public partial class ParameterDetails
|
public partial class ParameterDetails
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 用于创建元数据
|
||||||
|
/// </summary>
|
||||||
|
public ParameterDetails()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 为节点实例化新的入参描述
|
/// 为节点实例化新的入参描述
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -112,27 +122,15 @@ namespace Serein.Library
|
|||||||
/// <param name="info">参数信息</param>
|
/// <param name="info">参数信息</param>
|
||||||
public ParameterDetails(ParameterDetailsInfo info)
|
public ParameterDetails(ParameterDetailsInfo info)
|
||||||
{
|
{
|
||||||
//this.env = env;
|
|
||||||
Index = info.Index;
|
Index = info.Index;
|
||||||
Name = info.Name;
|
Name = info.Name;
|
||||||
DataType = Type.GetType(info.DataTypeFullName);
|
DataType = Type.GetType(info.DataTypeFullName);
|
||||||
ExplicitType = Type.GetType(info.ExplicitTypeFullName);
|
ExplicitType = Type.GetType(info.ExplicitTypeFullName);
|
||||||
ExplicitTypeName = info.ExplicitTypeName;
|
ExplicitTypeName = info.ExplicitTypeName;
|
||||||
Items = info.Items;
|
Items = info.Items;
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 用于创建元数据
|
|
||||||
/// </summary>
|
|
||||||
public ParameterDetails()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 转为描述
|
/// 转为描述
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -141,12 +139,12 @@ namespace Serein.Library
|
|||||||
{
|
{
|
||||||
return new ParameterDetailsInfo
|
return new ParameterDetailsInfo
|
||||||
{
|
{
|
||||||
Index = Index,
|
Index = this.Index,
|
||||||
DataTypeFullName = DataType.FullName,
|
DataTypeFullName = this.DataType.FullName,
|
||||||
Name = Name,
|
Name = this.Name,
|
||||||
ExplicitTypeFullName = ExplicitType.FullName,
|
ExplicitTypeFullName = this.ExplicitType.FullName,
|
||||||
ExplicitTypeName = ExplicitTypeName,
|
ExplicitTypeName = this.ExplicitTypeName,
|
||||||
Items = Items,
|
Items = this.Items.Select(it => it).ToArray(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,7 +152,7 @@ namespace Serein.Library
|
|||||||
/// 为某个节点拷贝方法描述的入参描述
|
/// 为某个节点拷贝方法描述的入参描述
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="env">运行环境</param>
|
/// <param name="env">运行环境</param>
|
||||||
/// <param name="nodeGuid">运行环境</param>
|
/// <param name="nodeModel">对应的节点</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public ParameterDetails CloneOfClone(IFlowEnvironment env, NodeModelBase nodeModel)
|
public ParameterDetails CloneOfClone(IFlowEnvironment env, NodeModelBase nodeModel)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ namespace Serein.Library
|
|||||||
{
|
{
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 方法入参描述
|
/// 方法入参描述(远程用)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ParameterDetailsInfo
|
public class ParameterDetailsInfo
|
||||||
{
|
{
|
||||||
@@ -26,6 +26,7 @@ namespace Serein.Library
|
|||||||
/// 方法入参参数名称
|
/// 方法入参参数名称
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 显式类型
|
/// 显式类型
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -202,14 +202,13 @@ namespace Serein.Library
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 参数
|
/// 参数
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Parameterdata[] ParameterData { get; set; }
|
public ParameterData[] ParameterData { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 如果是区域控件,则会存在子项。
|
/// 如果是区域控件,则会存在子项。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string[] ChildNodeGuids { get; set; }
|
public string[] ChildNodeGuids { get; set; }
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 于画布中的位置
|
/// 于画布中的位置
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -223,14 +222,26 @@ namespace Serein.Library
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 显示参数,项目文件相关
|
/// 参数信息,项目文件相关
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Parameterdata
|
public class ParameterData
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 参数类型,true时使用自定义的入参,false时由运行环境自动传参
|
/// 参数类型,true时使用自定义的入参,false时由运行环境自动传参
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool State { get; set; }
|
public bool State { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 参数来源节点
|
||||||
|
/// </summary>
|
||||||
|
public string SourceNodeGuid { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 来源类型
|
||||||
|
/// </summary>
|
||||||
|
public string SourceType { get; set; }
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 自定义入参
|
/// 自定义入参
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -17,28 +17,58 @@ using Type = System.Type;
|
|||||||
|
|
||||||
namespace Serein.Library.Web
|
namespace Serein.Library.Web
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 路由接口
|
||||||
|
/// </summary>
|
||||||
public interface IRouter
|
public interface IRouter
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 添加处理模块
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="controllerType"></param>
|
||||||
void AddHandle(Type controllerType);
|
void AddHandle(Type controllerType);
|
||||||
|
/// <summary>
|
||||||
|
/// 路由解析开始处理
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context"></param>
|
||||||
|
/// <returns></returns>
|
||||||
Task<bool> ProcessingAsync(HttpListenerContext context);
|
Task<bool> ProcessingAsync(HttpListenerContext context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// api请求处理模块
|
||||||
|
/// </summary>
|
||||||
public class ApiHandleConfig
|
public class ApiHandleConfig
|
||||||
{
|
{
|
||||||
private readonly Delegate EmitDelegate;
|
private readonly DelegateDetails delegateDetails;
|
||||||
private readonly EmitHelper.EmitMethodType EmitMethodType;
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Post请求处理方法中,入参参数类型
|
||||||
|
/// </summary>
|
||||||
public enum PostArgType
|
public enum PostArgType
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 不做处理
|
||||||
|
/// </summary>
|
||||||
None,
|
None,
|
||||||
|
/// <summary>
|
||||||
|
/// 使用Url参数
|
||||||
|
/// </summary>
|
||||||
IsUrlData,
|
IsUrlData,
|
||||||
|
/// <summary>
|
||||||
|
/// 使用整体的Boby参数
|
||||||
|
/// </summary>
|
||||||
IsBobyData,
|
IsBobyData,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 添加处理配置
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="methodInfo"></param>
|
||||||
public ApiHandleConfig(MethodInfo methodInfo)
|
public ApiHandleConfig(MethodInfo methodInfo)
|
||||||
{
|
{
|
||||||
EmitMethodType = EmitHelper.CreateDynamicMethod(methodInfo, out EmitDelegate);
|
delegateDetails = new DelegateDetails(methodInfo);
|
||||||
var parameterInfos = methodInfo.GetParameters();
|
var parameterInfos = methodInfo.GetParameters();
|
||||||
ParameterType = parameterInfos.Select(t => t.ParameterType).ToArray();
|
ParameterType = parameterInfos.Select(t => t.ParameterType).ToArray();
|
||||||
ParameterName = parameterInfos.Select(t => t.Name.ToLower()).ToArray();
|
ParameterName = parameterInfos.Select(t => t.Name.ToLower()).ToArray();
|
||||||
@@ -68,7 +98,12 @@ namespace Serein.Library.Web
|
|||||||
private readonly string[] ParameterName;
|
private readonly string[] ParameterName;
|
||||||
private readonly Type[] ParameterType;
|
private readonly Type[] ParameterType;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 处理Get请求
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="instance"></param>
|
||||||
|
/// <param name="routeData"></param>
|
||||||
|
/// <returns></returns>
|
||||||
public async Task<object> HandleGet(object instance, Dictionary<string, string> routeData)
|
public async Task<object> HandleGet(object instance, Dictionary<string, string> routeData)
|
||||||
{
|
{
|
||||||
object[] args = new object[ParameterType.Length];
|
object[] args = new object[ParameterType.Length];
|
||||||
@@ -93,40 +128,20 @@ namespace Serein.Library.Web
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
object result = null;
|
||||||
object result;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (EmitMethodType == EmitHelper.EmitMethodType.HasResultTask && EmitDelegate is Func<object, object[], Task<object>> hasResultTask)
|
result = await delegateDetails.InvokeAsync(instance, args);
|
||||||
{
|
|
||||||
result = await hasResultTask(instance, args);
|
|
||||||
}
|
|
||||||
else if (EmitMethodType == EmitHelper.EmitMethodType.Task && EmitDelegate is Func<object, object[], Task> task)
|
|
||||||
{
|
|
||||||
await task.Invoke(instance, args);
|
|
||||||
result = null;
|
|
||||||
}
|
|
||||||
else if (EmitMethodType == EmitHelper.EmitMethodType.Func && EmitDelegate is Func<object, object[], object> func)
|
|
||||||
{
|
|
||||||
result = func.Invoke(instance, args);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
result = null;
|
result = null;
|
||||||
await Console.Out.WriteLineAsync(ex.Message);
|
await Console.Out.WriteLineAsync(ex.Message);
|
||||||
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <returns></returns>
|
||||||
|
|
||||||
public async Task<object> HandlePost(object instance, JObject jsonObject, Dictionary<string, string> routeData)
|
public async Task<object> HandlePost(object instance, JObject jsonObject, Dictionary<string, string> routeData)
|
||||||
{
|
{
|
||||||
object[] args = new object[ParameterType.Length];
|
object[] args = new object[ParameterType.Length];
|
||||||
@@ -173,26 +188,10 @@ namespace Serein.Library.Web
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object result;
|
object result = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (EmitMethodType == EmitHelper.EmitMethodType.HasResultTask && EmitDelegate is Func<object, object[], Task<object>> hasResultTask)
|
result = await delegateDetails.InvokeAsync(instance, args);
|
||||||
{
|
|
||||||
result = await hasResultTask(instance, args);
|
|
||||||
}
|
|
||||||
else if (EmitMethodType == EmitHelper.EmitMethodType.Task && EmitDelegate is Func<object, object[], Task> task)
|
|
||||||
{
|
|
||||||
await task.Invoke(instance, args);
|
|
||||||
result = null;
|
|
||||||
}
|
|
||||||
else if (EmitMethodType == EmitHelper.EmitMethodType.Func && EmitDelegate is Func<object, object[], object> func)
|
|
||||||
{
|
|
||||||
result = func.Invoke(instance, args);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -567,107 +566,6 @@ namespace Serein.Library.Web
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
internal static class WebFunc
|
|
||||||
{
|
|
||||||
public static bool ToBool(this JToken token, bool defult = false)
|
|
||||||
{
|
|
||||||
var value = token?.ToString();
|
|
||||||
if (string.IsNullOrWhiteSpace(value))
|
|
||||||
{
|
|
||||||
return defult;
|
|
||||||
}
|
|
||||||
if (!bool.TryParse(value, out bool result))
|
|
||||||
{
|
|
||||||
return defult;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static int ToInt(this JToken token, int defult = 0)
|
|
||||||
{
|
|
||||||
var value = token?.ToString();
|
|
||||||
if (string.IsNullOrWhiteSpace(value))
|
|
||||||
{
|
|
||||||
return defult;
|
|
||||||
}
|
|
||||||
if (!int.TryParse(value, out int result))
|
|
||||||
{
|
|
||||||
return defult;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static double ToDouble(this JToken token, double defult = 0)
|
|
||||||
{
|
|
||||||
var value = token?.ToString();
|
|
||||||
if (string.IsNullOrWhiteSpace(value))
|
|
||||||
{
|
|
||||||
return defult;
|
|
||||||
}
|
|
||||||
if (!int.TryParse(value, out int result))
|
|
||||||
{
|
|
||||||
return defult;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#region 已经注释
|
|
||||||
|
|
||||||
// private readonly ConcurrentDictionary<string, bool> _controllerAutoHosting; // 存储是否实例化
|
|
||||||
// private readonly ConcurrentDictionary<string, object> _controllerInstances;
|
|
||||||
|
|
||||||
//public void CollectRoutes(Type controllerType)
|
|
||||||
//{
|
|
||||||
// string controllerName = controllerType.Name.Replace("Controller", "").ToLower(); // 获取控制器名称并转换为小写
|
|
||||||
// foreach (var method in controllerType.GetMethods()) // 遍历控制器类型的所有方法
|
|
||||||
// {
|
|
||||||
// var routeAttribute = method.GetCustomAttribute<WebApiAttribute>(); // 获取方法上的 WebAPIAttribute 自定义属性
|
|
||||||
// if (routeAttribute != null) // 如果存在 WebAPIAttribute 属性
|
|
||||||
// {
|
|
||||||
// var customUrl = routeAttribute.Url; // 获取自定义 URL
|
|
||||||
// string url;
|
|
||||||
// if (string.IsNullOrEmpty(customUrl)) // 如果自定义 URL 为空
|
|
||||||
// {
|
|
||||||
// url = $"/api/{controllerName}/{method.Name}".ToLower(); // 构建默认 URL
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// customUrl = CleanUrl(customUrl);
|
|
||||||
// url = $"/api/{controllerName}/{method.Name}/{customUrl}".ToLower();// 清理自定义 URL,并构建新的 URL
|
|
||||||
// }
|
|
||||||
// var httpMethod = routeAttribute.Http; // 获取 HTTP 方法
|
|
||||||
// _routes[httpMethod.ToString()].TryAdd(url, method); // 将 URL 和方法添加到对应的路由字典中
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
//public void RegisterRoute<T>(T controllerInstance) // 方法声明,用于动态注册路由
|
|
||||||
//{
|
|
||||||
// Type controllerType = controllerInstance.GetType(); // 获取控制器实例的类型
|
|
||||||
// var autoHostingAttribute = controllerType.GetCustomAttribute<AutoHostingAttribute>();
|
|
||||||
// foreach (var method in controllerType.GetMethods()) // 遍历控制器类型的所有方法
|
|
||||||
// {
|
|
||||||
// var webAttribute = method.GetCustomAttribute<WebApiAttribute>(); // 获取方法上的 WebAPIAttribute 自定义属性
|
|
||||||
// if (webAttribute != null) // 如果存在 WebAPIAttribute 属性
|
|
||||||
// {
|
|
||||||
// var url = AddRoutesUrl(autoHostingAttribute, webAttribute, controllerType, method);
|
|
||||||
// if (url == null) continue;
|
|
||||||
// _controllerInstances[url] = controllerInstance;
|
|
||||||
// _controllerAutoHosting[url] = false;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
64
Library/Network/Http/SereinExtension.cs
Normal file
64
Library/Network/Http/SereinExtension.cs
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Serein.Library.Network.Http
|
||||||
|
{
|
||||||
|
internal static partial class SereinExtension
|
||||||
|
{
|
||||||
|
#region JSON相关
|
||||||
|
|
||||||
|
public static bool ToBool(this JToken token, bool defult = false)
|
||||||
|
{
|
||||||
|
var value = token?.ToString();
|
||||||
|
if (string.IsNullOrWhiteSpace(value))
|
||||||
|
{
|
||||||
|
return defult;
|
||||||
|
}
|
||||||
|
if (!bool.TryParse(value, out bool result))
|
||||||
|
{
|
||||||
|
return defult;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static int ToInt(this JToken token, int defult = 0)
|
||||||
|
{
|
||||||
|
var value = token?.ToString();
|
||||||
|
if (string.IsNullOrWhiteSpace(value))
|
||||||
|
{
|
||||||
|
return defult;
|
||||||
|
}
|
||||||
|
if (!int.TryParse(value, out int result))
|
||||||
|
{
|
||||||
|
return defult;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static double ToDouble(this JToken token, double defult = 0)
|
||||||
|
{
|
||||||
|
var value = token?.ToString();
|
||||||
|
if (string.IsNullOrWhiteSpace(value))
|
||||||
|
{
|
||||||
|
return defult;
|
||||||
|
}
|
||||||
|
if (!int.TryParse(value, out int result))
|
||||||
|
{
|
||||||
|
return defult;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,7 +31,7 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
|
|||||||
Action<Exception, Action<object>> onExceptionTracking,
|
Action<Exception, Action<object>> onExceptionTracking,
|
||||||
bool ArgNotNull)
|
bool ArgNotNull)
|
||||||
{
|
{
|
||||||
EmitMethodType = EmitHelper.CreateDynamicMethod(methodInfo,out EmitDelegate);
|
DelegateDetails = new DelegateDetails(methodInfo);
|
||||||
this.Module = model;
|
this.Module = model;
|
||||||
Instance = instance;
|
Instance = instance;
|
||||||
var parameterInfos = methodInfo.GetParameters();
|
var parameterInfos = methodInfo.GetParameters();
|
||||||
@@ -72,15 +72,10 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
|
|||||||
/// 参数不能为空
|
/// 参数不能为空
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private bool ArgNotNull;
|
private bool ArgNotNull;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Emit委托
|
/// Emit委托
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly Delegate EmitDelegate;
|
private readonly DelegateDetails DelegateDetails;
|
||||||
/// <summary>
|
|
||||||
/// Emit委托类型
|
|
||||||
/// </summary>
|
|
||||||
private readonly EmitHelper.EmitMethodType EmitMethodType;
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 未捕获的异常跟踪
|
/// 未捕获的异常跟踪
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -114,29 +109,26 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly bool[] IsCheckArgNotNull;
|
private readonly bool[] IsCheckArgNotNull;
|
||||||
|
|
||||||
//private object ConvertArg(Type type, string argName )
|
|
||||||
//{
|
|
||||||
|
|
||||||
//}
|
|
||||||
|
|
||||||
public async void Handle(Func<object, Task> SendAsync,string msgId, JObject jsonObject)
|
public async void Handle(Func<object, Task> SendAsync,string msgId, JObject jsonObject)
|
||||||
{
|
{
|
||||||
object[] args = new object[ParameterType.Length];
|
object[] args = new object[ParameterType.Length];
|
||||||
bool isCanInvoke = true;; // 表示是否可以调用方法
|
bool isCanInvoke = true;; // 表示是否可以调用方法
|
||||||
for (int i = 0; i < ParameterType.Length; i++)
|
for (int i = 0; i < ParameterType.Length; i++)
|
||||||
{
|
{
|
||||||
var type = ParameterType[i];
|
var type = ParameterType[i]; // 入参变量类型
|
||||||
var argName = ParameterName[i];
|
var argName = ParameterName[i]; // 入参参数名称
|
||||||
#region DATA JSON数据
|
#region 传递消息ID
|
||||||
if (useData[i])
|
if (useMsgId[i])
|
||||||
{
|
|
||||||
args[i] = jsonObject.ToObject(type);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
else if (useMsgId[i])
|
|
||||||
{
|
{
|
||||||
args[i] = msgId;
|
args[i] = msgId;
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
|
#region DATA JSON数据
|
||||||
|
else if (useData[i])
|
||||||
|
{
|
||||||
|
args[i] = jsonObject.ToObject(type);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
#region 值类型参数
|
#region 值类型参数
|
||||||
else if (type.IsValueType)
|
else if (type.IsValueType)
|
||||||
{
|
{
|
||||||
@@ -229,23 +221,7 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
|
|||||||
object result;
|
object result;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (EmitMethodType == EmitHelper.EmitMethodType.HasResultTask && EmitDelegate is Func<object, object[], Task<object>> hasResultTask)
|
result = await DelegateDetails.InvokeAsync(Instance, args);
|
||||||
{
|
|
||||||
result = await hasResultTask(Instance, args);
|
|
||||||
}
|
|
||||||
else if (EmitMethodType == EmitHelper.EmitMethodType.Task && EmitDelegate is Func<object, object[], Task> task)
|
|
||||||
{
|
|
||||||
await task.Invoke(Instance, args);
|
|
||||||
result = null;
|
|
||||||
}
|
|
||||||
else if (EmitMethodType == EmitHelper.EmitMethodType.Func && EmitDelegate is Func<object, object[], object> func)
|
|
||||||
{
|
|
||||||
result = func.Invoke(Instance, args);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -256,25 +232,11 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
|
|||||||
await SendAsync.Invoke(exData);
|
await SendAsync.Invoke(exData);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
//sw.Stop();
|
|
||||||
//Console.WriteLine($"Emit Invoke:{sw.ElapsedTicks * 1000000F / Stopwatch.Frequency:n3}μs");
|
|
||||||
|
|
||||||
|
|
||||||
if (Module.IsReturnValue)
|
if (Module.IsReturnValue)
|
||||||
{
|
{
|
||||||
if (result is null)
|
|
||||||
{
|
|
||||||
result = "null";
|
|
||||||
}
|
|
||||||
_ = SendAsync.Invoke(result);
|
_ = SendAsync.Invoke(result);
|
||||||
}
|
}
|
||||||
//if( && result != null && result.GetType().IsClass)
|
|
||||||
//{
|
|
||||||
// //var reusltJsonText = JsonConvert.SerializeObject(result);
|
|
||||||
|
|
||||||
// //_ = SendAsync.Invoke($"{reusltJsonText}");
|
|
||||||
//}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -91,6 +91,8 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
|
|||||||
MyHandleConfigs.Clear();
|
MyHandleConfigs.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private HashSet<string> _myMsgIdHash = new HashSet<string>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 处理JSON数据
|
/// 处理JSON数据
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -106,11 +108,15 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
string msgId = jsonObject.GetValue(MsgIdJsonKey)?.ToString();
|
string msgId = jsonObject.GetValue(MsgIdJsonKey)?.ToString();
|
||||||
|
if (_myMsgIdHash.Contains(msgId))
|
||||||
|
{
|
||||||
|
Console.WriteLine($"[{msgId}]{theme} 消息重复");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_myMsgIdHash.Add(msgId);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
||||||
JObject dataObj = jsonObject.GetValue(DataJsonKey)?.ToObject<JObject>();
|
JObject dataObj = jsonObject.GetValue(DataJsonKey)?.ToObject<JObject>();
|
||||||
handldConfig.Handle(async (data) =>
|
handldConfig.Handle(async (data) =>
|
||||||
{
|
{
|
||||||
@@ -170,9 +176,8 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
|
|||||||
}
|
}
|
||||||
|
|
||||||
var msg = jsonData.ToString();
|
var msg = jsonData.ToString();
|
||||||
//Console.WriteLine(msg);
|
|
||||||
//Console.WriteLine();
|
|
||||||
|
|
||||||
await sendAsync.Invoke(msg);
|
await sendAsync.Invoke(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -155,21 +155,16 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步处理消息
|
/// 异步处理消息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="SendAsync"></param>
|
/// <param name="sendAsync"></param>
|
||||||
/// <param name="message"></param>
|
/// <param name="message"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task HandleMsgAsync(Func<string, Task> SendAsync, string message)
|
public void HandleMsg(Func<string, Task> sendAsync, string message)
|
||||||
{
|
{
|
||||||
//Console.WriteLine(message);
|
|
||||||
JObject json = JObject.Parse(message);
|
JObject json = JObject.Parse(message);
|
||||||
await Task.Run(() =>
|
foreach (var module in MyHandleModuleDict.Values)
|
||||||
{
|
{
|
||||||
foreach (var module in MyHandleModuleDict.Values)
|
module.HandleSocketMsg(sendAsync, json);
|
||||||
{
|
}
|
||||||
module.HandleSocketMsg(SendAsync, json);
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,28 +8,4 @@ namespace Serein.Library.Network.WebSocketCommunication
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//[AutoRegister(RegisterSequence.FlowLoading)]
|
|
||||||
//[AutoSocketModule(JsonThemeField = "theme", JsonDataField = "data")]
|
|
||||||
//public class UserService : ISocketControlBase
|
|
||||||
//{
|
|
||||||
// public Guid HandleGuid { get; } = new Guid();
|
|
||||||
|
|
||||||
// // Action<string> 类型是特殊的,会用一个委托代替,这个委托可以将文本信息发送到客户端
|
|
||||||
// // Action<object> 类型是特殊的,会用一个委托代替,这个委托可以将对象转成json发送到客户端
|
|
||||||
|
|
||||||
// [AutoSocketHandle]
|
|
||||||
// public void AddUser(User user,Action<string> Recover)
|
|
||||||
// {
|
|
||||||
// Console.WriteLine(user.ToString());
|
|
||||||
// Recover("ok");
|
|
||||||
// }
|
|
||||||
|
|
||||||
// [AutoSocketHandle(ThemeValue = "Remote")]
|
|
||||||
// public void DeleteUser(User user, Action<string> Recover)
|
|
||||||
// {
|
|
||||||
// Console.WriteLine(user.ToString());
|
|
||||||
// }
|
|
||||||
|
|
||||||
//}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
73
Library/Network/WebSocket/TestExtension.cs
Normal file
73
Library/Network/WebSocket/TestExtension.cs
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
using Serein.Library.Utils;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net.WebSockets;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Channels;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Serein.Library.Network.WebSocketCommunication
|
||||||
|
{
|
||||||
|
public class MsgQueueUtil
|
||||||
|
{
|
||||||
|
public ConcurrentQueue<string> Msgs = new ConcurrentQueue<string>();
|
||||||
|
|
||||||
|
private readonly Channel<string> _msgChannel;
|
||||||
|
public MsgQueueUtil()
|
||||||
|
{
|
||||||
|
_msgChannel = CreateChannel();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Channel<string> CreateChannel()
|
||||||
|
{
|
||||||
|
return Channel.CreateBounded<string>(new BoundedChannelOptions(100)
|
||||||
|
{
|
||||||
|
FullMode = BoundedChannelFullMode.Wait
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 等待消息
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<string> WaitMsgAsync()
|
||||||
|
{
|
||||||
|
var state = await _msgChannel.Reader.ReadAsync();
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteMsg(string msg)
|
||||||
|
{
|
||||||
|
//Msgs.Enqueue(msg);
|
||||||
|
Console.WriteLine($"{DateTime.Now}{msg}{Environment.NewLine}");
|
||||||
|
_ = _msgChannel.Writer.WriteAsync(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetMsg(out string msg)
|
||||||
|
{
|
||||||
|
return Msgs.TryDequeue(out msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public class SocketExtension
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 发送消息
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="webSocket"></param>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static async Task SendAsync(WebSocket webSocket, string message)
|
||||||
|
{
|
||||||
|
var buffer = Encoding.UTF8.GetBytes(message);
|
||||||
|
await webSocket.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, CancellationToken.None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,13 @@
|
|||||||
using Serein.Library.Network.WebSocketCommunication.Handle;
|
using Serein.Library.Network.WebSocketCommunication.Handle;
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.IO.Compression;
|
||||||
|
using System.IO;
|
||||||
using System.Net.WebSockets;
|
using System.Net.WebSockets;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using static System.Net.Mime.MediaTypeNames;
|
||||||
|
|
||||||
namespace Serein.Library.Network.WebSocketCommunication
|
namespace Serein.Library.Network.WebSocketCommunication
|
||||||
{
|
{
|
||||||
@@ -38,7 +41,6 @@ namespace Serein.Library.Network.WebSocketCommunication
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
||||||
await _client.ConnectAsync(new Uri(uri), CancellationToken.None);
|
await _client.ConnectAsync(new Uri(uri), CancellationToken.None);
|
||||||
_ = ReceiveAsync();
|
_ = ReceiveAsync();
|
||||||
return true;
|
return true;
|
||||||
@@ -58,8 +60,12 @@ namespace Serein.Library.Network.WebSocketCommunication
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task SendAsync(string message)
|
public async Task SendAsync(string message)
|
||||||
{
|
{
|
||||||
var buffer = Encoding.UTF8.GetBytes(message);
|
Console.WriteLine("发送消息");
|
||||||
await _client.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, CancellationToken.None);
|
await Task.Delay(2000);
|
||||||
|
await SocketExtension.SendAsync(this._client, message); // 回复客户端
|
||||||
|
Console.WriteLine();
|
||||||
|
//var buffer = Encoding.UTF8.GetBytes(message);
|
||||||
|
//await _client.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, CancellationToken.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -68,13 +74,21 @@ namespace Serein.Library.Network.WebSocketCommunication
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private async Task ReceiveAsync()
|
private async Task ReceiveAsync()
|
||||||
{
|
{
|
||||||
var buffer = new byte[1024];
|
|
||||||
|
var msgQueueUtil = new MsgQueueUtil();
|
||||||
|
_ = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await HandleMsgAsync(_client, msgQueueUtil);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
var receivedMessage = new StringBuilder(); // 用于拼接长消息
|
var receivedMessage = new StringBuilder(); // 用于拼接长消息
|
||||||
|
|
||||||
while (_client.State == WebSocketState.Open)
|
while (_client.State == WebSocketState.Open)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
var buffer = new byte[1024];
|
||||||
WebSocketReceiveResult result;
|
WebSocketReceiveResult result;
|
||||||
|
|
||||||
do
|
do
|
||||||
@@ -86,21 +100,22 @@ namespace Serein.Library.Network.WebSocketCommunication
|
|||||||
receivedMessage.Append(partialMessage);
|
receivedMessage.Append(partialMessage);
|
||||||
|
|
||||||
} while (!result.EndOfMessage); // 判断是否已经收到完整消息
|
} while (!result.EndOfMessage); // 判断是否已经收到完整消息
|
||||||
|
var message = receivedMessage.ToString();
|
||||||
|
msgQueueUtil.WriteMsg(message);
|
||||||
|
receivedMessage.Clear(); // 清空 StringBuilder 为下一条消息做准备
|
||||||
// 处理收到的完整消息
|
// 处理收到的完整消息
|
||||||
if (result.MessageType == WebSocketMessageType.Close)
|
if (result.MessageType == WebSocketMessageType.Close)
|
||||||
{
|
{
|
||||||
await _client.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None);
|
await _client.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None);
|
||||||
}
|
}
|
||||||
else
|
//else
|
||||||
{
|
//{
|
||||||
var completeMessage = receivedMessage.ToString();
|
// var completeMessage = receivedMessage.ToString();
|
||||||
_ = MsgHandleHelper.HandleMsgAsync(SendAsync, completeMessage); // 处理消息
|
// MsgHandleHelper.HandleMsg(SendAsync, completeMessage); // 处理消息,如果方法入参是需要发送消息委托时,将 SendAsync 作为委托参数提供
|
||||||
//Debug.WriteLine($"Received: {completeMessage}");
|
// //Debug.WriteLine($"Received: {completeMessage}");
|
||||||
}
|
//}
|
||||||
|
|
||||||
// 清空 StringBuilder 为下一条消息做准备
|
|
||||||
receivedMessage.Clear();
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -110,65 +125,86 @@ namespace Serein.Library.Network.WebSocketCommunication
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* #region 消息处理
|
public async Task HandleMsgAsync(WebSocket webSocket,
|
||||||
private readonly string ThemeField;
|
MsgQueueUtil msgQueueUtil)
|
||||||
private readonly ConcurrentDictionary<string, HandldConfig> ThemeConfigs = new ConcurrentDictionary<string, HandldConfig>();
|
|
||||||
|
|
||||||
public async Task HandleSocketMsg(string jsonStr)
|
|
||||||
{
|
{
|
||||||
JObject json;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
json = JObject.Parse(jsonStr);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
await SendAsync(_client, ex.Message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 获取到消息
|
|
||||||
string themeName = json[ThemeField]?.ToString();
|
|
||||||
if (!ThemeConfigs.TryGetValue(themeName, out var handldConfig))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
object dataValue;
|
while (true)
|
||||||
if (string.IsNullOrEmpty(handldConfig.DataField))
|
|
||||||
{
|
{
|
||||||
dataValue = json.ToObject(handldConfig.DataType);
|
var message = await msgQueueUtil.WaitMsgAsync(); // 有消息时通知
|
||||||
}
|
//if (!msgQueueUtil.TryGetMsg(out var message)) // 获取消息
|
||||||
else
|
//{
|
||||||
{
|
// return;
|
||||||
dataValue = json[handldConfig.DataField].ToObject(handldConfig.DataType);
|
//}
|
||||||
}
|
// 消息处理
|
||||||
await handldConfig.Invoke(dataValue, SendAsync);
|
MsgHandleHelper.HandleMsg(async (text) =>
|
||||||
}
|
|
||||||
|
|
||||||
public void AddConfig(string themeName, Type dataType, MsgHandler msgHandler)
|
|
||||||
{
|
|
||||||
if (!ThemeConfigs.TryGetValue(themeName, out var handldConfig))
|
|
||||||
{
|
|
||||||
handldConfig = new HandldConfig
|
|
||||||
{
|
{
|
||||||
DataField = themeName,
|
await SocketExtension.SendAsync(webSocket, text); // 回复客户端,处理方法中入参如果需要发送消息委托,则将该回调方法作为委托参数传入
|
||||||
DataType = dataType
|
}, message); // 处理消息
|
||||||
};
|
|
||||||
ThemeConfigs.TryAdd(themeName, handldConfig);
|
|
||||||
}
|
}
|
||||||
handldConfig.HandldAsync += msgHandler;
|
|
||||||
}
|
|
||||||
public void RemoteConfig(string themeName, MsgHandler msgHandler)
|
/* #region 消息处理
|
||||||
{
|
private readonly string ThemeField;
|
||||||
if (ThemeConfigs.TryGetValue(themeName, out var handldConfig))
|
private readonly ConcurrentDictionary<string, HandldConfig> ThemeConfigs = new ConcurrentDictionary<string, HandldConfig>();
|
||||||
|
|
||||||
|
public async Task HandleSocketMsg(string jsonStr)
|
||||||
{
|
{
|
||||||
handldConfig.HandldAsync -= msgHandler;
|
JObject json;
|
||||||
if (!handldConfig.HasSubscribers)
|
try
|
||||||
{
|
{
|
||||||
ThemeConfigs.TryRemove(themeName, out _);
|
json = JObject.Parse(jsonStr);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await SendAsync(_client, ex.Message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 获取到消息
|
||||||
|
string themeName = json[ThemeField]?.ToString();
|
||||||
|
if (!ThemeConfigs.TryGetValue(themeName, out var handldConfig))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
object dataValue;
|
||||||
|
if (string.IsNullOrEmpty(handldConfig.DataField))
|
||||||
|
{
|
||||||
|
dataValue = json.ToObject(handldConfig.DataType);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dataValue = json[handldConfig.DataField].ToObject(handldConfig.DataType);
|
||||||
|
}
|
||||||
|
await handldConfig.Invoke(dataValue, SendAsync);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddConfig(string themeName, Type dataType, MsgHandler msgHandler)
|
||||||
|
{
|
||||||
|
if (!ThemeConfigs.TryGetValue(themeName, out var handldConfig))
|
||||||
|
{
|
||||||
|
handldConfig = new HandldConfig
|
||||||
|
{
|
||||||
|
DataField = themeName,
|
||||||
|
DataType = dataType
|
||||||
|
};
|
||||||
|
ThemeConfigs.TryAdd(themeName, handldConfig);
|
||||||
|
}
|
||||||
|
handldConfig.HandldAsync += msgHandler;
|
||||||
|
}
|
||||||
|
public void RemoteConfig(string themeName, MsgHandler msgHandler)
|
||||||
|
{
|
||||||
|
if (ThemeConfigs.TryGetValue(themeName, out var handldConfig))
|
||||||
|
{
|
||||||
|
handldConfig.HandldAsync -= msgHandler;
|
||||||
|
if (!handldConfig.HasSubscribers)
|
||||||
|
{
|
||||||
|
ThemeConfigs.TryRemove(themeName, out _);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endregion*/
|
||||||
}
|
}
|
||||||
#endregion*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -180,67 +180,46 @@ namespace Serein.Library.Network.WebSocketCommunication
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var msgQueueUtil = new MsgQueueUtil();
|
||||||
|
_ = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await HandleMsgAsync(webSocket,msgQueueUtil, authorizedHelper);
|
||||||
|
});
|
||||||
|
|
||||||
//Func<string, Task> SendAsync = async (text) =>
|
//Func<string, Task> SendAsync = async (text) =>
|
||||||
//{
|
//{
|
||||||
// await WebSocketServer.SendAsync(webSocket, text);
|
// await WebSocketServer.SendAsync(webSocket, text);
|
||||||
//};
|
//};
|
||||||
|
|
||||||
var buffer = new byte[1024];
|
|
||||||
var receivedMessage = new StringBuilder(); // 用于拼接长消息
|
var receivedMessage = new StringBuilder(); // 用于拼接长消息
|
||||||
|
|
||||||
while (webSocket.State == WebSocketState.Open)
|
while ( webSocket.State == WebSocketState.Open)
|
||||||
{
|
{
|
||||||
WebSocketReceiveResult result;
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
WebSocketReceiveResult result;
|
||||||
|
var buffer = new byte[1024];
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
|
result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
|
||||||
|
if (result.MessageType == WebSocketMessageType.Close)
|
||||||
|
{
|
||||||
|
await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None);
|
||||||
|
if (IsCheckToken)
|
||||||
|
{
|
||||||
|
AuthorizedClients.TryRemove(authorizedHelper.AddresPort, out var _);
|
||||||
|
}
|
||||||
|
}
|
||||||
// 将接收到的部分消息解码并拼接
|
// 将接收到的部分消息解码并拼接
|
||||||
var partialMessage = Encoding.UTF8.GetString(buffer, 0, result.Count);
|
var partialMessage = Encoding.UTF8.GetString(buffer, 0, result.Count);
|
||||||
receivedMessage.Append(partialMessage);
|
receivedMessage.Append(partialMessage);
|
||||||
|
|
||||||
} while (!result.EndOfMessage); // 循环直到接收到完整的消息
|
} while (!result.EndOfMessage); // 循环直到接收到完整的消息
|
||||||
|
|
||||||
// 完整消息已经接收到,准备处理
|
// 完整消息已经接收到,准备处理
|
||||||
var message = receivedMessage.ToString();
|
var message = receivedMessage.ToString(); // 获取消息文本
|
||||||
|
receivedMessage.Clear(); // 清空 StringBuilder 为下一条消息做准备
|
||||||
if (result.MessageType == WebSocketMessageType.Close)
|
msgQueueUtil.WriteMsg(message); // 处理消息
|
||||||
{
|
|
||||||
//SendAsync = null;
|
|
||||||
await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None);
|
|
||||||
if (IsCheckToken)
|
|
||||||
{
|
|
||||||
AuthorizedClients.TryRemove(authorizedHelper.AddresPort, out var _);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (IsCheckToken)
|
|
||||||
{
|
|
||||||
var authorizedResult = await authorizedHelper.HandleAuthorized(message); // 尝试检测授权
|
|
||||||
if (!authorizedResult) // 授权失败
|
|
||||||
{
|
|
||||||
await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None);
|
|
||||||
if (IsCheckToken)
|
|
||||||
{
|
|
||||||
AuthorizedClients.TryRemove(authorizedHelper.AddresPort, out var _);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 消息处理
|
|
||||||
_ = MsgHandleHelper.HandleMsgAsync(async (text) =>
|
|
||||||
{
|
|
||||||
await WebSocketServer.SendAsync(webSocket, text);
|
|
||||||
}, message); // 处理消息
|
|
||||||
}
|
|
||||||
|
|
||||||
// 清空 StringBuilder 为下一条消息做准备
|
|
||||||
receivedMessage.Clear();
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -249,17 +228,45 @@ namespace Serein.Library.Network.WebSocketCommunication
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// <summary>
|
|
||||||
/// 发送消息
|
|
||||||
/// </summary>
|
public async Task HandleMsgAsync(WebSocket webSocket,
|
||||||
/// <param name="webSocket"></param>
|
MsgQueueUtil msgQueueUtil,
|
||||||
/// <param name="message"></param>
|
WebSocketAuthorizedHelper authorizedHelper)
|
||||||
/// <returns></returns>
|
|
||||||
public static async Task SendAsync(WebSocket webSocket, string message)
|
|
||||||
{
|
{
|
||||||
var buffer = Encoding.UTF8.GetBytes(message);
|
|
||||||
await webSocket.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, CancellationToken.None);
|
while (true)
|
||||||
|
{
|
||||||
|
var message = await msgQueueUtil.WaitMsgAsync(); // 有消息时通知
|
||||||
|
//if (!msgQueueUtil.TryGetMsg(out var message)) // 获取消息
|
||||||
|
//{
|
||||||
|
// return;
|
||||||
|
//}
|
||||||
|
if (IsCheckToken)
|
||||||
|
{
|
||||||
|
var authorizedResult = await authorizedHelper.HandleAuthorized(message); // 尝试检测授权
|
||||||
|
if (!authorizedResult) // 授权失败
|
||||||
|
{
|
||||||
|
await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None);
|
||||||
|
if (IsCheckToken)
|
||||||
|
{
|
||||||
|
AuthorizedClients.TryRemove(authorizedHelper.AddresPort, out var _);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 消息处理
|
||||||
|
MsgHandleHelper.HandleMsg(async (text) =>
|
||||||
|
{
|
||||||
|
await SocketExtension.SendAsync(webSocket, text); // 回复客户端,处理方法中入参如果需要发送消息委托,则将该回调方法作为委托参数传入
|
||||||
|
}, message); // 处理消息
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Version>1.0.17</Version>
|
<Version>1.0.18</Version>
|
||||||
<TargetFrameworks>net8.0;net462</TargetFrameworks>
|
<TargetFrameworks>net8.0;net462</TargetFrameworks>
|
||||||
<!--<TargetFrameworks>net8.0</TargetFrameworks>-->
|
<!--<TargetFrameworks>net8.0</TargetFrameworks>-->
|
||||||
<BaseOutputPath>D:\Project\C#\DynamicControl\SereinFlow\.Output</BaseOutputPath>
|
<BaseOutputPath>D:\Project\C#\DynamicControl\SereinFlow\.Output</BaseOutputPath>
|
||||||
@@ -37,7 +37,6 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
||||||
<ProjectReference Include="..\Serein.Library.MyGenerator\Serein.Library.NodeGenerator.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="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="System.Reactive" Version="6.0.1" />
|
<PackageReference Include="System.Reactive" Version="6.0.1" />
|
||||||
<PackageReference Include="System.Threading.Channels" Version="8.0.0" />
|
<PackageReference Include="System.Threading.Channels" Version="8.0.0" />
|
||||||
|
|||||||
@@ -100,4 +100,14 @@ namespace Serein.Library.Utils
|
|||||||
return _channels.GetOrAdd(signal, _ => Channel.CreateUnbounded<(TriggerType, object)>());
|
return _channels.GetOrAdd(signal, _ => Channel.CreateUnbounded<(TriggerType, object)>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ namespace Serein.Library.Utils
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 管理远程环境,具备连接、发送消息、停止的功能
|
/// 管理远程环境,具备连接、发送消息、停止的功能
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class RemoteEnvControl
|
public class RemoteMsgUtil
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 远程环境配置
|
/// 远程环境配置
|
||||||
@@ -52,7 +52,7 @@ namespace Serein.Library.Utils
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 配置远程连接IP端口
|
/// 配置远程连接IP端口
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public RemoteEnvControl(ControlConfiguration controlConfiguration)
|
public RemoteMsgUtil(ControlConfiguration controlConfiguration)
|
||||||
{
|
{
|
||||||
Config = controlConfiguration;
|
Config = controlConfiguration;
|
||||||
}
|
}
|
||||||
@@ -120,13 +120,6 @@ namespace Serein.Library.Utils
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task SendAsync(string msgId , string theme, object data)
|
public async Task SendAsync(string msgId , string theme, object data)
|
||||||
{
|
{
|
||||||
//var sendMsg = new
|
|
||||||
//{
|
|
||||||
// theme = theme,
|
|
||||||
// token = this.Token,
|
|
||||||
// data = data,
|
|
||||||
//};
|
|
||||||
//var msg = JsonConvert.SerializeObject(sendMsg);
|
|
||||||
JObject jsonData;
|
JObject jsonData;
|
||||||
|
|
||||||
if (data is null)
|
if (data is null)
|
||||||
@@ -156,11 +149,8 @@ namespace Serein.Library.Utils
|
|||||||
[Config.DataJsonKey] = dataToken
|
[Config.DataJsonKey] = dataToken
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
var msg = jsonData.ToString();
|
var msg = jsonData.ToString();
|
||||||
//Console.WriteLine(msg);
|
Console.WriteLine($"[{msgId}] => {theme}");
|
||||||
//Console.WriteLine();
|
|
||||||
|
|
||||||
await EnvClient.SendAsync(msg);
|
await EnvClient.SendAsync(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,21 +30,31 @@
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public const string SetStartNode = nameof(SetStartNode);
|
public const string SetStartNode = nameof(SetStartNode);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 尝试连接两个节点
|
|
||||||
/// </summary>
|
|
||||||
public const string ConnectNode = nameof(ConnectNode);
|
|
||||||
/// <summary>
|
|
||||||
/// 尝试创建节点
|
/// 尝试创建节点
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const string CreateNode = nameof(CreateNode);
|
public const string CreateNode = nameof(CreateNode);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 尝试移除节点之间的连接关系
|
|
||||||
/// </summary>
|
|
||||||
public const string RemoveConnect = nameof(RemoveConnect);
|
|
||||||
/// <summary>
|
|
||||||
/// 尝试移除节点
|
/// 尝试移除节点
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const string RemoveNode = nameof(RemoveNode);
|
public const string RemoveNode = nameof(RemoveNode);
|
||||||
|
/// <summary>
|
||||||
|
/// 尝试连接两个节点的方法调用关系
|
||||||
|
/// </summary>
|
||||||
|
public const string ConnectInvokeNode = nameof(ConnectInvokeNode);
|
||||||
|
/// <summary>
|
||||||
|
/// 尝试移除节点之间的方法调用关系
|
||||||
|
/// </summary>
|
||||||
|
public const string RemoveInvokeConnect = nameof(RemoveInvokeConnect);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 尝试连接两个节点的参数传递关系
|
||||||
|
/// </summary>
|
||||||
|
public const string ConnectArgSourceNode = nameof(ConnectArgSourceNode);
|
||||||
|
/// <summary>
|
||||||
|
/// 尝试移除节点之间的参数传递关系
|
||||||
|
/// </summary>
|
||||||
|
public const string RemoveArgSourceConnect = nameof(RemoveArgSourceConnect);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 激活一个触发器
|
/// 激活一个触发器
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Serein.Library;
|
using Serein.Library;
|
||||||
using Serein.Library.Api;
|
using Serein.Library.Api;
|
||||||
|
using Serein.Library.FlowNode;
|
||||||
using Serein.Library.Utils;
|
using Serein.Library.Utils;
|
||||||
using Serein.Library.Utils.SereinExpression;
|
using Serein.Library.Utils.SereinExpression;
|
||||||
using Serein.NodeFlow.Model;
|
using Serein.NodeFlow.Model;
|
||||||
@@ -9,6 +10,7 @@ using Serein.NodeFlow.Tool;
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Reflection.Metadata.Ecma335;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
using static Serein.Library.Utils.ChannelFlowInterrupt;
|
using static Serein.Library.Utils.ChannelFlowInterrupt;
|
||||||
|
|
||||||
@@ -78,9 +80,8 @@ namespace Serein.NodeFlow.Env
|
|||||||
if (clientMsgManage is null)
|
if (clientMsgManage is null)
|
||||||
{
|
{
|
||||||
clientMsgManage = new MsgControllerOfServer(this);
|
clientMsgManage = new MsgControllerOfServer(this);
|
||||||
//clientMsgManage = new MsgControllerOfServer(this, "token");
|
|
||||||
}
|
}
|
||||||
await clientMsgManage.StartRemoteServerAsync(port);
|
_ = clientMsgManage.StartRemoteServerAsync(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -346,18 +347,11 @@ namespace Serein.NodeFlow.Env
|
|||||||
List<MethodDetails> initMethods = [];
|
List<MethodDetails> initMethods = [];
|
||||||
List<MethodDetails> loadMethods = [];
|
List<MethodDetails> loadMethods = [];
|
||||||
List<MethodDetails> exitMethods = [];
|
List<MethodDetails> exitMethods = [];
|
||||||
//foreach(var mds in MethodDetailss.Values)
|
|
||||||
//{
|
|
||||||
// var initMds = mds.Where(it => it.MethodDynamicType == NodeType.Init);
|
|
||||||
// var loadMds = mds.Where(it => it.MethodDynamicType == NodeType.Loading);
|
|
||||||
// var exitMds = mds.Where(it => it.MethodDynamicType == NodeType.Exit);
|
|
||||||
// initMethods.AddRange(initMds);
|
|
||||||
// loadMethods.AddRange(loadMds);
|
|
||||||
// exitMethods.AddRange(exitMds);
|
|
||||||
//}
|
|
||||||
var initMds = MethodDetailss.Values.Where(it => it.MethodDynamicType == NodeType.Init);
|
var initMds = MethodDetailss.Values.Where(it => it.MethodDynamicType == NodeType.Init);
|
||||||
var loadMds = MethodDetailss.Values.Where(it => it.MethodDynamicType == NodeType.Loading);
|
var loadMds = MethodDetailss.Values.Where(it => it.MethodDynamicType == NodeType.Loading);
|
||||||
var exitMds = MethodDetailss.Values.Where(it => it.MethodDynamicType == NodeType.Exit);
|
var exitMds = MethodDetailss.Values.Where(it => it.MethodDynamicType == NodeType.Exit);
|
||||||
|
|
||||||
initMethods.AddRange(initMds);
|
initMethods.AddRange(initMds);
|
||||||
loadMethods.AddRange(loadMds);
|
loadMethods.AddRange(loadMds);
|
||||||
exitMethods.AddRange(exitMds);
|
exitMethods.AddRange(exitMds);
|
||||||
@@ -418,9 +412,11 @@ namespace Serein.NodeFlow.Env
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<object> InvokeNodeAsync(string nodeGuid)
|
public async Task<object> InvokeNodeAsync(string nodeGuid)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
if(this.NodeModels.TryGetValue(nodeGuid, out var model))
|
if(this.NodeModels.TryGetValue(nodeGuid, out var model))
|
||||||
{
|
{
|
||||||
return await model.ExecutingAsync(null);
|
return await model.InvokeAsync(this);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -435,18 +431,7 @@ namespace Serein.NodeFlow.Env
|
|||||||
{
|
{
|
||||||
ChannelFlowInterrupt?.CancelAllTasks();
|
ChannelFlowInterrupt?.CancelAllTasks();
|
||||||
flowStarter?.Exit();
|
flowStarter?.Exit();
|
||||||
|
|
||||||
foreach (var node in NodeModels.Values)
|
|
||||||
{
|
|
||||||
if (node is not null)
|
|
||||||
{
|
|
||||||
node.ReleaseFlowData(); // 退出时释放对象计数
|
|
||||||
}
|
|
||||||
}
|
|
||||||
UIContextOperation?.Invoke(() => OnFlowRunComplete?.Invoke(new FlowEventArgs()));
|
UIContextOperation?.Invoke(() => OnFlowRunComplete?.Invoke(new FlowEventArgs()));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GC.Collect();
|
GC.Collect();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -489,7 +474,6 @@ namespace Serein.NodeFlow.Env
|
|||||||
/// 获取当前环境信息(远程连接)
|
/// 获取当前环境信息(远程连接)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
// [AutoSocketHandle]
|
|
||||||
public async Task<FlowEnvInfo> GetEnvInfoAsync()
|
public async Task<FlowEnvInfo> GetEnvInfoAsync()
|
||||||
{
|
{
|
||||||
Dictionary<NodeLibrary, List<MethodDetailsInfo>> LibraryMds = [];
|
Dictionary<NodeLibrary, List<MethodDetailsInfo>> LibraryMds = [];
|
||||||
@@ -574,12 +558,6 @@ namespace Serein.NodeFlow.Env
|
|||||||
{
|
{
|
||||||
MethodDetailss.TryGetValue(nodeInfo.MethodName, out methodDetails);// 加载项目时尝试获取方法信息
|
MethodDetailss.TryGetValue(nodeInfo.MethodName, out methodDetails);// 加载项目时尝试获取方法信息
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
var nodeModel = FlowFunc.CreateNode(this, controlType, methodDetails); // 加载项目时创建节点
|
var nodeModel = FlowFunc.CreateNode(this, controlType, methodDetails); // 加载项目时创建节点
|
||||||
nodeModel.LoadInfo(nodeInfo); // 创建节点model
|
nodeModel.LoadInfo(nodeInfo); // 创建节点model
|
||||||
if (nodeModel is null)
|
if (nodeModel is null)
|
||||||
@@ -588,7 +566,6 @@ namespace Serein.NodeFlow.Env
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TryAddNode(nodeModel); // 加载项目时将节点加载到环境中
|
TryAddNode(nodeModel); // 加载项目时将节点加载到环境中
|
||||||
if (nodeInfo.ChildNodeGuids?.Length > 0)
|
if (nodeInfo.ChildNodeGuids?.Length > 0)
|
||||||
{
|
{
|
||||||
@@ -643,6 +620,7 @@ namespace Serein.NodeFlow.Env
|
|||||||
Task.Run(async () =>
|
Task.Run(async () =>
|
||||||
{
|
{
|
||||||
await Task.Delay(777);
|
await Task.Delay(777);
|
||||||
|
#region 方法调用关系
|
||||||
foreach (var nodeInfo in projectData.Nodes)
|
foreach (var nodeInfo in projectData.Nodes)
|
||||||
{
|
{
|
||||||
if (!NodeModels.TryGetValue(nodeInfo.Guid, out NodeModelBase? fromNode))
|
if (!NodeModels.TryGetValue(nodeInfo.Guid, out NodeModelBase? fromNode))
|
||||||
@@ -650,8 +628,6 @@ namespace Serein.NodeFlow.Env
|
|||||||
// 不存在对应的起始节点
|
// 不存在对应的起始节点
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
List<(ConnectionInvokeType connectionType, string[] guids)> allToNodes = [(ConnectionInvokeType.IsSucceed,nodeInfo.TrueNodes),
|
List<(ConnectionInvokeType connectionType, string[] guids)> allToNodes = [(ConnectionInvokeType.IsSucceed,nodeInfo.TrueNodes),
|
||||||
(ConnectionInvokeType.IsFail, nodeInfo.FalseNodes),
|
(ConnectionInvokeType.IsFail, nodeInfo.FalseNodes),
|
||||||
(ConnectionInvokeType.IsError, nodeInfo.ErrorNodes),
|
(ConnectionInvokeType.IsError, nodeInfo.ErrorNodes),
|
||||||
@@ -670,8 +646,24 @@ namespace Serein.NodeFlow.Env
|
|||||||
{
|
{
|
||||||
_ = ConnectInvokeOfNode(fromNode, toNode, item.connectionType); // 加载时确定节点间的连接关系
|
_ = ConnectInvokeOfNode(fromNode, toNode, item.connectionType); // 加载时确定节点间的连接关系
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
#region 参数调用关系
|
||||||
|
foreach (var toNode in NodeModels.Values)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < toNode.MethodDetails.ParameterDetailss.Length; i++)
|
||||||
|
{
|
||||||
|
var pd = toNode.MethodDetails.ParameterDetailss[i];
|
||||||
|
if (!string.IsNullOrEmpty(pd.ArgDataSourceNodeGuid)
|
||||||
|
&& NodeModels.TryGetValue(pd.ArgDataSourceNodeGuid, out var fromNode))
|
||||||
|
{
|
||||||
|
|
||||||
|
ConnectGerResultOfNode(fromNode, toNode, pd.ArgDataSourceType, pd.Index);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
});
|
});
|
||||||
|
|
||||||
SetStartNode(projectData.StartNode);
|
SetStartNode(projectData.StartNode);
|
||||||
@@ -686,7 +678,7 @@ namespace Serein.NodeFlow.Env
|
|||||||
/// <param name="addres">远程环境地址</param>
|
/// <param name="addres">远程环境地址</param>
|
||||||
/// <param name="port">远程环境端口</param>
|
/// <param name="port">远程环境端口</param>
|
||||||
/// <param name="token">密码</param>
|
/// <param name="token">密码</param>
|
||||||
public async Task<(bool, RemoteEnvControl)> ConnectRemoteEnv(string addres, int port, string token)
|
public async Task<(bool, RemoteMsgUtil)> ConnectRemoteEnv(string addres, int port, string token)
|
||||||
{
|
{
|
||||||
if (IsLcR)
|
if (IsLcR)
|
||||||
{
|
{
|
||||||
@@ -695,7 +687,7 @@ namespace Serein.NodeFlow.Env
|
|||||||
}
|
}
|
||||||
// 没有连接远程环境,可以重新连接
|
// 没有连接远程环境,可以重新连接
|
||||||
|
|
||||||
var controlConfiguration = new RemoteEnvControl.ControlConfiguration
|
var controlConfiguration = new RemoteMsgUtil.ControlConfiguration
|
||||||
{
|
{
|
||||||
Addres = addres,
|
Addres = addres,
|
||||||
Port = port,
|
Port = port,
|
||||||
@@ -704,8 +696,8 @@ namespace Serein.NodeFlow.Env
|
|||||||
MsgIdJsonKey = FlowEnvironment.MsgIdKey,
|
MsgIdJsonKey = FlowEnvironment.MsgIdKey,
|
||||||
DataJsonKey = FlowEnvironment.DataKey,
|
DataJsonKey = FlowEnvironment.DataKey,
|
||||||
};
|
};
|
||||||
var remoteEnvControl = new RemoteEnvControl(controlConfiguration);
|
var remoteMsgUtil = new RemoteMsgUtil(controlConfiguration);
|
||||||
var result = await remoteEnvControl.ConnectAsync();
|
var result = await remoteMsgUtil.ConnectAsync();
|
||||||
if (!result)
|
if (!result)
|
||||||
{
|
{
|
||||||
await Console.Out.WriteLineAsync("连接失败,请检查地址与端口是否正确");
|
await Console.Out.WriteLineAsync("连接失败,请检查地址与端口是否正确");
|
||||||
@@ -713,7 +705,7 @@ namespace Serein.NodeFlow.Env
|
|||||||
}
|
}
|
||||||
await Console.Out.WriteLineAsync("连接成功,开始验证Token");
|
await Console.Out.WriteLineAsync("连接成功,开始验证Token");
|
||||||
IsLcR = true;
|
IsLcR = true;
|
||||||
return (true, remoteEnvControl);
|
return (true, remoteMsgUtil);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -908,19 +900,18 @@ namespace Serein.NodeFlow.Env
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 连接节点
|
/// 连接节点,创建方法调用关系
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="fromNodeGuid">起始节点</param>
|
/// <param name="fromNodeGuid">起始节点</param>
|
||||||
/// <param name="toNodeGuid">目标节点</param>
|
/// <param name="toNodeGuid">目标节点</param>
|
||||||
/// <param name="fromNodeJunctionType">起始节点控制点</param>
|
/// <param name="fromNodeJunctionType">起始节点控制点</param>
|
||||||
/// <param name="toNodeJunctionType">目标节点控制点</param>
|
/// <param name="toNodeJunctionType">目标节点控制点</param>
|
||||||
/// <param name="connectionType">连接关系</param>
|
/// <param name="invokeType">连接关系</param>
|
||||||
public async Task<bool> ConnectNodeAsync(string fromNodeGuid,
|
public async Task<bool> ConnectInvokeNodeAsync(string fromNodeGuid,
|
||||||
string toNodeGuid,
|
string toNodeGuid,
|
||||||
JunctionType fromNodeJunctionType,
|
JunctionType fromNodeJunctionType,
|
||||||
JunctionType toNodeJunctionType,
|
JunctionType toNodeJunctionType,
|
||||||
ConnectionInvokeType connectionType,
|
ConnectionInvokeType invokeType)
|
||||||
int argIndex)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
// 获取起始节点与目标节点
|
// 获取起始节点与目标节点
|
||||||
@@ -943,22 +934,43 @@ namespace Serein.NodeFlow.Env
|
|||||||
(fromNode, toNode) = (toNode, fromNode);
|
(fromNode, toNode) = (toNode, fromNode);
|
||||||
}
|
}
|
||||||
// 从起始节点“下一个方法”控制点,连接到目标节点“方法调用”控制点
|
// 从起始节点“下一个方法”控制点,连接到目标节点“方法调用”控制点
|
||||||
state = ConnectInvokeOfNode(fromNode, toNode, connectionType); // 本地环境进行连接
|
state = ConnectInvokeOfNode(fromNode, toNode, invokeType); // 本地环境进行连接
|
||||||
}
|
}
|
||||||
else if (type == JunctionOfConnectionType.Arg)
|
return state;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建节点之间的参数来源关系
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fromNodeGuid">起始节点</param>
|
||||||
|
/// <param name="toNodeGuid">目标节点</param>
|
||||||
|
/// <param name="fromNodeJunctionType">起始节点控制点(result控制点)</param>
|
||||||
|
/// <param name="toNodeJunctionType">目标节点控制点(argData控制点)</param>
|
||||||
|
/// <param name="argIndex">目标节点的第几个参数</param>
|
||||||
|
/// <param name="connectionArgSourceType">调用目标节点对应方法时,对应参数来源类型</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<bool> ConnectArgSourceNodeAsync(string fromNodeGuid,
|
||||||
|
string toNodeGuid,
|
||||||
|
JunctionType fromNodeJunctionType,
|
||||||
|
JunctionType toNodeJunctionType,
|
||||||
|
ConnectionArgSourceType connectionArgSourceType,
|
||||||
|
int argIndex)
|
||||||
|
{
|
||||||
|
|
||||||
|
// 获取起始节点与目标节点
|
||||||
|
var fromNode = GuidToModel(fromNodeGuid);
|
||||||
|
var toNode = GuidToModel(toNodeGuid);
|
||||||
|
if (fromNode is null || toNode is null) return false;
|
||||||
|
(var type, var state) = CheckConnect(fromNode, toNode, fromNodeJunctionType, toNodeJunctionType);
|
||||||
|
if (!state)
|
||||||
{
|
{
|
||||||
ConnectionArgSourceType connectionArgSourceType;
|
Console.WriteLine("出现非预期的连接行为");
|
||||||
|
return false; // 出现不符预期的连接行为,忽略此次连接行为
|
||||||
|
}
|
||||||
|
|
||||||
if (fromNode.Guid.Equals(toNode.Guid))
|
if (type == JunctionOfConnectionType.Arg)
|
||||||
{
|
{
|
||||||
connectionArgSourceType = ConnectionArgSourceType.GetPreviousNodeData;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
connectionArgSourceType = ConnectionArgSourceType.GetOtherNodeData;
|
|
||||||
}
|
|
||||||
|
|
||||||
// (连接自身的情况下)从上一个节点“返回值”控制点,连接到目标节点“方法入参”控制点
|
|
||||||
// 从起始节点“返回值”控制点,连接到目标节点“方法入参”控制点
|
// 从起始节点“返回值”控制点,连接到目标节点“方法入参”控制点
|
||||||
if (fromNodeJunctionType == JunctionType.ArgData)
|
if (fromNodeJunctionType == JunctionType.ArgData)
|
||||||
{
|
{
|
||||||
@@ -966,32 +978,48 @@ namespace Serein.NodeFlow.Env
|
|||||||
(fromNode, toNode) = (toNode, fromNode);
|
(fromNode, toNode) = (toNode, fromNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 确定方法入参关系
|
// 确定方法入参关系
|
||||||
state = ConnectGerResultOfNode(fromNode, toNode, connectionArgSourceType, argIndex); // 本地环境进行连接
|
state = ConnectGerResultOfNode(fromNode, toNode, connectionArgSourceType, argIndex); // 本地环境进行连接
|
||||||
}
|
}
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 移除连接关系
|
/// 移除连接节点之间方法调用的关系
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="fromNodeGuid">起始节点Guid</param>
|
/// <param name="fromNodeGuid">起始节点Guid</param>
|
||||||
/// <param name="toNodeGuid">目标节点Guid</param>
|
/// <param name="toNodeGuid">目标节点Guid</param>
|
||||||
/// <param name="connectionType">连接关系</param>
|
/// <param name="connectionType">连接关系</param>
|
||||||
/// <exception cref="NotImplementedException"></exception>
|
/// <exception cref="NotImplementedException"></exception>
|
||||||
public async Task<bool> RemoveConnectAsync(string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType)
|
public async Task<bool> RemoveConnectInvokeAsync(string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType)
|
||||||
{
|
{
|
||||||
// 获取起始节点与目标节点
|
// 获取起始节点与目标节点
|
||||||
var fromNode = GuidToModel(fromNodeGuid);
|
var fromNode = GuidToModel(fromNodeGuid);
|
||||||
var toNode = GuidToModel(toNodeGuid);
|
var toNode = GuidToModel(toNodeGuid);
|
||||||
if (fromNode is null || toNode is null) return false;
|
if (fromNode is null || toNode is null) return false;
|
||||||
|
|
||||||
var result = await RemoteConnectAsync(fromNode, toNode, connectionType);
|
var result = await RemoteConnectAsync(fromNode, toNode, connectionType);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 移除连接节点之间参数传递的关系
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fromNodeGuid">起始节点Guid</param>
|
||||||
|
/// <param name="toNodeGuid">目标节点Guid</param>
|
||||||
|
/// <param name="argIndex">连接到第几个参数</param>
|
||||||
|
public async Task<bool> RemoveConnectArgSourceAsync(string fromNodeGuid, string toNodeGuid, int argIndex)
|
||||||
|
{
|
||||||
|
// 获取起始节点与目标节点
|
||||||
|
var fromNode = GuidToModel(fromNodeGuid);
|
||||||
|
var toNode = GuidToModel(toNodeGuid);
|
||||||
|
if (fromNode is null || toNode is null) return false;
|
||||||
|
var result = await RemoteConnectAsync(fromNode, toNode, argIndex);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取方法描述
|
/// 获取方法描述
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1077,41 +1105,39 @@ namespace Serein.NodeFlow.Env
|
|||||||
/// <param name="nodeGuid">被中断的目标节点Guid</param>
|
/// <param name="nodeGuid">被中断的目标节点Guid</param>
|
||||||
/// <param name="interruptClass">中断级别</param>
|
/// <param name="interruptClass">中断级别</param>
|
||||||
/// <returns>操作是否成功</returns>
|
/// <returns>操作是否成功</returns>
|
||||||
public Task<bool> SetNodeInterruptAsync(string nodeGuid, InterruptClass interruptClass)
|
public Task<bool> SetNodeInterruptAsync(string nodeGuid, bool isInterrupt)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
var nodeModel = GuidToModel(nodeGuid);
|
var nodeModel = GuidToModel(nodeGuid);
|
||||||
if (nodeModel is null)
|
if (nodeModel is null)
|
||||||
return Task.FromResult(false);
|
return Task.FromResult(false);
|
||||||
if (interruptClass == InterruptClass.None)
|
if (!isInterrupt)
|
||||||
{
|
{
|
||||||
nodeModel.CancelInterrupt();
|
nodeModel.CancelInterrupt();
|
||||||
}
|
}
|
||||||
else if (interruptClass == InterruptClass.Branch)
|
else if (isInterrupt)
|
||||||
{
|
{
|
||||||
nodeModel.DebugSetting.CancelInterruptCallback?.Invoke();
|
nodeModel.DebugSetting.CancelInterruptCallback?.Invoke();
|
||||||
nodeModel.DebugSetting.GetInterruptTask = async () =>
|
nodeModel.DebugSetting.GetInterruptTask = async () =>
|
||||||
{
|
{
|
||||||
TriggerInterrupt(nodeGuid, "", InterruptTriggerEventArgs.InterruptTriggerType.Monitor);
|
TriggerInterrupt(nodeGuid, "", InterruptTriggerEventArgs.InterruptTriggerType.Monitor);
|
||||||
var result = await ChannelFlowInterrupt.GetOrCreateChannelAsync(nodeGuid);
|
var result = await ChannelFlowInterrupt.GetOrCreateChannelAsync(nodeGuid);
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
nodeModel.DebugSetting.CancelInterruptCallback = () =>
|
nodeModel.DebugSetting.CancelInterruptCallback = () =>
|
||||||
{
|
{
|
||||||
|
//nodeModel.DebugSetting.IsInterrupt = false;
|
||||||
ChannelFlowInterrupt.TriggerSignal(nodeGuid);
|
ChannelFlowInterrupt.TriggerSignal(nodeGuid);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (interruptClass == InterruptClass.Global) // 全局……做不了omg
|
|
||||||
{
|
//nodeModel.DebugSetting.IsInterrupt = true;
|
||||||
return Task.FromResult(false);
|
|
||||||
}
|
|
||||||
nodeModel.DebugSetting.InterruptClass = interruptClass;
|
|
||||||
if (OperatingSystem.IsWindows())
|
if (OperatingSystem.IsWindows())
|
||||||
{
|
{
|
||||||
|
|
||||||
UIContextOperation?.Invoke(() => OnNodeInterruptStateChange?.Invoke(new NodeInterruptStateChangeEventArgs(nodeGuid, interruptClass)));
|
UIContextOperation?.Invoke(() => OnNodeInterruptStateChange?.Invoke(new NodeInterruptStateChangeEventArgs(nodeGuid, isInterrupt)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task.FromResult(true);
|
return Task.FromResult(true);
|
||||||
@@ -1311,10 +1337,6 @@ namespace Serein.NodeFlow.Env
|
|||||||
|
|
||||||
#region 私有方法
|
#region 私有方法
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 加载指定路径的DLL文件
|
/// 加载指定路径的DLL文件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1375,11 +1397,31 @@ namespace Serein.NodeFlow.Env
|
|||||||
connectionType,
|
connectionType,
|
||||||
NodeConnectChangeEventArgs.ConnectChangeType.Remote)));
|
NodeConnectChangeEventArgs.ConnectChangeType.Remote)));
|
||||||
}
|
}
|
||||||
//else if (OperatingSystem.IsLinux())
|
return true;
|
||||||
//{
|
}
|
||||||
|
/// <summary>
|
||||||
//}
|
/// 移除连接关系
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fromNodeGuid">起始节点Model</param>
|
||||||
|
/// <param name="toNodeGuid">目标节点Model</param>
|
||||||
|
/// <param name="connectionType">连接关系</param>
|
||||||
|
/// <exception cref="NotImplementedException"></exception>
|
||||||
|
private async Task<bool> RemoteConnectAsync(NodeModelBase fromNode, NodeModelBase toNode, int argIndex)
|
||||||
|
{
|
||||||
|
|
||||||
|
toNode.MethodDetails.ParameterDetailss[argIndex].ArgDataSourceNodeGuid = null;
|
||||||
|
toNode.MethodDetails.ParameterDetailss[argIndex].ArgDataSourceType = ConnectionArgSourceType.GetPreviousNodeData; // 恢复默认值
|
||||||
|
|
||||||
|
if (OperatingSystem.IsWindows())
|
||||||
|
{
|
||||||
|
await UIContextOperation.InvokeAsync(() => OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(
|
||||||
|
fromNode.Guid,
|
||||||
|
toNode.Guid,
|
||||||
|
JunctionOfConnectionType.Arg,
|
||||||
|
argIndex,
|
||||||
|
ConnectionArgSourceType.GetPreviousNodeData,
|
||||||
|
NodeConnectChangeEventArgs.ConnectChangeType.Remote)));
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1479,13 +1521,10 @@ namespace Serein.NodeFlow.Env
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建节点
|
/// 创建节点
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="nodeBase"></param>
|
/// <param name="nodeBase"></param>
|
||||||
|
|
||||||
private bool TryAddNode(NodeModelBase nodeModel)
|
private bool TryAddNode(NodeModelBase nodeModel)
|
||||||
{
|
{
|
||||||
nodeModel.Guid ??= Guid.NewGuid().ToString();
|
nodeModel.Guid ??= Guid.NewGuid().ToString();
|
||||||
@@ -1503,10 +1542,6 @@ namespace Serein.NodeFlow.Env
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 检查连接
|
/// 检查连接
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1530,12 +1565,12 @@ namespace Serein.NodeFlow.Env
|
|||||||
type = JunctionOfConnectionType.Invoke;
|
type = JunctionOfConnectionType.Invoke;
|
||||||
state = true;
|
state = true;
|
||||||
}
|
}
|
||||||
else if (toNodeJunctionType == JunctionType.ArgData && fromNode.Guid.Equals(toNode.Guid))
|
//else if (toNodeJunctionType == JunctionType.ArgData && fromNode.Guid.Equals(toNode.Guid))
|
||||||
{
|
//{
|
||||||
// “方法执行”控制点拖拽到“方法入参”控制点,且是同一个节点,则添加获取参数关系,表示生成入参参数时自动从该节点的上一节点获取flowdata
|
// // “方法执行”控制点拖拽到“方法入参”控制点,且是同一个节点,则添加获取参数关系,表示生成入参参数时自动从该节点的上一节点获取flowdata
|
||||||
type = JunctionOfConnectionType.Arg;
|
// type = JunctionOfConnectionType.Arg;
|
||||||
state = true;
|
// state = true;
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
else if (fromNodeJunctionType == JunctionType.NextStep && !fromNode.Guid.Equals(toNode.Guid))
|
else if (fromNodeJunctionType == JunctionType.NextStep && !fromNode.Guid.Equals(toNode.Guid))
|
||||||
{
|
{
|
||||||
@@ -1548,12 +1583,12 @@ namespace Serein.NodeFlow.Env
|
|||||||
}
|
}
|
||||||
else if (fromNodeJunctionType == JunctionType.ArgData)
|
else if (fromNodeJunctionType == JunctionType.ArgData)
|
||||||
{
|
{
|
||||||
if (toNodeJunctionType == JunctionType.Execute && fromNode.Guid.Equals(toNode.Guid)) // 添加获取参数关系
|
//if (toNodeJunctionType == JunctionType.Execute && fromNode.Guid.Equals(toNode.Guid)) // 添加获取参数关系
|
||||||
{
|
//{
|
||||||
// “方法入参”控制点拖拽到“方法执行”控制点,且是同一个节点,则添加获取参数关系,生成入参参数时自动从该节点的上一节点获取flowdata
|
// // “方法入参”控制点拖拽到“方法执行”控制点,且是同一个节点,则添加获取参数关系,生成入参参数时自动从该节点的上一节点获取flowdata
|
||||||
type = JunctionOfConnectionType.Arg;
|
// type = JunctionOfConnectionType.Arg;
|
||||||
state = true;
|
// state = true;
|
||||||
}
|
//}
|
||||||
if(toNodeJunctionType == JunctionType.ReturnData && !fromNode.Guid.Equals(toNode.Guid))
|
if(toNodeJunctionType == JunctionType.ReturnData && !fromNode.Guid.Equals(toNode.Guid))
|
||||||
{
|
{
|
||||||
// “”控制点拖拽到“方法返回值”控制点,且不是同一个节点,添加获取参数关系,生成参数时从目标节点获取flowdata
|
// “”控制点拖拽到“方法返回值”控制点,且不是同一个节点,添加获取参数关系,生成参数时从目标节点获取flowdata
|
||||||
@@ -1574,14 +1609,13 @@ namespace Serein.NodeFlow.Env
|
|||||||
return (type,state);
|
return (type,state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 连接节点
|
/// 连接节点
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="fromNode">起始节点</param>
|
/// <param name="fromNode">起始节点</param>
|
||||||
/// <param name="toNode">目标节点</param>
|
/// <param name="toNode">目标节点</param>
|
||||||
/// <param name="connectionType">连接关系</param>
|
/// <param name="invokeType">连接关系</param>
|
||||||
private bool ConnectInvokeOfNode(NodeModelBase fromNode, NodeModelBase toNode, ConnectionInvokeType connectionType)
|
private bool ConnectInvokeOfNode(NodeModelBase fromNode, NodeModelBase toNode, ConnectionInvokeType invokeType)
|
||||||
{
|
{
|
||||||
if (fromNode is null || toNode is null || fromNode == toNode)
|
if (fromNode is null || toNode is null || fromNode == toNode)
|
||||||
{
|
{
|
||||||
@@ -1634,17 +1668,19 @@ namespace Serein.NodeFlow.Env
|
|||||||
}
|
}
|
||||||
if (isPass)
|
if (isPass)
|
||||||
{
|
{
|
||||||
fromNode.SuccessorNodes[connectionType].Add(toNode); // 添加到起始节点的子分支
|
|
||||||
toNode.PreviousNodes[connectionType].Add(fromNode); // 添加到目标节点的父分支
|
fromNode.SuccessorNodes[invokeType].Add(toNode); // 添加到起始节点的子分支
|
||||||
|
toNode.PreviousNodes[invokeType].Add(fromNode); // 添加到目标节点的父分支
|
||||||
if (OperatingSystem.IsWindows())
|
if (OperatingSystem.IsWindows())
|
||||||
{
|
{
|
||||||
|
|
||||||
UIContextOperation?.Invoke(() =>
|
UIContextOperation?.Invoke(() =>
|
||||||
OnNodeConnectChange?.Invoke(
|
OnNodeConnectChange?.Invoke(
|
||||||
new NodeConnectChangeEventArgs(
|
new NodeConnectChangeEventArgs(
|
||||||
fromNode.Guid, // 从哪个节点开始
|
fromNode.Guid, // 从哪个节点开始
|
||||||
toNode.Guid, // 连接到那个节点
|
toNode.Guid, // 连接到那个节点
|
||||||
JunctionOfConnectionType.Invoke,
|
JunctionOfConnectionType.Invoke,
|
||||||
connectionType, // 连接线的样式类型
|
invokeType, // 连接线的样式类型
|
||||||
NodeConnectChangeEventArgs.ConnectChangeType.Create // 是创建连接还是删除连接
|
NodeConnectChangeEventArgs.ConnectChangeType.Create // 是创建连接还是删除连接
|
||||||
))); // 通知UI
|
))); // 通知UI
|
||||||
}
|
}
|
||||||
@@ -1668,8 +1704,13 @@ namespace Serein.NodeFlow.Env
|
|||||||
/// <param name="connectionArgSourceType"></param>
|
/// <param name="connectionArgSourceType"></param>
|
||||||
/// <param name="argIndex"></param>
|
/// <param name="argIndex"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private bool ConnectGerResultOfNode(NodeModelBase fromNode, NodeModelBase toNode, ConnectionArgSourceType connectionArgSourceType,int argIndex)
|
private bool ConnectGerResultOfNode(NodeModelBase fromNode,
|
||||||
|
NodeModelBase toNode,
|
||||||
|
ConnectionArgSourceType connectionArgSourceType,
|
||||||
|
int argIndex)
|
||||||
{
|
{
|
||||||
|
toNode.MethodDetails.ParameterDetailss[argIndex].ArgDataSourceNodeGuid = fromNode.Guid;
|
||||||
|
toNode.MethodDetails.ParameterDetailss[argIndex].ArgDataSourceType = connectionArgSourceType;
|
||||||
UIContextOperation?.Invoke(() =>
|
UIContextOperation?.Invoke(() =>
|
||||||
OnNodeConnectChange?.Invoke(
|
OnNodeConnectChange?.Invoke(
|
||||||
new NodeConnectChangeEventArgs(
|
new NodeConnectChangeEventArgs(
|
||||||
@@ -1680,7 +1721,7 @@ namespace Serein.NodeFlow.Env
|
|||||||
connectionArgSourceType,
|
connectionArgSourceType,
|
||||||
NodeConnectChangeEventArgs.ConnectChangeType.Create // 是创建连接还是删除连接
|
NodeConnectChangeEventArgs.ConnectChangeType.Create // 是创建连接还是删除连接
|
||||||
))); // 通知UI
|
))); // 通知UI
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Serein.Library;
|
using Serein.Library;
|
||||||
using Serein.Library.Api;
|
using Serein.Library.Api;
|
||||||
|
using Serein.Library.FlowNode;
|
||||||
using Serein.Library.Utils;
|
using Serein.Library.Utils;
|
||||||
|
|
||||||
namespace Serein.NodeFlow.Env
|
namespace Serein.NodeFlow.Env
|
||||||
@@ -33,22 +34,22 @@ namespace Serein.NodeFlow.Env
|
|||||||
private IFlowEnvironment currentFlowEnvironment;
|
private IFlowEnvironment currentFlowEnvironment;
|
||||||
|
|
||||||
|
|
||||||
private int _flag = 0; // 使用原子自增代替锁
|
private int _loadingProjectFlag = 0; // 使用原子自增代替锁
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 传入false时,将停止数据通知。传入true时,
|
/// 传入false时,将停止数据通知。传入true时,
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="value"></param>
|
/// <param name="value"></param>
|
||||||
public void SetFlag(bool value)
|
public void SetProjectLoadingFlag(bool value)
|
||||||
{
|
{
|
||||||
Interlocked.Exchange(ref _flag, value ? 1 : 0);
|
Interlocked.Exchange(ref _loadingProjectFlag, value ? 1 : 0);
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// 判断是否正在加载项目
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public bool IsFlagSet()
|
public bool IsLoadingProject()
|
||||||
{
|
{
|
||||||
return Interlocked.CompareExchange(ref _flag, 1, 1) == 1;
|
return Interlocked.CompareExchange(ref _loadingProjectFlag, 1, 1) == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -180,34 +181,69 @@ namespace Serein.NodeFlow.Env
|
|||||||
currentFlowEnvironment.ClearAll();
|
currentFlowEnvironment.ClearAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> ConnectNodeAsync(string fromNodeGuid,
|
/// <summary>
|
||||||
|
/// 在两个节点之间创建连接关系
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fromNodeGuid">起始节点Guid</param>
|
||||||
|
/// <param name="toNodeGuid">目标节点Guid</param>
|
||||||
|
/// <param name="fromNodeJunctionType">起始节点控制点</param>
|
||||||
|
/// <param name="toNodeJunctionType">目标节点控制点</param>
|
||||||
|
/// <param name="invokeType">决定了方法执行后的后继行为</param>
|
||||||
|
public async Task<bool> ConnectInvokeNodeAsync(string fromNodeGuid,
|
||||||
string toNodeGuid,
|
string toNodeGuid,
|
||||||
JunctionType fromNodeJunctionType,
|
JunctionType fromNodeJunctionType,
|
||||||
JunctionType toNodeJunctionType,
|
JunctionType toNodeJunctionType,
|
||||||
ConnectionInvokeType connectionType,
|
ConnectionInvokeType invokeType)
|
||||||
int argIndex)
|
|
||||||
{
|
{
|
||||||
return await currentFlowEnvironment.ConnectNodeAsync(fromNodeGuid, toNodeGuid, fromNodeJunctionType, toNodeJunctionType, connectionType, argIndex);
|
return await currentFlowEnvironment.ConnectInvokeNodeAsync(fromNodeGuid, toNodeGuid, fromNodeJunctionType, toNodeJunctionType, invokeType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<(bool, RemoteEnvControl)> ConnectRemoteEnv(string addres, int port, string token)
|
|
||||||
|
/// <summary>
|
||||||
|
/// 在两个节点之间创建连接关系
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fromNodeGuid">起始节点Guid</param>
|
||||||
|
/// <param name="toNodeGuid">目标节点Guid</param>
|
||||||
|
/// <param name="fromNodeJunctionType">起始节点控制点</param>
|
||||||
|
/// <param name="toNodeJunctionType">目标节点控制点</param>
|
||||||
|
/// <param name="argSourceType">决定了方法参数来源</param>
|
||||||
|
/// <param name="argIndex">设置第几个参数</param>
|
||||||
|
public async Task<bool> ConnectArgSourceNodeAsync(string fromNodeGuid,
|
||||||
|
string toNodeGuid,
|
||||||
|
JunctionType fromNodeJunctionType,
|
||||||
|
JunctionType toNodeJunctionType,
|
||||||
|
ConnectionArgSourceType argSourceType,
|
||||||
|
int argIndex)
|
||||||
|
{
|
||||||
|
return await currentFlowEnvironment.ConnectArgSourceNodeAsync(fromNodeGuid, toNodeGuid, fromNodeJunctionType, toNodeJunctionType, argSourceType, argIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 连接远程环境并自动切换环境
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="addres"></param>
|
||||||
|
/// <param name="port"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<(bool, RemoteMsgUtil)> ConnectRemoteEnv(string addres, int port, string token)
|
||||||
{
|
{
|
||||||
// 连接成功,切换远程环境
|
// 连接成功,切换远程环境
|
||||||
(var isConnect, var remoteEnvControl) = await currentFlowEnvironment.ConnectRemoteEnv(addres, port, token);
|
(var isConnect, var remoteMsgUtil) = await currentFlowEnvironment.ConnectRemoteEnv(addres, port, token);
|
||||||
if (isConnect)
|
if (isConnect)
|
||||||
{
|
{
|
||||||
|
|
||||||
remoteFlowEnvironment ??= new RemoteFlowEnvironment(remoteEnvControl, this.UIContextOperation);
|
remoteFlowEnvironment ??= new RemoteFlowEnvironment(remoteMsgUtil, this.UIContextOperation);
|
||||||
currentFlowEnvironment = remoteFlowEnvironment;
|
currentFlowEnvironment = remoteFlowEnvironment;
|
||||||
}
|
}
|
||||||
return (isConnect, remoteEnvControl);
|
return (isConnect, remoteMsgUtil);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<NodeInfo> CreateNodeAsync(NodeControlType nodeBase, PositionOfUI position, MethodDetailsInfo methodDetailsInfo = null)
|
public async Task<NodeInfo> CreateNodeAsync(NodeControlType nodeBase, PositionOfUI position, MethodDetailsInfo methodDetailsInfo = null)
|
||||||
{
|
{
|
||||||
SetFlag(false);
|
SetProjectLoadingFlag(false);
|
||||||
var result = await currentFlowEnvironment.CreateNodeAsync(nodeBase, position, methodDetailsInfo); // 装饰器调用
|
var result = await currentFlowEnvironment.CreateNodeAsync(nodeBase, position, methodDetailsInfo); // 装饰器调用
|
||||||
SetFlag(true);
|
SetProjectLoadingFlag(true);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,9 +285,9 @@ namespace Serein.NodeFlow.Env
|
|||||||
public void LoadProject(FlowEnvInfo flowEnvInfo, string filePath)
|
public void LoadProject(FlowEnvInfo flowEnvInfo, string filePath)
|
||||||
{
|
{
|
||||||
if (flowEnvInfo is null) return;
|
if (flowEnvInfo is null) return;
|
||||||
SetFlag(false);
|
SetProjectLoadingFlag(false);
|
||||||
currentFlowEnvironment.LoadProject(flowEnvInfo, filePath);
|
currentFlowEnvironment.LoadProject(flowEnvInfo, filePath);
|
||||||
SetFlag(true);
|
SetProjectLoadingFlag(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void MonitorObjectNotification(string nodeGuid, object monitorData, MonitorObjectEventArgs.ObjSourceType sourceType)
|
public void MonitorObjectNotification(string nodeGuid, object monitorData, MonitorObjectEventArgs.ObjSourceType sourceType)
|
||||||
@@ -275,9 +311,21 @@ namespace Serein.NodeFlow.Env
|
|||||||
return currentFlowEnvironment.RemoteDll(assemblyFullName);
|
return currentFlowEnvironment.RemoteDll(assemblyFullName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> RemoveConnectAsync(string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType)
|
public async Task<bool> RemoveConnectInvokeAsync(string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType)
|
||||||
{
|
{
|
||||||
return await currentFlowEnvironment.RemoveConnectAsync(fromNodeGuid, toNodeGuid, connectionType);
|
return await currentFlowEnvironment.RemoveConnectInvokeAsync(fromNodeGuid, toNodeGuid, connectionType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 移除连接节点之间参数传递的关系
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fromNodeGuid">起始节点Guid</param>
|
||||||
|
/// <param name="toNodeGuid">目标节点Guid</param>
|
||||||
|
/// <param name="argIndex">连接到第几个参数</param>
|
||||||
|
/// <param name="connectionArgSourceType">参数来源类型</param>
|
||||||
|
public async Task<bool> RemoveConnectArgSourceAsync(string fromNodeGuid, string toNodeGuid, int argIndex)
|
||||||
|
{
|
||||||
|
return await currentFlowEnvironment.RemoveConnectArgSourceAsync(fromNodeGuid, toNodeGuid, argIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> RemoveNodeAsync(string nodeGuid)
|
public async Task<bool> RemoveNodeAsync(string nodeGuid)
|
||||||
@@ -296,9 +344,9 @@ namespace Serein.NodeFlow.Env
|
|||||||
currentFlowEnvironment.SetMonitorObjState(key, isMonitor);
|
currentFlowEnvironment.SetMonitorObjState(key, isMonitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> SetNodeInterruptAsync(string nodeGuid, InterruptClass interruptClass)
|
public async Task<bool> SetNodeInterruptAsync(string nodeGuid, bool isInterrupt)
|
||||||
{
|
{
|
||||||
return await currentFlowEnvironment.SetNodeInterruptAsync(nodeGuid, interruptClass);
|
return await currentFlowEnvironment.SetNodeInterruptAsync(nodeGuid, isInterrupt);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetStartNode(string nodeGuid)
|
public void SetStartNode(string nodeGuid)
|
||||||
@@ -359,11 +407,11 @@ namespace Serein.NodeFlow.Env
|
|||||||
|
|
||||||
public async Task NotificationNodeValueChangeAsync(string nodeGuid, string path, object value)
|
public async Task NotificationNodeValueChangeAsync(string nodeGuid, string path, object value)
|
||||||
{
|
{
|
||||||
if (!IsFlagSet())
|
if (!IsLoadingProject())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await currentFlowEnvironment.NotificationNodeValueChangeAsync(nodeGuid, path, value);
|
await currentFlowEnvironment.NotificationNodeValueChangeAsync(nodeGuid, path, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
using Serein.Library;
|
using Newtonsoft.Json;
|
||||||
|
using Serein.Library;
|
||||||
using Serein.Library.Network.WebSocketCommunication;
|
using Serein.Library.Network.WebSocketCommunication;
|
||||||
using Serein.Library.Network.WebSocketCommunication.Handle;
|
using Serein.Library.Network.WebSocketCommunication.Handle;
|
||||||
using Serein.Library.Utils;
|
using Serein.Library.Utils;
|
||||||
|
|
||||||
namespace Serein.NodeFlow.Env
|
namespace Serein.NodeFlow.Env
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 客户端的消息管理(用于处理服务端的响应)
|
/// 客户端的消息管理(用于处理服务端的响应)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -28,6 +26,14 @@ namespace Serein.NodeFlow.Env
|
|||||||
this.remoteFlowEnvironment = remoteFlowEnvironment;
|
this.remoteFlowEnvironment = remoteFlowEnvironment;
|
||||||
SendCommandFunc = func;
|
SendCommandFunc = func;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 处理需要返回的消息
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="msgId"></param>
|
||||||
|
/// <param name="theme"></param>
|
||||||
|
/// <param name="data"></param>
|
||||||
|
/// <returns></returns>
|
||||||
private async Task SendCommandAsync(string msgId, string theme, object? data)
|
private async Task SendCommandAsync(string msgId, string theme, object? data)
|
||||||
{
|
{
|
||||||
await SendCommandFunc.Invoke(msgId, theme, data);
|
await SendCommandFunc.Invoke(msgId, theme, data);
|
||||||
@@ -40,15 +46,12 @@ namespace Serein.NodeFlow.Env
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
/// <exception cref="NotImplementedException">超时触发</exception>
|
/// <exception cref="NotImplementedException">超时触发</exception>
|
||||||
public async Task SendAsync(string signal, object? data = null, int overtimeInMs = 100)
|
public async Task SendAsync(string theme, object? data = null, int overtimeInMs = 100)
|
||||||
{
|
{
|
||||||
//Console.WriteLine($"指令[{signal}],value:{JsonConvert.SerializeObject(sendData)}");
|
|
||||||
if (!DebounceHelper.CanExecute(signal, overtimeInMs))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var msgId = MsgIdHelper.GenerateId().ToString();
|
var msgId = MsgIdHelper.GenerateId().ToString();
|
||||||
await SendCommandAsync(msgId, signal, data);
|
Console.WriteLine($"[{msgId}] => {theme}");
|
||||||
|
await SendCommandAsync(msgId, theme, data); // 客户端发送消息
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -58,33 +61,13 @@ namespace Serein.NodeFlow.Env
|
|||||||
/// <exception cref="NotImplementedException">超时触发</exception>
|
/// <exception cref="NotImplementedException">超时触发</exception>
|
||||||
public async Task<TResult> SendAndWaitDataAsync<TResult>(string theme, object? data = null, int overtimeInMs = 50)
|
public async Task<TResult> SendAndWaitDataAsync<TResult>(string theme, object? data = null, int overtimeInMs = 50)
|
||||||
{
|
{
|
||||||
//Console.WriteLine($"指令[{signal}],value:{JsonConvert.SerializeObject(sendData)}");
|
|
||||||
|
|
||||||
var msgId = MsgIdHelper.GenerateId().ToString();
|
var msgId = MsgIdHelper.GenerateId().ToString();
|
||||||
_ = SendCommandAsync(msgId, theme, data);
|
//_ = Task.Run(async () =>
|
||||||
|
//{
|
||||||
|
// await Task.Delay(500);
|
||||||
|
//});
|
||||||
|
await SendCommandAsync(msgId, theme, data); // 客户端发送消息
|
||||||
return await remoteFlowEnvironment.WaitData<TResult>(msgId);
|
return await remoteFlowEnvironment.WaitData<TResult>(msgId);
|
||||||
|
|
||||||
//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;
|
|
||||||
//}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -139,15 +122,26 @@ namespace Serein.NodeFlow.Env
|
|||||||
remoteFlowEnvironment.TriggerSignal(msgId, state);
|
remoteFlowEnvironment.TriggerSignal(msgId, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AutoSocketHandle(ThemeValue = EnvMsgTheme.ConnectInvokeNode)]
|
||||||
[AutoSocketHandle(ThemeValue = EnvMsgTheme.ConnectNode)]
|
public void ConnectInvokeNode([UseMsgId] string msgId, bool state)
|
||||||
public void ConnectNode([UseMsgId] string msgId, bool state)
|
|
||||||
{
|
{
|
||||||
remoteFlowEnvironment.TriggerSignal(msgId, state);
|
remoteFlowEnvironment.TriggerSignal(msgId, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
[AutoSocketHandle(ThemeValue = EnvMsgTheme.RemoveConnect)]
|
[AutoSocketHandle(ThemeValue = EnvMsgTheme.RemoveInvokeConnect)]
|
||||||
public void RemoveConnect([UseMsgId] string msgId, bool state)
|
public void RemoveInvokeConnect([UseMsgId] string msgId, bool state)
|
||||||
|
{
|
||||||
|
remoteFlowEnvironment.TriggerSignal(msgId, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
[AutoSocketHandle(ThemeValue = EnvMsgTheme.ConnectArgSourceNode)]
|
||||||
|
public void ConnectArgSourceNode([UseMsgId] string msgId, bool state)
|
||||||
|
{
|
||||||
|
remoteFlowEnvironment.TriggerSignal(msgId, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
[AutoSocketHandle(ThemeValue = EnvMsgTheme.RemoveArgSourceConnect)]
|
||||||
|
public void RemoveArgSourceConnect([UseMsgId] string msgId, bool state)
|
||||||
{
|
{
|
||||||
remoteFlowEnvironment.TriggerSignal(msgId, state);
|
remoteFlowEnvironment.TriggerSignal(msgId, state);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -227,7 +227,8 @@ namespace Serein.NodeFlow.Env
|
|||||||
[AutoSocketHandle(ThemeValue = EnvMsgTheme.GetEnvInfo)]
|
[AutoSocketHandle(ThemeValue = EnvMsgTheme.GetEnvInfo)]
|
||||||
private async Task<FlowEnvInfo> GetEnvInfoAsync()
|
private async Task<FlowEnvInfo> GetEnvInfoAsync()
|
||||||
{
|
{
|
||||||
return await environment.GetEnvInfoAsync();
|
var envInfo = await environment.GetEnvInfoAsync();
|
||||||
|
return envInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -248,7 +249,7 @@ namespace Serein.NodeFlow.Env
|
|||||||
/// <param name="port">远程环境端口</param>
|
/// <param name="port">远程环境端口</param>
|
||||||
/// <param name="token">密码</param>
|
/// <param name="token">密码</param>
|
||||||
// [AutoSocketHandle]
|
// [AutoSocketHandle]
|
||||||
public async Task<(bool, RemoteEnvControl)> ConnectRemoteEnv(string addres, int port, string token)
|
public async Task<(bool, RemoteMsgUtil)> ConnectRemoteEnv(string addres, int port, string token)
|
||||||
{
|
{
|
||||||
return await environment.ConnectRemoteEnv(addres, port, token);
|
return await environment.ConnectRemoteEnv(addres, port, token);
|
||||||
}
|
}
|
||||||
@@ -314,7 +315,7 @@ namespace Serein.NodeFlow.Env
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 从远程环境移除节点
|
/// 远程从远程环境移除节点
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="nodeGuid"></param>
|
/// <param name="nodeGuid"></param>
|
||||||
/// <exception cref="NotImplementedException"></exception>
|
/// <exception cref="NotImplementedException"></exception>
|
||||||
@@ -324,56 +325,178 @@ namespace Serein.NodeFlow.Env
|
|||||||
//var result = environment.RemoveNodeAsync(nodeGuid).GetAwaiter().GetResult();
|
//var result = environment.RemoveNodeAsync(nodeGuid).GetAwaiter().GetResult();
|
||||||
var result = await environment.RemoveNodeAsync(nodeGuid);
|
var result = await environment.RemoveNodeAsync(nodeGuid);
|
||||||
//return result;
|
//return result;
|
||||||
return new
|
return new { state = result };
|
||||||
{
|
|
||||||
state = result
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 连接节点
|
/// 远程连接节点的方法调用关系
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="fromNodeGuid">起始节点</param>
|
/// <param name="fromNodeGuid">起始节点</param>
|
||||||
/// <param name="toNodeGuid">目标节点</param>
|
/// <param name="toNodeGuid">目标节点</param>
|
||||||
/// <param name="connectionType">连接关系</param>
|
/// <param name="fromJunctionType">起始节点控制点</param>
|
||||||
[AutoSocketHandle(ThemeValue = EnvMsgTheme.ConnectNode)]
|
/// <param name="toJunctionType">目标节点控制点</param>
|
||||||
public async Task<object> ConnectNode(string fromNodeGuid, string toNodeGuid, string connectionType)
|
/// <param name="invokeType">连接关系</param>
|
||||||
|
[AutoSocketHandle(ThemeValue = EnvMsgTheme.ConnectInvokeNode)]
|
||||||
|
public async Task<object> ConnectInvokeNode(string fromNodeGuid,
|
||||||
|
string toNodeGuid,
|
||||||
|
string fromJunctionType,
|
||||||
|
string toJunctionType,
|
||||||
|
string invokeType)
|
||||||
{
|
{
|
||||||
if (!EnumHelper.TryConvertEnum<ConnectionInvokeType>(connectionType, out var tmpConnectionType))
|
if (!EnumHelper.TryConvertEnum<ConnectionInvokeType>(invokeType, out var tmpConnectionType))
|
||||||
{
|
{
|
||||||
return new
|
return new{ state = false};
|
||||||
{
|
|
||||||
state = false
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
//environment.ConnectNodeAsync(fromNodeGuid, toNodeGuid, tmpConnectionType);
|
if (!EnumHelper.TryConvertEnum<JunctionType>(fromJunctionType, out var tmpFromJunctionType))
|
||||||
var result = await environment.ConnectNodeAsync(fromNodeGuid, toNodeGuid,0,0, tmpConnectionType,0);
|
|
||||||
return new
|
|
||||||
{
|
{
|
||||||
state = result
|
return new{ state = false};
|
||||||
};
|
}
|
||||||
|
if (!EnumHelper.TryConvertEnum<JunctionType>(toJunctionType, out var tmpToJunctionType))
|
||||||
|
{
|
||||||
|
return new{ state = false};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查控制点类别,判断此次连接请求是否符合预期
|
||||||
|
if (tmpFromJunctionType == JunctionType.Execute)
|
||||||
|
{
|
||||||
|
if (tmpToJunctionType == JunctionType.NextStep)
|
||||||
|
{
|
||||||
|
(fromNodeGuid, toNodeGuid) = (toNodeGuid, fromNodeGuid); // 需要反转
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new { state = false }; // 非预期的控制点连接
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (tmpFromJunctionType == JunctionType.NextStep)
|
||||||
|
{
|
||||||
|
if (tmpToJunctionType == JunctionType.Execute)
|
||||||
|
{
|
||||||
|
// 顺序正确无须反转
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new { state = false }; // 非预期的控制点连接
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // 其它类型的控制点,排除
|
||||||
|
{
|
||||||
|
return new { state = false }; // 非预期的控制点连接
|
||||||
|
}
|
||||||
|
Console.WriteLine();
|
||||||
|
Console.WriteLine($"起始节点:{fromNodeGuid}");
|
||||||
|
Console.WriteLine($"目标节点:{toNodeGuid}");
|
||||||
|
Console.WriteLine($"链接请求:{(tmpFromJunctionType, tmpToJunctionType)}");
|
||||||
|
|
||||||
|
var result = await environment.ConnectInvokeNodeAsync(fromNodeGuid, toNodeGuid, tmpFromJunctionType, tmpToJunctionType, tmpConnectionType);
|
||||||
|
return new { state = result };
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 移除连接关系
|
/// 远程移除节点的方法调用关系
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="fromNodeGuid">起始节点Guid</param>
|
/// <param name="fromNodeGuid">起始节点Guid</param>
|
||||||
/// <param name="toNodeGuid">目标节点Guid</param>
|
/// <param name="toNodeGuid">目标节点Guid</param>
|
||||||
/// <param name="connectionType">连接关系</param>
|
/// <param name="invokeType">连接关系</param>
|
||||||
/// <exception cref="NotImplementedException"></exception>
|
[AutoSocketHandle(ThemeValue = EnvMsgTheme.RemoveInvokeConnect)]
|
||||||
[AutoSocketHandle(ThemeValue = EnvMsgTheme.RemoveConnect)]
|
public async Task<object> RemoveInvokeConnect(string fromNodeGuid, string toNodeGuid, string invokeType)
|
||||||
public async Task<object> RemoveConnect(string fromNodeGuid, string toNodeGuid, string connectionType)
|
|
||||||
{
|
{
|
||||||
if (!EnumHelper.TryConvertEnum<ConnectionInvokeType>(connectionType, out var tmpConnectionType))
|
if (!EnumHelper.TryConvertEnum<ConnectionInvokeType>(invokeType, out var tmpConnectionType))
|
||||||
{
|
{
|
||||||
return new
|
return new
|
||||||
{
|
{
|
||||||
state = false
|
state = false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
var result = await environment.RemoveConnectInvokeAsync(fromNodeGuid, toNodeGuid, tmpConnectionType);
|
||||||
|
return new { state = result };
|
||||||
|
}
|
||||||
|
|
||||||
var result = await environment.RemoveConnectAsync(fromNodeGuid, toNodeGuid, tmpConnectionType);
|
|
||||||
|
/// <summary>
|
||||||
|
/// 远程连接节点的参数传递关系
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fromNodeGuid">起始节点</param>
|
||||||
|
/// <param name="toNodeGuid">目标节点</param>
|
||||||
|
/// <param name="fromJunctionType">起始节点控制点</param>
|
||||||
|
/// <param name="toJunctionType">目标节点控制点</param>
|
||||||
|
/// <param name="argSourceType">入参参数来源类型</param>
|
||||||
|
/// <param name="argIndex">第几个参数</param>
|
||||||
|
[AutoSocketHandle(ThemeValue = EnvMsgTheme.ConnectArgSourceNode)]
|
||||||
|
public async Task<object> ConnectArgSourceNode(string fromNodeGuid,
|
||||||
|
string toNodeGuid,
|
||||||
|
string fromJunctionType,
|
||||||
|
string toJunctionType,
|
||||||
|
string argSourceType,
|
||||||
|
int argIndex)
|
||||||
|
{
|
||||||
|
if (argIndex < 0 || argIndex > 65535) // 下标不合法
|
||||||
|
{
|
||||||
|
return new { state = false };
|
||||||
|
}
|
||||||
|
// 检查字面量是否可转换枚举类型
|
||||||
|
if (!EnumHelper.TryConvertEnum<ConnectionArgSourceType>(argSourceType, out var tmpArgSourceType))
|
||||||
|
{
|
||||||
|
return new { state = false };
|
||||||
|
}
|
||||||
|
if (!EnumHelper.TryConvertEnum<JunctionType>(fromJunctionType, out var tmpFromJunctionType))
|
||||||
|
{
|
||||||
|
return new { state = false };
|
||||||
|
}
|
||||||
|
if (!EnumHelper.TryConvertEnum<JunctionType>(toJunctionType, out var tmpToJunctionType))
|
||||||
|
{
|
||||||
|
return new { state = false };
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查控制点类别,判断此次连接请求是否符合预期
|
||||||
|
if (tmpFromJunctionType == JunctionType.ArgData)
|
||||||
|
{
|
||||||
|
if (tmpToJunctionType == JunctionType.ReturnData)
|
||||||
|
{
|
||||||
|
(fromNodeGuid, toNodeGuid) = (toNodeGuid, fromNodeGuid);// 需要反转
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new { state = false }; // 非预期的控制点连接
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (tmpFromJunctionType == JunctionType.ReturnData)
|
||||||
|
{
|
||||||
|
if (tmpToJunctionType == JunctionType.ArgData)
|
||||||
|
{
|
||||||
|
// 顺序正确无须反转
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new { state = false }; // 非预期的控制点连接
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // 其它类型的控制点,排除
|
||||||
|
{
|
||||||
|
return new { state = false }; // 非预期的控制点连接
|
||||||
|
}
|
||||||
|
//Console.WriteLine();
|
||||||
|
//Console.WriteLine($"起始节点:{fromNodeGuid}");
|
||||||
|
//Console.WriteLine($"目标节点:{toNodeGuid}");
|
||||||
|
//Console.WriteLine($"链接请求:{(tmpFromJunctionType, tmpToJunctionType)}");
|
||||||
|
// 调用环境接口进行连接
|
||||||
|
var result = await environment.ConnectArgSourceNodeAsync(fromNodeGuid, toNodeGuid, tmpFromJunctionType, tmpToJunctionType, tmpArgSourceType, argIndex);
|
||||||
|
return new { state = result };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 远程移除节点的参数传递关系
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fromNodeGuid">起始节点Guid</param>
|
||||||
|
/// <param name="toNodeGuid">目标节点Guid</param>
|
||||||
|
/// <param name="argIndex">目标节点的第几个参数</param>
|
||||||
|
[AutoSocketHandle(ThemeValue = EnvMsgTheme.RemoveArgSourceConnect)]
|
||||||
|
public async Task<object> RemoveArgSourceConnect(string fromNodeGuid, string toNodeGuid, int argIndex)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
var result = await environment.RemoveConnectArgSourceAsync(fromNodeGuid, toNodeGuid, argIndex);
|
||||||
return new
|
return new
|
||||||
{
|
{
|
||||||
state = result
|
state = result
|
||||||
@@ -408,18 +531,14 @@ namespace Serein.NodeFlow.Env
|
|||||||
/// 中断指定节点,并指定中断等级。
|
/// 中断指定节点,并指定中断等级。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="nodeGuid">被中断的目标节点Guid</param>
|
/// <param name="nodeGuid">被中断的目标节点Guid</param>
|
||||||
/// <param name="interruptClass">中断级别</param>
|
/// <param name="isInterrupt">是否中断</param>
|
||||||
/// <returns>操作是否成功</returns>
|
/// <returns>操作是否成功</returns>
|
||||||
[AutoSocketHandle(ThemeValue = EnvMsgTheme.SetNodeInterrupt)]
|
[AutoSocketHandle(ThemeValue = EnvMsgTheme.SetNodeInterrupt)]
|
||||||
public async Task<bool> SetNodeInterruptAsync(string nodeGuid, string interruptClass)
|
public async Task<bool> SetNodeInterruptAsync(string nodeGuid, bool isInterrupt)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!EnumHelper.TryConvertEnum<InterruptClass>(interruptClass, out var @class))
|
|
||||||
{
|
return await this.environment.SetNodeInterruptAsync(nodeGuid, isInterrupt);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return await this.environment.SetNodeInterruptAsync(nodeGuid, @class);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
using Serein.Library;
|
using Serein.Library;
|
||||||
using Serein.Library.Api;
|
using Serein.Library.Api;
|
||||||
|
using Serein.Library.FlowNode;
|
||||||
using Serein.Library.Utils;
|
using Serein.Library.Utils;
|
||||||
using Serein.NodeFlow.Tool;
|
using Serein.NodeFlow.Tool;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
|
using System.Security.AccessControl;
|
||||||
|
using System.Threading.Channels;
|
||||||
|
|
||||||
namespace Serein.NodeFlow.Env
|
namespace Serein.NodeFlow.Env
|
||||||
{
|
{
|
||||||
@@ -16,21 +19,21 @@ namespace Serein.NodeFlow.Env
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 连接到远程环境后切换到的环境接口实现
|
/// 连接到远程环境后切换到的环境接口实现
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="RemoteEnvControl">连接到远程环境后,本地环境自动切换到对应的环境实体</param>
|
/// <param name="remoteMsgUtil">连接到远程环境后,本地环境自动切换到对应的环境实体</param>
|
||||||
/// <param name="uIContextOperation">远程环境下需要操作UI线程时,所提供的线程上下文封装工具</param>
|
/// <param name="uIContextOperation">远程环境下需要操作UI线程时,所提供的线程上下文封装工具</param>
|
||||||
public RemoteFlowEnvironment(RemoteEnvControl RemoteEnvControl, UIContextOperation uIContextOperation)
|
public RemoteFlowEnvironment(RemoteMsgUtil remoteMsgUtil, UIContextOperation uIContextOperation)
|
||||||
{
|
{
|
||||||
this.UIContextOperation = uIContextOperation;
|
this.UIContextOperation = uIContextOperation;
|
||||||
remoteEnvControl = RemoteEnvControl;
|
RemoteMsgUtil = remoteMsgUtil;
|
||||||
msgClient = new MsgControllerOfClient(this, RemoteEnvControl.SendAsync);
|
msgClient = new MsgControllerOfClient(this, remoteMsgUtil.SendAsync); // 这里提供的是主动发送消息的方法
|
||||||
RemoteEnvControl.EnvClient.MsgHandleHelper.AddModule(msgClient, (ex, send) =>
|
remoteMsgUtil.EnvClient.MsgHandleHelper.AddModule(msgClient, (ex, send) =>
|
||||||
{
|
{
|
||||||
Console.WriteLine(ex);
|
Console.WriteLine(ex);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//private readonly Func<string, object?, Task> SendCommandAsync;
|
//private readonly Func<string, object?, Task> SendCommandAsync;
|
||||||
private readonly RemoteEnvControl remoteEnvControl;
|
private readonly RemoteMsgUtil RemoteMsgUtil;
|
||||||
private readonly MsgControllerOfClient msgClient;
|
private readonly MsgControllerOfClient msgClient;
|
||||||
private readonly ConcurrentDictionary<string, MethodDetails> MethodDetailss = [];
|
private readonly ConcurrentDictionary<string, MethodDetails> MethodDetailss = [];
|
||||||
|
|
||||||
@@ -70,6 +73,12 @@ namespace Serein.NodeFlow.Env
|
|||||||
|
|
||||||
public IFlowEnvironment CurrentEnv => this;
|
public IFlowEnvironment CurrentEnv => this;
|
||||||
public UIContextOperation UIContextOperation { get; }
|
public UIContextOperation UIContextOperation { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 标示是否正在加载项目
|
||||||
|
/// </summary>
|
||||||
|
private bool IsLoadingProject = false;
|
||||||
|
|
||||||
public void SetConsoleOut()
|
public void SetConsoleOut()
|
||||||
{
|
{
|
||||||
var logTextWriter = new LogTextWriter(msg =>
|
var logTextWriter = new LogTextWriter(msg =>
|
||||||
@@ -102,9 +111,9 @@ namespace Serein.NodeFlow.Env
|
|||||||
|
|
||||||
public void LoadProject(FlowEnvInfo flowEnvInfo, string filePath)
|
public void LoadProject(FlowEnvInfo flowEnvInfo, string filePath)
|
||||||
{
|
{
|
||||||
//Console.WriteLine("远程环境尚未实现的接口:LoadProject");
|
Console.WriteLine("加载远程环境");
|
||||||
|
IsLoadingProject = true;
|
||||||
// dll面板
|
#region DLL功能区创建
|
||||||
var libmds = flowEnvInfo.LibraryMds;
|
var libmds = flowEnvInfo.LibraryMds;
|
||||||
foreach (var lib in libmds)
|
foreach (var lib in libmds)
|
||||||
{
|
{
|
||||||
@@ -114,21 +123,18 @@ namespace Serein.NodeFlow.Env
|
|||||||
FilePath = "Remote",
|
FilePath = "Remote",
|
||||||
};
|
};
|
||||||
var mdInfos = lib.Mds.ToList();
|
var mdInfos = lib.Mds.ToList();
|
||||||
//OnDllLoad?.Invoke(new LoadDllEventArgs(nodeLibrary, mdInfos)); // 通知UI创建dll面板显示
|
|
||||||
UIContextOperation?.Invoke(() => OnDllLoad?.Invoke(new LoadDllEventArgs(nodeLibrary, mdInfos))); // 通知UI创建dll面板显示
|
UIContextOperation?.Invoke(() => OnDllLoad?.Invoke(new LoadDllEventArgs(nodeLibrary, mdInfos))); // 通知UI创建dll面板显示
|
||||||
foreach (var mdInfo in mdInfos)
|
foreach (var mdInfo in mdInfos)
|
||||||
{
|
{
|
||||||
MethodDetailss.TryAdd(mdInfo.MethodName, new MethodDetails(mdInfo)); // 从DLL读取时生成元数据
|
MethodDetailss.TryAdd(mdInfo.MethodName, new MethodDetails(mdInfo)); // 从DLL读取时生成元数据
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//flowSemaphore.
|
#endregion
|
||||||
|
|
||||||
|
#region 加载节点数据,如果是区域控件,提前加载区域
|
||||||
var projectData = flowEnvInfo.Project;
|
var projectData = flowEnvInfo.Project;
|
||||||
|
|
||||||
|
|
||||||
List<(NodeModelBase, string[])> regionChildNodes = new List<(NodeModelBase, string[])>();
|
List<(NodeModelBase, string[])> regionChildNodes = new List<(NodeModelBase, string[])>();
|
||||||
List<(NodeModelBase, PositionOfUI)> ordinaryNodes = new List<(NodeModelBase, PositionOfUI)>();
|
List<(NodeModelBase, PositionOfUI)> ordinaryNodes = new List<(NodeModelBase, PositionOfUI)>();
|
||||||
|
|
||||||
// 加载节点
|
// 加载节点
|
||||||
foreach (var nodeInfo in projectData.Nodes)
|
foreach (var nodeInfo in projectData.Nodes)
|
||||||
{
|
{
|
||||||
@@ -139,7 +145,6 @@ namespace Serein.NodeFlow.Env
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
MethodDetails? methodDetails = null;
|
MethodDetails? methodDetails = null;
|
||||||
if (!string.IsNullOrEmpty(nodeInfo.MethodName))
|
if (!string.IsNullOrEmpty(nodeInfo.MethodName))
|
||||||
{
|
{
|
||||||
@@ -167,7 +172,9 @@ namespace Serein.NodeFlow.Env
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 加载区域中的节点
|
||||||
// 加载区域子项
|
// 加载区域子项
|
||||||
foreach ((NodeModelBase region, string[] childNodeGuids) item in regionChildNodes)
|
foreach ((NodeModelBase region, string[] childNodeGuids) item in regionChildNodes)
|
||||||
{
|
{
|
||||||
@@ -183,7 +190,9 @@ namespace Serein.NodeFlow.Env
|
|||||||
UIContextOperation?.Invoke(() => OnNodeCreate?.Invoke(new NodeCreateEventArgs(childNode, true, item.region.Guid)));
|
UIContextOperation?.Invoke(() => OnNodeCreate?.Invoke(new NodeCreateEventArgs(childNode, true, item.region.Guid)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 加载普通的节点
|
||||||
// 加载节点
|
// 加载节点
|
||||||
foreach ((NodeModelBase nodeModel, PositionOfUI position) item in ordinaryNodes)
|
foreach ((NodeModelBase nodeModel, PositionOfUI position) item in ordinaryNodes)
|
||||||
{
|
{
|
||||||
@@ -202,60 +211,84 @@ namespace Serein.NodeFlow.Env
|
|||||||
//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)));
|
UIContextOperation?.Invoke(() => OnNodeCreate?.Invoke(new NodeCreateEventArgs(item.nodeModel, item.position)));
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 确定节点之间的连接关系
|
||||||
|
|
||||||
// 确定节点之间的连接关系
|
|
||||||
_ = Task.Run(async () =>
|
_ = Task.Run(async () =>
|
||||||
{
|
|
||||||
await Task.Delay(250);
|
|
||||||
foreach (var nodeInfo in projectData.Nodes)
|
|
||||||
{
|
{
|
||||||
if (!NodeModels.TryGetValue(nodeInfo.Guid, out NodeModelBase? fromNode))
|
await Task.Delay(500);
|
||||||
|
#region 连接节点的调用关系
|
||||||
|
foreach (var nodeInfo in projectData.Nodes)
|
||||||
{
|
{
|
||||||
// 不存在对应的起始节点
|
if (!NodeModels.TryGetValue(nodeInfo.Guid, out NodeModelBase? fromNode))
|
||||||
continue;
|
{
|
||||||
}
|
// 不存在对应的起始节点
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
List<(ConnectionInvokeType connectionType, string[] guids)> allToNodes = [(ConnectionInvokeType.IsSucceed,nodeInfo.TrueNodes),
|
List<(ConnectionInvokeType connectionType, string[] guids)> allToNodes = [(ConnectionInvokeType.IsSucceed,nodeInfo.TrueNodes),
|
||||||
(ConnectionInvokeType.IsFail, nodeInfo.FalseNodes),
|
(ConnectionInvokeType.IsFail, nodeInfo.FalseNodes),
|
||||||
(ConnectionInvokeType.IsError, nodeInfo.ErrorNodes),
|
(ConnectionInvokeType.IsError, nodeInfo.ErrorNodes),
|
||||||
(ConnectionInvokeType.Upstream, nodeInfo.UpstreamNodes)];
|
(ConnectionInvokeType.Upstream, nodeInfo.UpstreamNodes)];
|
||||||
|
|
||||||
List<(ConnectionInvokeType, NodeModelBase[])> fromNodes = allToNodes.Where(info => info.guids.Length > 0)
|
List<(ConnectionInvokeType, NodeModelBase[])> fromNodes = allToNodes.Where(info => info.guids.Length > 0)
|
||||||
.Select(info => (info.connectionType,
|
.Select(info => (info.connectionType,
|
||||||
info.guids.Where(guid => NodeModels.ContainsKey(guid)).Select(guid => NodeModels[guid])
|
info.guids.Where(guid => NodeModels.ContainsKey(guid)).Select(guid => NodeModels[guid])
|
||||||
.ToArray()))
|
.ToArray()))
|
||||||
.ToList();
|
.ToList();
|
||||||
// 遍历每种类型的节点分支(四种)
|
// 遍历每种类型的节点分支(四种)
|
||||||
foreach ((ConnectionInvokeType connectionType, NodeModelBase[] toNodes) item in fromNodes)
|
foreach ((ConnectionInvokeType connectionType, NodeModelBase[] toNodes) item in fromNodes)
|
||||||
{
|
|
||||||
// 遍历当前类型分支的节点(确认连接关系)
|
|
||||||
foreach (var toNode in item.toNodes)
|
|
||||||
{
|
{
|
||||||
|
// 遍历当前类型分支的节点(确认连接关系)
|
||||||
UIContextOperation?.Invoke(() => OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNode.Guid,
|
foreach (var toNode in item.toNodes)
|
||||||
toNode.Guid,
|
{
|
||||||
JunctionOfConnectionType.Invoke,
|
UIContextOperation?.Invoke(() => OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNode.Guid,
|
||||||
item.connectionType,
|
toNode.Guid,
|
||||||
NodeConnectChangeEventArgs.ConnectChangeType.Create))); // 通知UI连接节点
|
JunctionOfConnectionType.Invoke,
|
||||||
//OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNode.Guid,
|
item.connectionType,
|
||||||
// toNode.Guid,
|
NodeConnectChangeEventArgs.ConnectChangeType.Create))); // 通知UI连接节点
|
||||||
// item.connectionType,
|
}
|
||||||
// NodeConnectChangeEventArgs.ConnectChangeType.Create)); //
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
#endregion
|
||||||
});
|
|
||||||
|
|
||||||
SetStartNode(projectData.StartNode);
|
#region 连接节点的传参关系
|
||||||
|
foreach (var toNode in NodeModels.Values)
|
||||||
|
{
|
||||||
|
if(toNode.MethodDetails.ParameterDetailss is null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (var i = 0; i < toNode.MethodDetails.ParameterDetailss.Length; i++)
|
||||||
|
{
|
||||||
|
var pd = toNode.MethodDetails.ParameterDetailss[i];
|
||||||
|
if (!string.IsNullOrEmpty(pd.ArgDataSourceNodeGuid)
|
||||||
|
&& NodeModels.TryGetValue(pd.ArgDataSourceNodeGuid, out var fromNode))
|
||||||
|
{
|
||||||
|
UIContextOperation?.Invoke(() =>
|
||||||
|
OnNodeConnectChange?.Invoke(
|
||||||
|
new NodeConnectChangeEventArgs(
|
||||||
|
fromNode.Guid, // 从哪个节点开始
|
||||||
|
toNode.Guid, // 连接到那个节点
|
||||||
|
JunctionOfConnectionType.Arg,
|
||||||
|
(int)pd.Index, // 连接线的样式类型
|
||||||
|
pd.ArgDataSourceType,
|
||||||
|
NodeConnectChangeEventArgs.ConnectChangeType.Create // 是创建连接还是删除连接
|
||||||
|
))); // 通知UI
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
});
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
SetStartNode(projectData.StartNode); // 设置流程起点
|
||||||
UIContextOperation?.Invoke(() =>
|
UIContextOperation?.Invoke(() =>
|
||||||
{
|
{
|
||||||
OnProjectLoaded?.Invoke(new ProjectLoadedEventArgs());
|
OnProjectLoaded?.Invoke(new ProjectLoadedEventArgs()); // 加载完成
|
||||||
});
|
});
|
||||||
|
IsLoadingProject = false;
|
||||||
}
|
}
|
||||||
private bool TryAddNode(NodeModelBase nodeModel)
|
private bool TryAddNode(NodeModelBase nodeModel)
|
||||||
{
|
{
|
||||||
@@ -339,15 +372,12 @@ namespace Serein.NodeFlow.Env
|
|||||||
|
|
||||||
public async Task<FlowEnvInfo> GetEnvInfoAsync()
|
public async Task<FlowEnvInfo> GetEnvInfoAsync()
|
||||||
{
|
{
|
||||||
|
|
||||||
var envInfo = await msgClient.SendAndWaitDataAsync<FlowEnvInfo>(EnvMsgTheme.GetEnvInfo);
|
var envInfo = await msgClient.SendAndWaitDataAsync<FlowEnvInfo>(EnvMsgTheme.GetEnvInfo);
|
||||||
|
|
||||||
return envInfo;
|
return envInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async Task<(bool, RemoteMsgUtil)> ConnectRemoteEnv(string addres, int port, string token)
|
||||||
public async Task<(bool, RemoteEnvControl)> ConnectRemoteEnv(string addres, int port, string token)
|
|
||||||
{
|
{
|
||||||
await Console.Out.WriteLineAsync("远程环境尚未实现的接口:ConnectRemoteEnv");
|
await Console.Out.WriteLineAsync("远程环境尚未实现的接口:ConnectRemoteEnv");
|
||||||
return (false, null);
|
return (false, null);
|
||||||
@@ -436,32 +466,204 @@ namespace Serein.NodeFlow.Env
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> ConnectNodeAsync(string fromNodeGuid,
|
/// <summary>
|
||||||
string toNodeGuid,
|
/// 在两个节点之间创建方法调用关系
|
||||||
JunctionType fromNodeJunctionType,
|
/// </summary>
|
||||||
JunctionType toNodeJunctionType,
|
/// <param name="fromNodeGuid">起始节点Guid</param>
|
||||||
ConnectionInvokeType connectionType,
|
/// <param name="toNodeGuid">目标节点Guid</param>
|
||||||
int argIndex = 0)
|
/// <param name="fromNodeJunctionType">起始节点控制点</param>
|
||||||
|
/// <param name="toNodeJunctionType">目标节点控制点</param>
|
||||||
|
/// <param name="invokeType">决定了方法执行后的后继行为</param>
|
||||||
|
public async Task<bool> ConnectInvokeNodeAsync(string fromNodeGuid,
|
||||||
|
string toNodeGuid,
|
||||||
|
JunctionType fromNodeJunctionType,
|
||||||
|
JunctionType toNodeJunctionType,
|
||||||
|
ConnectionInvokeType invokeType)
|
||||||
{
|
{
|
||||||
var result = await msgClient.SendAndWaitDataAsync<bool>(EnvMsgTheme.ConnectNode, new
|
if (fromNodeJunctionType == JunctionType.Execute)
|
||||||
{
|
{
|
||||||
fromNodeGuid,
|
if (toNodeJunctionType == JunctionType.NextStep)
|
||||||
toNodeGuid,
|
{
|
||||||
fromNodeJunctionType = fromNodeJunctionType.ToString(),
|
(fromNodeGuid, toNodeGuid) = (toNodeGuid, fromNodeGuid);// 需要反转
|
||||||
toNodeJunctionType = toNodeJunctionType.ToString(),
|
}
|
||||||
connectionType = connectionType.ToString(),
|
else
|
||||||
});
|
{
|
||||||
|
return false; // 非预期的控制点连接
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (fromNodeJunctionType == JunctionType.NextStep)
|
||||||
|
{
|
||||||
|
if (toNodeJunctionType == JunctionType.Execute)
|
||||||
|
{
|
||||||
|
// 顺序正确无须反转
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false; // 非预期的控制点连接
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // 其它类型的控制点,排除
|
||||||
|
{
|
||||||
|
return false; // 非预期的控制点连接
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var sendObj = new
|
||||||
|
{
|
||||||
|
fromNodeGuid = fromNodeGuid,
|
||||||
|
toNodeGuid = toNodeGuid,
|
||||||
|
fromJunctionType = fromNodeJunctionType.ToString(),
|
||||||
|
toJunctionType = toNodeJunctionType.ToString(),
|
||||||
|
invokeType = invokeType.ToString(),
|
||||||
|
};
|
||||||
|
var result = await msgClient.SendAndWaitDataAsync<bool>(EnvMsgTheme.ConnectInvokeNode, sendObj);
|
||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNodeGuid,
|
OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNodeGuid,
|
||||||
toNodeGuid,
|
toNodeGuid,
|
||||||
JunctionOfConnectionType.Invoke,
|
JunctionOfConnectionType.Invoke,
|
||||||
connectionType,
|
invokeType,
|
||||||
NodeConnectChangeEventArgs.ConnectChangeType.Create)); // 通知UI
|
NodeConnectChangeEventArgs.ConnectChangeType.Create)); // 通知UI
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 在两个节点之间创建参数传递关系
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fromNodeGuid">起始节点Guid</param>
|
||||||
|
/// <param name="toNodeGuid">目标节点Guid</param>
|
||||||
|
/// <param name="fromNodeJunctionType">起始节点控制点</param>
|
||||||
|
/// <param name="toNodeJunctionType">目标节点控制点</param>
|
||||||
|
/// <param name="argSourceType">决定了方法参数来源</param>
|
||||||
|
/// <param name="argIndex">设置第几个参数</param>
|
||||||
|
public async Task<bool> ConnectArgSourceNodeAsync(string fromNodeGuid,
|
||||||
|
string toNodeGuid,
|
||||||
|
JunctionType fromNodeJunctionType,
|
||||||
|
JunctionType toNodeJunctionType,
|
||||||
|
ConnectionArgSourceType argSourceType,
|
||||||
|
int argIndex = 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
// 正确的顺序:起始节点[返回值控制点] 向 目标节点[入参控制点] 发起连接
|
||||||
|
//Console.WriteLine();
|
||||||
|
//Console.WriteLine($"起始节点:{fromNodeGuid}");
|
||||||
|
//Console.WriteLine($"目标节点:{toNodeGuid}");
|
||||||
|
//Console.WriteLine($"链接请求:{(fromNodeJunctionType, toNodeJunctionType)}");
|
||||||
|
//Console.WriteLine((fromNodeJunctionType, toNodeJunctionType));
|
||||||
|
|
||||||
|
if (fromNodeJunctionType == JunctionType.ArgData)
|
||||||
|
{
|
||||||
|
if (toNodeJunctionType == JunctionType.ReturnData)
|
||||||
|
{
|
||||||
|
(fromNodeGuid, toNodeGuid) = (toNodeGuid, fromNodeGuid);// 需要反转
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false; // 非预期的控制点连接
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (fromNodeJunctionType == JunctionType.ReturnData)
|
||||||
|
{
|
||||||
|
if (toNodeJunctionType == JunctionType.ArgData)
|
||||||
|
{
|
||||||
|
// 顺序正确无须反转
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false; // 非预期的控制点连接
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // 其它类型的控制点,排除
|
||||||
|
{
|
||||||
|
return false; // 非预期的控制点连接
|
||||||
|
}
|
||||||
|
|
||||||
|
var sendObj = new
|
||||||
|
{
|
||||||
|
fromNodeGuid = fromNodeGuid,
|
||||||
|
toNodeGuid = toNodeGuid,
|
||||||
|
fromJunctionType = fromNodeJunctionType.ToString(),
|
||||||
|
toJunctionType = toNodeJunctionType.ToString(),
|
||||||
|
argSourceType = argSourceType.ToString(),
|
||||||
|
argIndex = argIndex,
|
||||||
|
};
|
||||||
|
var result = await msgClient.SendAndWaitDataAsync<bool>(EnvMsgTheme.ConnectArgSourceNode, sendObj);
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNodeGuid,
|
||||||
|
toNodeGuid,
|
||||||
|
JunctionOfConnectionType.Arg,
|
||||||
|
argIndex,
|
||||||
|
argSourceType,
|
||||||
|
NodeConnectChangeEventArgs.ConnectChangeType.Create)); // 通知UI
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 移除两个节点之间的方法调用关系
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fromNodeGuid">起始节点</param>
|
||||||
|
/// <param name="toNodeGuid">目标节点</param>
|
||||||
|
/// <param name="invokeType">连接类型</param>
|
||||||
|
public async Task<bool> RemoveConnectInvokeAsync(string fromNodeGuid, string toNodeGuid, ConnectionInvokeType invokeType)
|
||||||
|
{
|
||||||
|
var result = await msgClient.SendAndWaitDataAsync<bool>(EnvMsgTheme.RemoveInvokeConnect, new
|
||||||
|
{
|
||||||
|
fromNodeGuid = fromNodeGuid,
|
||||||
|
toNodeGuid = toNodeGuid,
|
||||||
|
invokeType = invokeType.ToString(),
|
||||||
|
});
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
UIContextOperation.Invoke(() =>
|
||||||
|
{
|
||||||
|
OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNodeGuid,
|
||||||
|
toNodeGuid,
|
||||||
|
JunctionOfConnectionType.Invoke,
|
||||||
|
invokeType,
|
||||||
|
NodeConnectChangeEventArgs.ConnectChangeType.Remote));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 移除连接节点之间参数传递的关系
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fromNodeGuid">起始节点Guid</param>
|
||||||
|
/// <param name="toNodeGuid">目标节点Guid</param>
|
||||||
|
/// <param name="argIndex">连接到第几个参数</param>
|
||||||
|
public async Task<bool> RemoveConnectArgSourceAsync(string fromNodeGuid, string toNodeGuid, int argIndex)
|
||||||
|
{
|
||||||
|
var result = await msgClient.SendAndWaitDataAsync<bool>(EnvMsgTheme.RemoveArgSourceConnect, new
|
||||||
|
{
|
||||||
|
fromNodeGuid = fromNodeGuid,
|
||||||
|
toNodeGuid = toNodeGuid,
|
||||||
|
argIndex = argIndex,
|
||||||
|
});
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
UIContextOperation.Invoke(() =>
|
||||||
|
{
|
||||||
|
OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNodeGuid,
|
||||||
|
toNodeGuid,
|
||||||
|
JunctionOfConnectionType.Arg,
|
||||||
|
argIndex,
|
||||||
|
ConnectionArgSourceType.GetPreviousNodeData,
|
||||||
|
NodeConnectChangeEventArgs.ConnectChangeType.Remote)); // 通知UI
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建节点/区域/基础控件
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="nodeType">节点/区域/基础控件类型</param>
|
||||||
|
/// <param name="position">节点在画布上的位置(</param>
|
||||||
|
/// <param name="methodDetailsInfo">节点绑定的方法说明</param>
|
||||||
public async Task<NodeInfo> CreateNodeAsync(NodeControlType nodeControlType, PositionOfUI position, MethodDetailsInfo methodDetailsInfo = null)
|
public async Task<NodeInfo> CreateNodeAsync(NodeControlType nodeControlType, PositionOfUI position, MethodDetailsInfo methodDetailsInfo = null)
|
||||||
{
|
{
|
||||||
var nodeInfo = await msgClient.SendAndWaitDataAsync<NodeInfo>(EnvMsgTheme.CreateNode, new
|
var nodeInfo = await msgClient.SendAndWaitDataAsync<NodeInfo>(EnvMsgTheme.CreateNode, new
|
||||||
@@ -489,29 +691,6 @@ namespace Serein.NodeFlow.Env
|
|||||||
});
|
});
|
||||||
return nodeInfo;
|
return nodeInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> RemoveConnectAsync(string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType)
|
|
||||||
{
|
|
||||||
var result = await msgClient.SendAndWaitDataAsync<bool>(EnvMsgTheme.RemoveConnect, new
|
|
||||||
{
|
|
||||||
fromNodeGuid,
|
|
||||||
toNodeGuid,
|
|
||||||
connectionType = connectionType.ToString(),
|
|
||||||
});
|
|
||||||
if (result)
|
|
||||||
{
|
|
||||||
UIContextOperation.Invoke(() =>
|
|
||||||
{
|
|
||||||
OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNodeGuid,
|
|
||||||
toNodeGuid,
|
|
||||||
JunctionOfConnectionType.Invoke,
|
|
||||||
connectionType,
|
|
||||||
NodeConnectChangeEventArgs.ConnectChangeType.Remote));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<bool> RemoveNodeAsync(string nodeGuid)
|
public async Task<bool> RemoveNodeAsync(string nodeGuid)
|
||||||
{
|
{
|
||||||
var result = await msgClient.SendAndWaitDataAsync<bool>(EnvMsgTheme.RemoveNode, new
|
var result = await msgClient.SendAndWaitDataAsync<bool>(EnvMsgTheme.RemoveNode, new
|
||||||
@@ -548,13 +727,13 @@ namespace Serein.NodeFlow.Env
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> SetNodeInterruptAsync(string nodeGuid, InterruptClass interruptClass)
|
public async Task<bool> SetNodeInterruptAsync(string nodeGuid, bool isInterrupt)
|
||||||
{
|
{
|
||||||
var state = await msgClient.SendAndWaitDataAsync<bool>(EnvMsgTheme.SetNodeInterrupt, // 设置节点中断
|
var state = await msgClient.SendAndWaitDataAsync<bool>(EnvMsgTheme.SetNodeInterrupt, // 设置节点中断
|
||||||
new
|
new
|
||||||
{
|
{
|
||||||
nodeGuid,
|
nodeGuid,
|
||||||
interruptClass = interruptClass.ToString(),
|
isInterrupt,
|
||||||
});
|
});
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
@@ -638,12 +817,13 @@ namespace Serein.NodeFlow.Env
|
|||||||
public async Task NotificationNodeValueChangeAsync(string nodeGuid, string path, object value)
|
public async Task NotificationNodeValueChangeAsync(string nodeGuid, string path, object value)
|
||||||
{
|
{
|
||||||
//Console.WriteLine($"通知远程环境修改节点数据:{nodeGuid},name:{path},value:{value}");
|
//Console.WriteLine($"通知远程环境修改节点数据:{nodeGuid},name:{path},value:{value}");
|
||||||
_ = msgClient.SendAsync(EnvMsgTheme.ValueNotification, new
|
|
||||||
{
|
//_ = msgClient.SendAsync(EnvMsgTheme.ValueNotification, new
|
||||||
nodeGuid = nodeGuid,
|
//{
|
||||||
path = path,
|
// nodeGuid = nodeGuid,
|
||||||
value = value.ToString(),
|
// path = path,
|
||||||
});
|
// value = value.ToString(),
|
||||||
|
//});
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,13 +46,27 @@ namespace Serein.NodeFlow
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task StartFlowInSelectNodeAsync(IFlowEnvironment env, NodeModelBase startNode)
|
public async Task StartFlowInSelectNodeAsync(IFlowEnvironment env, NodeModelBase startNode)
|
||||||
{
|
{
|
||||||
IDynamicContext Context;
|
IDynamicContext context;
|
||||||
#if NET6_0_OR_GREATER
|
#if NET6_0_OR_GREATER
|
||||||
Context = new Serein.Library.Core.NodeFlow.DynamicContext(env); // 从起始节点启动流程时创建上下文
|
context = new Serein.Library.Core.NodeFlow.DynamicContext(env); // 从起始节点启动流程时创建上下文
|
||||||
#else
|
#else
|
||||||
Context = new Serein.Library.Framework.NodeFlow.DynamicContext(env);
|
Context = new Serein.Library.Framework.NodeFlow.DynamicContext(env);
|
||||||
#endif
|
#endif
|
||||||
await startNode.StartFlowAsync(Context); // 开始运行时从选定节点开始运行
|
await startNode.StartFlowAsync(context); // 开始运行时从选定节点开始运行
|
||||||
|
context.Exit();
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
foreach (var node in NodeModels.Values)
|
||||||
|
{
|
||||||
|
if (node is not null)
|
||||||
|
{
|
||||||
|
node.ReleaseFlowData(); // 退出时释放对象
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -360,7 +374,7 @@ namespace Serein.NodeFlow
|
|||||||
if (nextNodes[i].DebugSetting.IsEnable)
|
if (nextNodes[i].DebugSetting.IsEnable)
|
||||||
{
|
{
|
||||||
nextNodes[i].PreviousNode = singleFlipFlopNode;
|
nextNodes[i].PreviousNode = singleFlipFlopNode;
|
||||||
if (nextNodes[i].DebugSetting.InterruptClass != InterruptClass.None) // 执行触发前
|
if (nextNodes[i].DebugSetting.IsInterrupt) // 执行触发前
|
||||||
{
|
{
|
||||||
var cancelType = await nextNodes[i].DebugSetting.GetInterruptTask();
|
var cancelType = await nextNodes[i].DebugSetting.GetInterruptTask();
|
||||||
await Console.Out.WriteLineAsync($"[{nextNodes[i].MethodDetails.MethodName}]中断已{cancelType},开始执行后继分支");
|
await Console.Out.WriteLineAsync($"[{nextNodes[i].MethodDetails.MethodName}]中断已{cancelType},开始执行后继分支");
|
||||||
|
|||||||
@@ -1,61 +0,0 @@
|
|||||||
using Serein.Library;
|
|
||||||
using Serein.Library.Api;
|
|
||||||
|
|
||||||
namespace Serein.NodeFlow.Model
|
|
||||||
{
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 组合动作节点(用于动作区域)
|
|
||||||
/// </summary>
|
|
||||||
public class CompositeActionNode : NodeModelBase
|
|
||||||
{
|
|
||||||
public List<SingleActionNode> ActionNodes;
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 组合动作节点(用于动作区域)
|
|
||||||
/// </summary>
|
|
||||||
public CompositeActionNode(IFlowEnvironment environment, List<SingleActionNode> actionNodes):base(environment)
|
|
||||||
{
|
|
||||||
ActionNodes = actionNodes;
|
|
||||||
}
|
|
||||||
|
|
||||||
//public override async Task<object?> Executing(IDynamicContext context)
|
|
||||||
public override Task<object?> ExecutingAsync(IDynamicContext context)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException("动作区域暂未实现");
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Parameterdata[] GetParameterdatas()
|
|
||||||
{
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
public override NodeInfo? ToInfo()
|
|
||||||
{
|
|
||||||
if (MethodDetails is null) return null;
|
|
||||||
|
|
||||||
var trueNodes = SuccessorNodes[ConnectionInvokeType.IsSucceed].Select(item => item.Guid); // 真分支
|
|
||||||
var falseNodes = SuccessorNodes[ConnectionInvokeType.IsFail].Select(item => item.Guid);// 假分支
|
|
||||||
var errorNodes = SuccessorNodes[ConnectionInvokeType.IsError].Select(item => item.Guid);// 异常分支
|
|
||||||
var upstreamNodes = SuccessorNodes[ConnectionInvokeType.Upstream].Select(item => item.Guid);// 上游分支
|
|
||||||
// 生成参数列表
|
|
||||||
Parameterdata[] parameterData = GetParameterdatas();
|
|
||||||
|
|
||||||
return new NodeInfo
|
|
||||||
{
|
|
||||||
Guid = Guid,
|
|
||||||
MethodName = MethodDetails?.MethodName,
|
|
||||||
Label = DisplayName ?? "",
|
|
||||||
Type = this.GetType().ToString(),
|
|
||||||
TrueNodes = trueNodes.ToArray(),
|
|
||||||
FalseNodes = falseNodes.ToArray(),
|
|
||||||
UpstreamNodes = upstreamNodes.ToArray(),
|
|
||||||
ParameterData = parameterData.ToArray(),
|
|
||||||
ErrorNodes = errorNodes.ToArray(),
|
|
||||||
ChildNodeGuids = ActionNodes.Select(node => node.Guid).ToArray(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -58,7 +58,8 @@ namespace Serein.NodeFlow.Model
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Task.FromResult( PreviousNode?.GetFlowData()); // 条件区域透传上一节点的数据
|
|
||||||
|
return Task.FromResult(context.GetFlowData(PreviousNode.Guid)); // 条件区域透传上一节点的数据
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -78,7 +79,7 @@ namespace Serein.NodeFlow.Model
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Parameterdata[] GetParameterdatas()
|
public override ParameterData[] GetParameterdatas()
|
||||||
{
|
{
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@@ -97,7 +98,7 @@ namespace Serein.NodeFlow.Model
|
|||||||
var upstreamNodes = SuccessorNodes[ConnectionInvokeType.Upstream].Select(item => item.Guid);// 上游分支
|
var upstreamNodes = SuccessorNodes[ConnectionInvokeType.Upstream].Select(item => item.Guid);// 上游分支
|
||||||
|
|
||||||
// 生成参数列表
|
// 生成参数列表
|
||||||
Parameterdata[] parameterData = GetParameterdatas();
|
ParameterData[] parameterData = GetParameterdatas();
|
||||||
|
|
||||||
return new NodeInfo
|
return new NodeInfo
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
namespace Serein.NodeFlow.Model
|
|
||||||
{
|
|
||||||
//public class CompositeLoopNode : NodeBase
|
|
||||||
//{
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
using Serein.Library.Api;
|
using Serein.Library.Api;
|
||||||
using Serein.Library;
|
using Serein.Library;
|
||||||
|
using System.Security.AccessControl;
|
||||||
|
|
||||||
namespace Serein.NodeFlow.Model
|
namespace Serein.NodeFlow.Model
|
||||||
{
|
{
|
||||||
@@ -12,13 +13,15 @@ namespace Serein.NodeFlow.Model
|
|||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
public override Parameterdata[] GetParameterdatas()
|
public override ParameterData[] GetParameterdatas()
|
||||||
{
|
{
|
||||||
if (base.MethodDetails.ParameterDetailss.Length > 0)
|
if (base.MethodDetails.ParameterDetailss.Length > 0)
|
||||||
{
|
{
|
||||||
return MethodDetails.ParameterDetailss
|
return MethodDetails.ParameterDetailss
|
||||||
.Select(it => new Parameterdata
|
.Select(it => new ParameterData
|
||||||
{
|
{
|
||||||
|
SourceNodeGuid = it.ArgDataSourceNodeGuid,
|
||||||
|
SourceType = it.ArgDataSourceType.ToString(),
|
||||||
State = it.IsExplicitData,
|
State = it.IsExplicitData,
|
||||||
Value = it.DataValue,
|
Value = it.DataValue,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ namespace Serein.NodeFlow.Model
|
|||||||
{
|
{
|
||||||
// 接收上一节点参数or自定义参数内容
|
// 接收上一节点参数or自定义参数内容
|
||||||
object? parameter;
|
object? parameter;
|
||||||
object? result = PreviousNode?.GetFlowData(); // 条件节点透传上一节点的数据
|
object? result = context.GetFlowData(PreviousNode.Guid); // 条件节点透传上一节点的数据
|
||||||
if (IsCustomData) // 是否使用自定义参数
|
if (IsCustomData) // 是否使用自定义参数
|
||||||
{
|
{
|
||||||
// 表达式获取上一节点数据
|
// 表达式获取上一节点数据
|
||||||
@@ -88,7 +88,7 @@ namespace Serein.NodeFlow.Model
|
|||||||
return Task.FromResult(result);
|
return Task.FromResult(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Parameterdata[] GetParameterdatas()
|
public override ParameterData[] GetParameterdatas()
|
||||||
{
|
{
|
||||||
var value = CustomData switch
|
var value = CustomData switch
|
||||||
{
|
{
|
||||||
@@ -99,7 +99,7 @@ namespace Serein.NodeFlow.Model
|
|||||||
Type when CustomData.GetType() == typeof(bool) => ((bool)CustomData).ToString(),
|
Type when CustomData.GetType() == typeof(bool) => ((bool)CustomData).ToString(),
|
||||||
_ => CustomData?.ToString()!,
|
_ => CustomData?.ToString()!,
|
||||||
};
|
};
|
||||||
return [new Parameterdata
|
return [new ParameterData
|
||||||
{
|
{
|
||||||
State = IsCustomData,
|
State = IsCustomData,
|
||||||
Expression = Expression,
|
Expression = Expression,
|
||||||
@@ -114,11 +114,10 @@ namespace Serein.NodeFlow.Model
|
|||||||
this.Position = nodeInfo.Position;// 加载位置信息
|
this.Position = nodeInfo.Position;// 加载位置信息
|
||||||
for (int i = 0; i < nodeInfo.ParameterData.Length; i++)
|
for (int i = 0; i < nodeInfo.ParameterData.Length; i++)
|
||||||
{
|
{
|
||||||
Parameterdata? pd = nodeInfo.ParameterData[i];
|
ParameterData? pd = nodeInfo.ParameterData[i];
|
||||||
node.IsCustomData = pd.State;
|
node.IsCustomData = pd.State;
|
||||||
node.CustomData = pd.Value;
|
node.CustomData = pd.Value;
|
||||||
node.Expression = pd.Expression;
|
node.Expression = pd.Expression;
|
||||||
|
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ namespace Serein.NodeFlow.Model
|
|||||||
//public override async Task<object?> Executing(IDynamicContext context)
|
//public override async Task<object?> Executing(IDynamicContext context)
|
||||||
public override Task<object?> ExecutingAsync(IDynamicContext context)
|
public override Task<object?> ExecutingAsync(IDynamicContext context)
|
||||||
{
|
{
|
||||||
var data = PreviousNode?.GetFlowData(); // 表达式节点使用上一节点数据
|
var data = context.GetFlowData(PreviousNode.Guid); // 表达式节点使用上一节点数据
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -59,9 +59,9 @@ namespace Serein.NodeFlow.Model
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Parameterdata[] GetParameterdatas()
|
public override ParameterData[] GetParameterdatas()
|
||||||
{
|
{
|
||||||
return [new Parameterdata { Expression = Expression }];
|
return [new ParameterData { Expression = Expression }];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ namespace Serein.NodeFlow.Model
|
|||||||
public override async Task<object?> ExecutingAsync(IDynamicContext context)
|
public override async Task<object?> ExecutingAsync(IDynamicContext context)
|
||||||
{
|
{
|
||||||
#region 执行前中断
|
#region 执行前中断
|
||||||
if (DebugSetting.InterruptClass != InterruptClass.None) // 执行触发前
|
if (DebugSetting.IsInterrupt) // 执行触发前
|
||||||
{
|
{
|
||||||
string guid = this.Guid.ToString();
|
string guid = this.Guid.ToString();
|
||||||
var cancelType = await this.DebugSetting.GetInterruptTask();
|
var cancelType = await this.DebugSetting.GetInterruptTask();
|
||||||
@@ -82,13 +82,15 @@ namespace Serein.NodeFlow.Model
|
|||||||
/// 获取触发器参数
|
/// 获取触发器参数
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public override Parameterdata[] GetParameterdatas()
|
public override ParameterData[] GetParameterdatas()
|
||||||
{
|
{
|
||||||
if (base.MethodDetails.ParameterDetailss.Length > 0)
|
if (base.MethodDetails.ParameterDetailss.Length > 0)
|
||||||
{
|
{
|
||||||
return MethodDetails.ParameterDetailss
|
return MethodDetails.ParameterDetailss
|
||||||
.Select(it => new Parameterdata
|
.Select(it => new ParameterData
|
||||||
{
|
{
|
||||||
|
SourceNodeGuid = it.ArgDataSourceNodeGuid,
|
||||||
|
SourceType = it.ArgDataSourceType.ToString(),
|
||||||
State = it.IsExplicitData,
|
State = it.IsExplicitData,
|
||||||
Value = it.DataValue
|
Value = it.DataValue
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Version>1.0.17</Version>
|
<Version>1.0.18</Version>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
@@ -60,11 +60,6 @@
|
|||||||
</None>
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
|
||||||
<PackageReference Include="System.Collections.NonGeneric" Version="4.3.0" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Serein.Library.MyGenerator\Serein.Library.NodeGenerator.csproj" OutputItemType="Analyzer" />
|
<ProjectReference Include="..\Serein.Library.MyGenerator\Serein.Library.NodeGenerator.csproj" OutputItemType="Analyzer" />
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using Serein.Library.Utils;
|
|||||||
using Serein.Library;
|
using Serein.Library;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using Serein.Library.FlowNode;
|
||||||
|
|
||||||
namespace Serein.NodeFlow.Tool;
|
namespace Serein.NodeFlow.Tool;
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ namespace Serein.Library
|
|||||||
/// 节点的调试设置
|
/// 节点的调试设置
|
||||||
/// </summary>
|
/// </summary>
|
||||||
DebugSetting,
|
DebugSetting,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -68,6 +67,12 @@ namespace Serein.Library
|
|||||||
/// 是否禁止参数进行修改(初始化后不能再通过 Setter 修改)
|
/// 是否禁止参数进行修改(初始化后不能再通过 Setter 修改)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsProtection = false;
|
public bool IsProtection = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 自定义代码
|
||||||
|
/// </summary>
|
||||||
|
public string CustomCode = null;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ namespace Serein.Library.NodeGenerator
|
|||||||
var propertyName = field.ToPropertyName(); // 转为合适的属性名称
|
var propertyName = field.ToPropertyName(); // 转为合适的属性名称
|
||||||
var attributeInfo = fieldKV.Value; // 缓存的特性信息
|
var attributeInfo = fieldKV.Value; // 缓存的特性信息
|
||||||
|
|
||||||
var isProtection = attributeInfo.Search(nameof(PropertyInfo), nameof(PropertyInfo.IsProtection), "true"); // 是否为保护字段
|
var isProtection = attributeInfo.Search(nameof(PropertyInfo), nameof(PropertyInfo.IsProtection), value => bool.Parse(value)); // 是否为保护字段
|
||||||
|
|
||||||
// 生成 getter / setter
|
// 生成 getter / setter
|
||||||
sb.AppendLine(leadingTrivia);
|
sb.AppendLine(leadingTrivia);
|
||||||
@@ -174,11 +174,12 @@ namespace Serein.Library.NodeGenerator
|
|||||||
sb.AppendLine(" {");
|
sb.AppendLine(" {");
|
||||||
sb.AppendLine($" if ({fieldName} {(isProtection ? "== default" : "!= value")})"); // 非保护的Setter
|
sb.AppendLine($" if ({fieldName} {(isProtection ? "== default" : "!= value")})"); // 非保护的Setter
|
||||||
sb.AppendLine(" {");
|
sb.AppendLine(" {");
|
||||||
if (attributeInfo.Search(nameof(PropertyInfo), nameof(PropertyInfo.IsPrint), "true")) // 是否打印
|
sb.AppendLine($" SetProperty<{fieldType}>(ref {fieldName}, value); // 通知UI属性发生改变了");
|
||||||
|
if (attributeInfo.Search(nameof(PropertyInfo), nameof(PropertyInfo.IsPrint), value => bool.Parse(value))) // 是否打印
|
||||||
{
|
{
|
||||||
sb.AddCode(5, $"Console.WriteLine({fieldName});");
|
sb.AddCode(5, $"Console.WriteLine({fieldName});");
|
||||||
}
|
}
|
||||||
if (attributeInfo.Search(nameof(PropertyInfo), nameof(PropertyInfo.IsNotification), "true")) // 是否通知
|
if (attributeInfo.Search(nameof(PropertyInfo), nameof(PropertyInfo.IsNotification), value => bool.Parse(value))) // 是否通知
|
||||||
{
|
{
|
||||||
if (classInfo.ExitsPath(nameof(NodeValuePath.Node))) // 节点 or 自定义节点
|
if (classInfo.ExitsPath(nameof(NodeValuePath.Node))) // 节点 or 自定义节点
|
||||||
{
|
{
|
||||||
@@ -197,7 +198,12 @@ namespace Serein.Library.NodeGenerator
|
|||||||
sb.AddCode(5, $"NodeModel?.Env?.NotificationNodeValueChangeAsync(NodeModel.Guid, \"DebugSetting.\"+nameof({propertyName}), value); // 通知远程环境属性发生改变了");
|
sb.AddCode(5, $"NodeModel?.Env?.NotificationNodeValueChangeAsync(NodeModel.Guid, \"DebugSetting.\"+nameof({propertyName}), value); // 通知远程环境属性发生改变了");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sb.AppendLine($" SetProperty<{fieldType}>(ref {fieldName}, value); // 通知UI属性发生改变了");
|
if (attributeInfo.Search(nameof(PropertyInfo), nameof(PropertyInfo.CustomCode), value => !string.IsNullOrEmpty(value))) // 是否打印
|
||||||
|
{
|
||||||
|
var customCode = attributeInfo[nameof(PropertyInfo)][nameof(PropertyInfo.CustomCode)] as string;
|
||||||
|
customCode = customCode.Trim().Substring(1, customCode.Length - 2);
|
||||||
|
sb.AddCode(5, $"{customCode} // 添加的自定义代码");
|
||||||
|
}
|
||||||
//sb.AppendLine($" {fieldName} = value;");
|
//sb.AppendLine($" {fieldName} = value;");
|
||||||
//sb.AppendLine($" OnPropertyChanged(); // 通知UI属性发生改变了");
|
//sb.AppendLine($" OnPropertyChanged(); // 通知UI属性发生改变了");
|
||||||
sb.AppendLine(" }");
|
sb.AppendLine(" }");
|
||||||
@@ -510,7 +516,7 @@ namespace Serein.Library.NodeGenerator
|
|||||||
public static bool Search(this Dictionary<string, Dictionary<string, string>> dict,
|
public static bool Search(this Dictionary<string, Dictionary<string, string>> dict,
|
||||||
string attributeName = null,
|
string attributeName = null,
|
||||||
string attributePropertyName = null,
|
string attributePropertyName = null,
|
||||||
string comparisonValue = null)
|
Func<string, bool> judgeFunc = null)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(attributeName))
|
if (string.IsNullOrWhiteSpace(attributeName))
|
||||||
return false;
|
return false;
|
||||||
@@ -521,9 +527,11 @@ namespace Serein.Library.NodeGenerator
|
|||||||
return true;
|
return true;
|
||||||
if (!abs.TryGetValue(attributePropertyName, out var absValue))
|
if (!abs.TryGetValue(attributePropertyName, out var absValue))
|
||||||
return false;
|
return false;
|
||||||
if (string.IsNullOrWhiteSpace(comparisonValue))
|
if (judgeFunc == null)
|
||||||
return true;
|
return true;
|
||||||
return absValue.Equals(comparisonValue);
|
|
||||||
|
return judgeFunc.Invoke(absValue); ;
|
||||||
|
//return absValue.Equals(comparisonValue);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
|
<Version>1.0.1</Version>
|
||||||
<IsRoslynComponent>true</IsRoslynComponent>
|
<IsRoslynComponent>true</IsRoslynComponent>
|
||||||
|
|
||||||
<BaseOutputPath>D:\Project\C#\DynamicControl\SereinFlow\.Output</BaseOutputPath>
|
<BaseOutputPath>D:\Project\C#\DynamicControl\SereinFlow\.Output</BaseOutputPath>
|
||||||
@@ -14,6 +15,12 @@
|
|||||||
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
|
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Remove="bin\**" />
|
||||||
|
<EmbeddedResource Remove="bin\**" />
|
||||||
|
<None Remove="bin\**" />
|
||||||
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.11.0" PrivateAssets="all" />
|
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.11.0" PrivateAssets="all" />
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0" PrivateAssets="all" />
|
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0" PrivateAssets="all" />
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ namespace Serein.Workbench
|
|||||||
void LoadLocalProject()
|
void LoadLocalProject()
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
if (1 == 1)
|
if (1 == 11)
|
||||||
{
|
{
|
||||||
string filePath;
|
string filePath;
|
||||||
filePath = @"F:\临时\project\linux\project.dnf";
|
filePath = @"F:\临时\project\linux\project.dnf";
|
||||||
|
|||||||
@@ -1,18 +1,26 @@
|
|||||||
<Window x:Class="Serein.Workbench.MainWindow"
|
<Window x:Class="Serein.Workbench.MainWindow"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:local="clr-namespace:Serein.Workbench"
|
xmlns:local="clr-namespace:Serein.Workbench"
|
||||||
xmlns:tool="clr-namespace:Serein.Workbench.Tool.Converters"
|
xmlns:tool="clr-namespace:Serein.Workbench.Tool.Converters"
|
||||||
xmlns:nodeView="clr-namespace:Serein.Workbench.Node.View"
|
xmlns:nodeView="clr-namespace:Serein.Workbench.Node.View"
|
||||||
xmlns:themes="clr-namespace:Serein.Workbench.Themes"
|
xmlns:themes="clr-namespace:Serein.Workbench.Themes"
|
||||||
|
xmlns:converters="clr-namespace:Serein.Workbench.Tool.Converters"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DataContext="{d:DesignInstance local:MainWindowViewModel}"
|
||||||
Title="Dynamic Node Flow" Height="900" Width="1400"
|
Title="Dynamic Node Flow" Height="900" Width="1400"
|
||||||
AllowDrop="True" Drop="Window_Drop" DragOver="Window_DragOver"
|
AllowDrop="True"
|
||||||
|
Drop="Window_Drop"
|
||||||
|
DragOver="Window_DragOver"
|
||||||
Loaded="Window_Loaded"
|
Loaded="Window_Loaded"
|
||||||
ContentRendered="Window_ContentRendered"
|
ContentRendered="Window_ContentRendered"
|
||||||
PreviewKeyDown="Window_PreviewKeyDown"
|
PreviewKeyDown="Window_PreviewKeyDown"
|
||||||
Closing="Window_Closing">
|
Closing="Window_Closing">
|
||||||
|
|
||||||
<Window.Resources>
|
<Window.Resources>
|
||||||
|
<converters:InvertableBooleanToVisibilityConverter x:Key="InvertedBoolConverter"/>
|
||||||
<tool:RightThumbPositionConverter x:Key="RightThumbPositionConverter" />
|
<tool:RightThumbPositionConverter x:Key="RightThumbPositionConverter" />
|
||||||
<tool:BottomThumbPositionConverter x:Key="BottomThumbPositionConverter" />
|
<tool:BottomThumbPositionConverter x:Key="BottomThumbPositionConverter" />
|
||||||
<tool:VerticalCenterThumbPositionConverter x:Key="VerticalCenterThumbPositionConverter" />
|
<tool:VerticalCenterThumbPositionConverter x:Key="VerticalCenterThumbPositionConverter" />
|
||||||
@@ -35,7 +43,7 @@
|
|||||||
<ColumnDefinition Width="*"/>
|
<ColumnDefinition Width="*"/>
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
<Menu DockPanel.Dock="Top" Grid.Row="0" Height="20">
|
<Menu DockPanel.Dock="Top" Grid.Row="0" Grid.ColumnSpan="5" Height="20">
|
||||||
<MenuItem Header="项目">
|
<MenuItem Header="项目">
|
||||||
<!--菜单项为MenuItem,文字使用属性 Header-->
|
<!--菜单项为MenuItem,文字使用属性 Header-->
|
||||||
<MenuItem Header="保存项目" Click="ButtonSaveFile_Click" ></MenuItem>
|
<MenuItem Header="保存项目" Click="ButtonSaveFile_Click" ></MenuItem>
|
||||||
@@ -99,7 +107,7 @@
|
|||||||
<GridSplitter Grid.Row="1" Grid.Column="1" Width="5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ResizeBehavior="PreviousAndNext" Background="Gray" />
|
<GridSplitter Grid.Row="1" Grid.Column="1" Width="5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ResizeBehavior="PreviousAndNext" Background="Gray" />
|
||||||
|
|
||||||
<Grid Grid.Row="1" Grid.Column="2" x:Name="FlowChartStackGrid">
|
<Grid Grid.Row="1" Grid.Column="2" x:Name="FlowChartStackGrid">
|
||||||
|
|
||||||
<StackPanel x:Name="FlowChartStackPanel"
|
<StackPanel x:Name="FlowChartStackPanel"
|
||||||
|
|
||||||
ClipToBounds="True">
|
ClipToBounds="True">
|
||||||
@@ -199,6 +207,25 @@ Canvas.Top="{Binding ActualHeight, ElementName=FlowChartCanvas, Mode=OneWay, Con
|
|||||||
|
|
||||||
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
<StackPanel>
|
||||||
|
<StackPanel x:Name="CreateNodeInvoke"
|
||||||
|
Margin="14" Width="auto" HorizontalAlignment="Left" Background="White" Opacity="0.7"
|
||||||
|
Visibility="{Binding IsConnectionInvokeNode,
|
||||||
|
Converter={StaticResource InvertedBoolConverter},ConverterParameter=Normal}" >
|
||||||
|
<TextBlock Margin="8,2,8,0" Foreground="#FF2727" FontSize="14" Text="正在设置调用关系"/>
|
||||||
|
<TextBlock Margin="8,0,8,0" Foreground="#4A82E4" FontSize="14" Text=" 按 1 切换:上游分支"/>
|
||||||
|
<TextBlock Margin="8,0,8,0" Foreground="#04FC10" FontSize="14" Text=" 按 2 切换:Succeed 分支"/>
|
||||||
|
<TextBlock Margin="8,0,8,0" Foreground="#F18905" FontSize="14" Text=" 按 3 切换:Fail 分支"/>
|
||||||
|
<TextBlock Margin="8,0,8,2" Foreground="#FE1343" FontSize="14" Text=" 按 4 切换:异常分支"/>
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Margin="14" Width="auto" HorizontalAlignment="Left" Background="White" Opacity="0.9"
|
||||||
|
Visibility="{Binding IsConnectionArgSourceNode,
|
||||||
|
Converter={StaticResource InvertedBoolConverter},ConverterParameter=Normal}" >
|
||||||
|
<TextBlock Margin="8,2,8,0" Foreground="#FF2727" FontSize="14" Text="正在设置参数传递关系"/>
|
||||||
|
<TextBlock Margin="8,0,8,0" Foreground="#56CEF6" FontSize="14" Text=" 按 1 切换:调用时获取指定节点的返回值"/>
|
||||||
|
<TextBlock Margin="8,0,8,2" Foreground="#B06BBB" FontSize="14" Text=" 按 2 切换:调用时立刻调用指定节点,使用其返回值作为入参参数"/>
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
<GridSplitter Grid.Row="1" Grid.Column="3" Width="5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ResizeBehavior="PreviousAndNext" Background="Gray" />
|
<GridSplitter Grid.Row="1" Grid.Column="3" Width="5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ResizeBehavior="PreviousAndNext" Background="Gray" />
|
||||||
<!--IOC容器属性-->
|
<!--IOC容器属性-->
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using Serein.Library.Api;
|
|||||||
using Serein.Library.Utils;
|
using Serein.Library.Utils;
|
||||||
using Serein.Library.Utils.SereinExpression;
|
using Serein.Library.Utils.SereinExpression;
|
||||||
using Serein.NodeFlow.Tool;
|
using Serein.NodeFlow.Tool;
|
||||||
|
using Serein.Workbench.Extension;
|
||||||
using Serein.Workbench.Node;
|
using Serein.Workbench.Node;
|
||||||
using Serein.Workbench.Node.View;
|
using Serein.Workbench.Node.View;
|
||||||
using Serein.Workbench.Node.ViewModel;
|
using Serein.Workbench.Node.ViewModel;
|
||||||
@@ -83,7 +84,7 @@ namespace Serein.Workbench
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 标记是否正在进行连接操作
|
/// 标记是否正在进行连接操作
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private bool IsConnecting;
|
//private bool IsConnecting;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 标记是否正在拖动控件
|
/// 标记是否正在拖动控件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -116,7 +117,7 @@ namespace Serein.Workbench
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 记录开始连接的文本块
|
/// 记录开始连接的文本块
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private NodeControlBase? startConnectNodeControl;
|
//private NodeControlBase? startConnectNodeControl;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 当前正在绘制的连接线
|
/// 当前正在绘制的连接线
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -124,7 +125,7 @@ namespace Serein.Workbench
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 当前正在绘制的真假分支属性
|
/// 当前正在绘制的真假分支属性
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private ConnectionInvokeType currentConnectionType;
|
//private ConnectionInvokeType currentConnectionType;
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -144,36 +145,38 @@ namespace Serein.Workbench
|
|||||||
|
|
||||||
public MainWindow()
|
public MainWindow()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
|
||||||
ViewModel = new MainWindowViewModel(this);
|
ViewModel = new MainWindowViewModel(this);
|
||||||
|
this.DataContext = ViewModel;
|
||||||
|
InitializeComponent();
|
||||||
EnvDecorator = ViewModel.FlowEnvironment;
|
EnvDecorator = ViewModel.FlowEnvironment;
|
||||||
|
|
||||||
ViewObjectViewer.FlowEnvironment = EnvDecorator;
|
ViewObjectViewer.FlowEnvironment = EnvDecorator;
|
||||||
IOCObjectViewer.FlowEnvironment = EnvDecorator;
|
IOCObjectViewer.FlowEnvironment = EnvDecorator;
|
||||||
|
IOCObjectViewer.SelectObj += ViewObjectViewer.LoadObjectInformation;
|
||||||
|
|
||||||
|
|
||||||
//this.FlowEnvironment.SetConsoleOut((msg) => LogOutWindow.AppendText(msg), () => LogOutWindow.Clear()); // 设置输出
|
|
||||||
InitFlowEnvironmentEvent(); // 配置环境事件
|
|
||||||
|
|
||||||
|
|
||||||
|
#region 缩放平移容器
|
||||||
canvasTransformGroup = new TransformGroup();
|
canvasTransformGroup = new TransformGroup();
|
||||||
scaleTransform = new ScaleTransform();
|
scaleTransform = new ScaleTransform();
|
||||||
translateTransform = new TranslateTransform();
|
translateTransform = new TranslateTransform();
|
||||||
|
|
||||||
canvasTransformGroup.Children.Add(scaleTransform);
|
canvasTransformGroup.Children.Add(scaleTransform);
|
||||||
canvasTransformGroup.Children.Add(translateTransform);
|
canvasTransformGroup.Children.Add(translateTransform);
|
||||||
|
|
||||||
FlowChartCanvas.RenderTransform = canvasTransformGroup;
|
FlowChartCanvas.RenderTransform = canvasTransformGroup;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
InitFlowEnvironmentEvent(); // 配置环境事件
|
||||||
|
|
||||||
if (App.FlowProjectData is not null)
|
if (App.FlowProjectData is not null)
|
||||||
{
|
{
|
||||||
EnvDecorator.LoadProject(new FlowEnvInfo { Project = App.FlowProjectData }, App.FileDataPath); // 加载项目
|
EnvDecorator.LoadProject(new FlowEnvInfo { Project = App.FlowProjectData }, App.FileDataPath); // 加载项目
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
IOCObjectViewer.SelectObj += ViewObjectViewer.LoadObjectInformation;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 初始化环境事件
|
/// 初始化环境事件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -229,8 +232,6 @@ namespace Serein.Workbench
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#region 窗体加载方法
|
#region 窗体加载方法
|
||||||
private void Window_Loaded(object sender, RoutedEventArgs e)
|
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
@@ -382,13 +383,14 @@ namespace Serein.Workbench
|
|||||||
JunctionControlBase startJunction = IFormJunction.NextStepJunction;
|
JunctionControlBase startJunction = IFormJunction.NextStepJunction;
|
||||||
JunctionControlBase endJunction = IToJunction.ExecuteJunction;
|
JunctionControlBase endJunction = IToJunction.ExecuteJunction;
|
||||||
|
|
||||||
|
|
||||||
// 添加连接
|
// 添加连接
|
||||||
var connection = new ConnectionControl(
|
var connection = new ConnectionControl(
|
||||||
FlowChartCanvas,
|
FlowChartCanvas,
|
||||||
connectionType,
|
connectionType,
|
||||||
startJunction,
|
startJunction,
|
||||||
endJunction,
|
endJunction,
|
||||||
() => EnvDecorator.RemoveConnectAsync(fromNodeGuid, toNodeGuid, connectionType)
|
() => EnvDecorator.RemoveConnectInvokeAsync(fromNodeGuid, toNodeGuid, connectionType)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (toNodeControl is FlipflopNodeControl flipflopControl
|
if (toNodeControl is FlipflopNodeControl flipflopControl
|
||||||
@@ -400,7 +402,7 @@ namespace Serein.Workbench
|
|||||||
Connections.Add(connection);
|
Connections.Add(connection);
|
||||||
fromNodeControl.AddCnnection(connection);
|
fromNodeControl.AddCnnection(connection);
|
||||||
toNodeControl.AddCnnection(connection);
|
toNodeControl.AddCnnection(connection);
|
||||||
EndConnection();
|
EndConnection(); // 环境触发了创建节点连接事件
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -440,7 +442,7 @@ namespace Serein.Workbench
|
|||||||
|
|
||||||
JunctionControlBase startJunction = eventArgs.ConnectionArgSourceType switch
|
JunctionControlBase startJunction = eventArgs.ConnectionArgSourceType switch
|
||||||
{
|
{
|
||||||
ConnectionArgSourceType.GetPreviousNodeData => IFormJunction.ExecuteJunction, // 自身节点
|
ConnectionArgSourceType.GetPreviousNodeData => IFormJunction.ReturnDataJunction, // 自身节点
|
||||||
ConnectionArgSourceType.GetOtherNodeData => IFormJunction.ReturnDataJunction, // 其它节点的返回值控制点
|
ConnectionArgSourceType.GetOtherNodeData => IFormJunction.ReturnDataJunction, // 其它节点的返回值控制点
|
||||||
ConnectionArgSourceType.GetOtherNodeDataOfInvoke => IFormJunction.ReturnDataJunction, // 其它节点的返回值控制点
|
ConnectionArgSourceType.GetOtherNodeDataOfInvoke => IFormJunction.ReturnDataJunction, // 其它节点的返回值控制点
|
||||||
_ => throw new Exception("窗体事件 FlowEnvironment_NodeConnectChangeEvemt 创建/删除节点之间的参数传递关系 JunctionControlBase 枚举值错误 。非预期的枚举值。") // 应该不会触发
|
_ => throw new Exception("窗体事件 FlowEnvironment_NodeConnectChangeEvemt 创建/删除节点之间的参数传递关系 JunctionControlBase 枚举值错误 。非预期的枚举值。") // 应该不会触发
|
||||||
@@ -448,11 +450,6 @@ namespace Serein.Workbench
|
|||||||
|
|
||||||
JunctionControlBase endJunction = IToJunction.ArgDataJunction[eventArgs.ArgIndex];
|
JunctionControlBase endJunction = IToJunction.ArgDataJunction[eventArgs.ArgIndex];
|
||||||
LineType lineType = LineType.Bezier;
|
LineType lineType = LineType.Bezier;
|
||||||
if(eventArgs.ConnectionArgSourceType == ConnectionArgSourceType.GetPreviousNodeData)
|
|
||||||
{
|
|
||||||
lineType = LineType.Semicircle;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加连接
|
// 添加连接
|
||||||
var connection = new ConnectionControl(
|
var connection = new ConnectionControl(
|
||||||
lineType,
|
lineType,
|
||||||
@@ -461,19 +458,19 @@ namespace Serein.Workbench
|
|||||||
eventArgs.ConnectionArgSourceType,
|
eventArgs.ConnectionArgSourceType,
|
||||||
startJunction,
|
startJunction,
|
||||||
endJunction,
|
endJunction,
|
||||||
() => EnvDecorator.RemoveConnectAsync(fromNodeGuid, toNodeGuid, 0)
|
() => EnvDecorator.RemoveConnectArgSourceAsync(fromNodeGuid, toNodeGuid, eventArgs.ArgIndex)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (toNodeControl is FlipflopNodeControl flipflopControl
|
//if (toNodeControl is FlipflopNodeControl flipflopControl
|
||||||
&& flipflopControl?.ViewModel?.NodeModel is NodeModelBase nodeModel) // 某个节点连接到了触发器,尝试从全局触发器视图中移除该触发器
|
// && flipflopControl?.ViewModel?.NodeModel is NodeModelBase nodeModel) // 某个节点连接到了触发器,尝试从全局触发器视图中移除该触发器
|
||||||
{
|
//{
|
||||||
NodeTreeViewer.RemoteGlobalFlipFlop(nodeModel); // 从全局触发器树树视图中移除
|
// NodeTreeViewer.RemoteGlobalFlipFlop(nodeModel); // 从全局触发器树树视图中移除
|
||||||
}
|
//}
|
||||||
connection.RefreshLine(); // 添加贝塞尔曲线显示
|
connection.RefreshLine(); // 添加贝塞尔曲线显示
|
||||||
Connections.Add(connection);
|
Connections.Add(connection);
|
||||||
fromNodeControl.AddCnnection(connection);
|
fromNodeControl.AddCnnection(connection);
|
||||||
toNodeControl.AddCnnection(connection);
|
toNodeControl.AddCnnection(connection);
|
||||||
EndConnection();
|
EndConnection(); // 环境触发了创建节点连接事件
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -481,20 +478,27 @@ namespace Serein.Workbench
|
|||||||
{
|
{
|
||||||
// 需要移除连接
|
// 需要移除连接
|
||||||
var removeConnections = Connections.Where(c => c.Start.MyNode.Guid.Equals(fromNodeGuid)
|
var removeConnections = Connections.Where(c => c.Start.MyNode.Guid.Equals(fromNodeGuid)
|
||||||
&& c.End.MyNode.Guid.Equals(toNodeGuid))
|
&& c.End.MyNode.Guid.Equals(toNodeGuid))
|
||||||
.ToList();
|
.ToList(); // 获取这两个节点之间的所有连接关系
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
foreach (var connection in removeConnections)
|
foreach (var connection in removeConnections)
|
||||||
{
|
{
|
||||||
connection.DeleteConnection();
|
if(connection.End is ArgJunctionControl junctionControl && junctionControl.ArgIndex == eventArgs.ArgIndex)
|
||||||
Connections.Remove(connection);
|
|
||||||
fromNodeControl.RemoveCnnection(connection);
|
|
||||||
toNodeControl.RemoveCnnection(connection);
|
|
||||||
if (NodeControls.TryGetValue(connection.End.MyNode.Guid, out var control))
|
|
||||||
{
|
{
|
||||||
JudgmentFlipFlopNode(control); // 连接关系变更时判断
|
// 找到符合删除条件的连接线
|
||||||
|
connection.DeleteConnection(); // 从UI层面上移除
|
||||||
|
Connections.Remove(connection); // 从本地记录中移除
|
||||||
|
fromNodeControl.RemoveCnnection(connection); // 从节点持有的记录移除
|
||||||
|
toNodeControl.RemoveCnnection(connection); // 从节点持有的记录移除
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//if (NodeControls.TryGetValue(connection.End.MyNode.Guid, out var control))
|
||||||
|
//{
|
||||||
|
// JudgmentFlipFlopNode(control); // 连接关系变更时判断
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
@@ -1044,15 +1048,17 @@ namespace Serein.Workbench
|
|||||||
{
|
{
|
||||||
if ((s is MenuItem menuItem) && menuItem is not null)
|
if ((s is MenuItem menuItem) && menuItem is not null)
|
||||||
{
|
{
|
||||||
if (nodeControl?.ViewModel?.NodeModel?.DebugSetting?.InterruptClass == InterruptClass.None)
|
if (nodeControl?.ViewModel?.NodeModel?.DebugSetting?.IsInterrupt == true)
|
||||||
{
|
{
|
||||||
await EnvDecorator.SetNodeInterruptAsync(nodeGuid, InterruptClass.Branch);
|
await EnvDecorator.SetNodeInterruptAsync(nodeGuid,false);
|
||||||
|
nodeControl.ViewModel.IsInterrupt = false;
|
||||||
|
|
||||||
menuItem.Header = "取消中断";
|
menuItem.Header = "取消中断";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await EnvDecorator.SetNodeInterruptAsync(nodeGuid, InterruptClass.None);
|
nodeControl!.ViewModel!.IsInterrupt = true;
|
||||||
|
await EnvDecorator.SetNodeInterruptAsync(nodeGuid, true);
|
||||||
menuItem.Header = "在此中断";
|
menuItem.Header = "在此中断";
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1166,7 +1172,7 @@ namespace Serein.Workbench
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 与流程图与节点相关
|
#region 与流程图/节点相关
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 鼠标在画布移动。
|
/// 鼠标在画布移动。
|
||||||
@@ -1176,36 +1182,28 @@ namespace Serein.Workbench
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void FlowChartCanvas_MouseMove(object sender, MouseEventArgs e)
|
private void FlowChartCanvas_MouseMove(object sender, MouseEventArgs e)
|
||||||
{
|
{
|
||||||
|
var myData = GlobalJunctionData.MyGlobalConnectingData;
|
||||||
|
if (myData.IsCreateing && e.LeftButton == MouseButtonState.Pressed)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (myData.Type == JunctionOfConnectionType.Invoke)
|
||||||
|
{
|
||||||
|
ViewModel.IsConnectionInvokeNode = true; // 正在连接节点的调用关系
|
||||||
|
|
||||||
if (e.LeftButton == MouseButtonState.Pressed && GlobalJunctionData.MyGlobalConnectingData is not null)
|
}
|
||||||
{
|
else
|
||||||
// 正在连接节点
|
{
|
||||||
//var controlPointPosition = GlobalJunctionData.MyGlobalConnectingData.StartPoint;
|
ViewModel.IsConnectionArgSourceNode = true; // 正在连接节点的调用关系
|
||||||
|
}
|
||||||
var currentPoint = e.GetPosition(FlowChartCanvas);
|
var currentPoint = e.GetPosition(FlowChartCanvas);
|
||||||
GlobalJunctionData.MyGlobalConnectingData.UpdatePoint(currentPoint);
|
currentPoint.X -= 2;
|
||||||
|
currentPoint.Y -= 2;
|
||||||
|
myData.UpdatePoint(currentPoint);
|
||||||
//virtualLine.VirtualLine.UpdatePoints(currentPoint);
|
|
||||||
|
|
||||||
//virtualLine.VirtualLine.X1 = controlPointPosition.X;
|
|
||||||
//virtualLine.VirtualLine.Y1 = controlPointPosition.Y;
|
|
||||||
//virtualLine.VirtualLine.X2 = currentPoint.X;
|
|
||||||
//virtualLine.VirtualLine.Y2 = currentPoint.Y;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//if (IsConnecting) // 正在连接节点
|
|
||||||
//{
|
|
||||||
// Point position = e.GetPosition(FlowChartCanvas);
|
|
||||||
// if (currentLine is null || startConnectNodeControl is null)
|
|
||||||
// {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// currentLine.X1 = Canvas.GetLeft(startConnectNodeControl) + startConnectNodeControl.ActualWidth / 2;
|
|
||||||
// currentLine.Y1 = Canvas.GetTop(startConnectNodeControl) + startConnectNodeControl.ActualHeight / 2;
|
|
||||||
// currentLine.X2 = position.X;
|
|
||||||
// currentLine.Y2 = position.Y;
|
|
||||||
//}
|
|
||||||
|
|
||||||
if (IsCanvasDragging && e.MiddleButton == MouseButtonState.Pressed) // 正在移动画布(按住中键)
|
if (IsCanvasDragging && e.MiddleButton == MouseButtonState.Pressed) // 正在移动画布(按住中键)
|
||||||
{
|
{
|
||||||
Point currentMousePosition = e.GetPosition(this);
|
Point currentMousePosition = e.GetPosition(this);
|
||||||
@@ -1399,8 +1397,6 @@ namespace Serein.Workbench
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void Block_MouseMove(object sender, MouseEventArgs e)
|
private void Block_MouseMove(object sender, MouseEventArgs e)
|
||||||
{
|
{
|
||||||
if (IsConnecting)
|
|
||||||
return;
|
|
||||||
if (IsCanvasDragging)
|
if (IsCanvasDragging)
|
||||||
return;
|
return;
|
||||||
if (IsSelectControl)
|
if (IsSelectControl)
|
||||||
@@ -1465,8 +1461,8 @@ namespace Serein.Workbench
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 改变对象树?
|
// 改变对象树?
|
||||||
private void ChangeViewerObjOfNode(NodeControlBase nodeControl)
|
private void ChangeViewerObjOfNode(NodeControlBase nodeControl)
|
||||||
{
|
{
|
||||||
@@ -1475,7 +1471,9 @@ namespace Serein.Workbench
|
|||||||
if (node is not null && node.MethodDetails?.ReturnType != typeof(void))
|
if (node is not null && node.MethodDetails?.ReturnType != typeof(void))
|
||||||
{
|
{
|
||||||
var key = node.Guid;
|
var key = node.Guid;
|
||||||
var instance = node.GetFlowData(); // 对象预览树视图获取(后期更改)
|
object instance = null;
|
||||||
|
//Console.WriteLine("WindowXaml 后台代码中 ChangeViewerObjOfNode 需要重新设计");
|
||||||
|
//var instance = node.GetFlowData(); // 对象预览树视图获取(后期更改)
|
||||||
if(instance is not null)
|
if(instance is not null)
|
||||||
{
|
{
|
||||||
ViewObjectViewer.LoadObjectInformation(key, instance);
|
ViewObjectViewer.LoadObjectInformation(key, instance);
|
||||||
@@ -1505,12 +1503,12 @@ namespace Serein.Workbench
|
|||||||
EnvDecorator.SetMonitorObjState(key, true); // 通知环境,该节点的数据更新后需要传到UI
|
EnvDecorator.SetMonitorObjState(key, true); // 通知环境,该节点的数据更新后需要传到UI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region UI连接控件操作
|
#region UI连接控件操作
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 控件的鼠标左键松开事件,结束拖动操作,创建连线
|
/// 控件的鼠标左键松开事件,结束拖动操作
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void Block_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
|
private void Block_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
|
||||||
{
|
{
|
||||||
@@ -1534,52 +1532,18 @@ namespace Serein.Workbench
|
|||||||
//GlobalJunctionData.OK();
|
//GlobalJunctionData.OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 主窗口的KeyDown事件处理,用于在连接操作中按下Esc键取消连接。
|
|
||||||
/// </summary>
|
|
||||||
private void MainWindow_KeyDown(object sender, KeyEventArgs e)
|
|
||||||
{
|
|
||||||
if (e.Key == Key.Escape && IsConnecting)
|
|
||||||
{
|
|
||||||
this.KeyDown -= MainWindow_KeyDown;
|
|
||||||
EndConnection();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 结束连接操作,清理状态并移除虚线。
|
/// 结束连接操作,清理状态并移除虚线。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void EndConnection()
|
private void EndConnection()
|
||||||
{
|
{
|
||||||
IsConnecting = false;
|
Mouse.OverrideCursor = null; // 恢复视觉效果
|
||||||
startConnectNodeControl = null;
|
ViewModel.IsConnectionArgSourceNode = false;
|
||||||
// 移除虚线
|
ViewModel.IsConnectionInvokeNode = false;
|
||||||
//if (currentLine != null)
|
GlobalJunctionData.OK();
|
||||||
//{
|
|
||||||
// FlowChartCanvas.Children.Remove(currentLine);
|
|
||||||
// currentLine = null;
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 更新与指定控件相关的所有连接的位置。
|
|
||||||
/// </summary>
|
|
||||||
//private void UpdateConnections(NodeControlBase nodeControl)
|
|
||||||
//{
|
|
||||||
// nodeControl.UpdateLocationConnections();
|
|
||||||
// //foreach (var connection in Connections)
|
|
||||||
// //{
|
|
||||||
// // if (connection.Start.MyNode.Guid == nodeControl.ViewModel.NodeModel.Guid
|
|
||||||
// // || connection.End.MyNode.Guid == nodeControl.ViewModel.NodeModel.Guid)
|
|
||||||
// // {
|
|
||||||
// // connection.RefreshLine(); // 主动更新某个控件相关的所有连接线
|
|
||||||
// // //connection.RemoveFromCanvas();
|
|
||||||
// // //BezierLineDrawer.UpdateBezierLine(FlowChartCanvas, connection.Start, connection.End, connection.BezierPath, connection.ArrowPath);
|
|
||||||
// // }
|
|
||||||
// //}
|
|
||||||
//}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region 拖动画布实现缩放平移效果
|
#region 拖动画布实现缩放平移效果
|
||||||
private void FlowChartCanvas_MouseDown(object sender, MouseButtonEventArgs e)
|
private void FlowChartCanvas_MouseDown(object sender, MouseButtonEventArgs e)
|
||||||
{
|
{
|
||||||
@@ -1607,7 +1571,7 @@ namespace Serein.Workbench
|
|||||||
// if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
|
// if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
|
||||||
{
|
{
|
||||||
if (e.Delta < 0 && scaleTransform.ScaleX < 0.05) return;
|
if (e.Delta < 0 && scaleTransform.ScaleX < 0.05) return;
|
||||||
if (e.Delta > 0 && scaleTransform.ScaleY > 1.5) return;
|
if (e.Delta > 0 && scaleTransform.ScaleY > 2.0) return;
|
||||||
// 获取鼠标在 Canvas 内的相对位置
|
// 获取鼠标在 Canvas 内的相对位置
|
||||||
var mousePosition = e.GetPosition(FlowChartCanvas);
|
var mousePosition = e.GetPosition(FlowChartCanvas);
|
||||||
|
|
||||||
@@ -1781,7 +1745,7 @@ namespace Serein.Workbench
|
|||||||
/// <param name="e"></param>
|
/// <param name="e"></param>
|
||||||
private void FlowChartCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
private void FlowChartCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||||
{
|
{
|
||||||
if (GlobalJunctionData.MyGlobalConnectingData is not null)
|
if (GlobalJunctionData.MyGlobalConnectingData.IsCreateing)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1835,36 +1799,52 @@ namespace Serein.Workbench
|
|||||||
// 释放鼠标捕获
|
// 释放鼠标捕获
|
||||||
FlowChartCanvas.ReleaseMouseCapture();
|
FlowChartCanvas.ReleaseMouseCapture();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建连线
|
// 创建连线
|
||||||
if (GlobalJunctionData.MyGlobalConnectingData is not null)
|
if (GlobalJunctionData.MyGlobalConnectingData is ConnectingData myData && myData.IsCreateing)
|
||||||
{
|
{
|
||||||
var myData = GlobalJunctionData.MyGlobalConnectingData;
|
|
||||||
GlobalJunctionData.OK();
|
|
||||||
var canvas = this.FlowChartCanvas;
|
|
||||||
if (myData.IsCanConnected)
|
if (myData.IsCanConnected)
|
||||||
{
|
{
|
||||||
|
var canvas = this.FlowChartCanvas;
|
||||||
var currentendPoint = e.GetPosition(canvas); // 当前鼠标落点
|
var currentendPoint = e.GetPosition(canvas); // 当前鼠标落点
|
||||||
var changingJunctionPosition = myData.CurrentJunction.TranslatePoint(new Point(0, 0), canvas);
|
var changingJunctionPosition = myData.CurrentJunction.TranslatePoint(new Point(0, 0), canvas);
|
||||||
var changingJunctionRect = new Rect(changingJunctionPosition, new Size(myData.CurrentJunction.Width, myData.CurrentJunction.Height));
|
var changingJunctionRect = new Rect(changingJunctionPosition, new Size(myData.CurrentJunction.Width, myData.CurrentJunction.Height));
|
||||||
|
|
||||||
if (changingJunctionRect.Contains(currentendPoint)) // 可以创建连接
|
if (changingJunctionRect.Contains(currentendPoint)) // 可以创建连接
|
||||||
{
|
{
|
||||||
var argIndex = 0;
|
#region 方法调用关系创建
|
||||||
if(myData.StartJunction is ArgJunctionControl argJunction1)
|
if (myData.Type == JunctionOfConnectionType.Invoke)
|
||||||
{
|
{
|
||||||
argIndex = argJunction1.ArgIndex;
|
this.EnvDecorator.ConnectInvokeNodeAsync(myData.StartJunction.MyNode.Guid, myData.CurrentJunction.MyNode.Guid,
|
||||||
|
myData.StartJunction.JunctionType,
|
||||||
|
myData.CurrentJunction.JunctionType,
|
||||||
|
myData.ConnectionInvokeType);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
#region 参数来源关系创建
|
||||||
|
else if (myData.Type == JunctionOfConnectionType.Arg)
|
||||||
|
{
|
||||||
|
var argIndex = 0;
|
||||||
|
if (myData.StartJunction is ArgJunctionControl argJunction1)
|
||||||
|
{
|
||||||
|
argIndex = argJunction1.ArgIndex;
|
||||||
|
}
|
||||||
|
else if (myData.CurrentJunction is ArgJunctionControl argJunction2)
|
||||||
|
{
|
||||||
|
argIndex = argJunction2.ArgIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.EnvDecorator.ConnectArgSourceNodeAsync(myData.StartJunction.MyNode.Guid, myData.CurrentJunction.MyNode.Guid,
|
||||||
|
myData.StartJunction.JunctionType,
|
||||||
|
myData.CurrentJunction.JunctionType,
|
||||||
|
myData.ConnectionArgSourceType,
|
||||||
|
argIndex);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
}
|
|
||||||
else if (myData.CurrentJunction is ArgJunctionControl argJunction2)
|
|
||||||
{
|
|
||||||
argIndex = argJunction2.ArgIndex;
|
|
||||||
}
|
|
||||||
this.EnvDecorator.ConnectNodeAsync(myData.StartJunction.MyNode.Guid, myData.CurrentJunction.MyNode.Guid,
|
|
||||||
myData.StartJunction.JunctionType,
|
|
||||||
myData.CurrentJunction.JunctionType,
|
|
||||||
ConnectionInvokeType.IsSucceed,argIndex);
|
|
||||||
}
|
}
|
||||||
|
EndConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -2605,6 +2585,7 @@ namespace Serein.Workbench
|
|||||||
#region 顶部菜单栏 - 远程管理
|
#region 顶部菜单栏 - 远程管理
|
||||||
private async void ButtonStartRemoteServer_Click(object sender, RoutedEventArgs e)
|
private async void ButtonStartRemoteServer_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
|
|
||||||
await this.EnvDecorator.StartRemoteServerAsync();
|
await this.EnvDecorator.StartRemoteServerAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2618,12 +2599,13 @@ namespace Serein.Workbench
|
|||||||
var windowEnvRemoteLoginView = new WindowEnvRemoteLoginView(async (addres, port, token) =>
|
var windowEnvRemoteLoginView = new WindowEnvRemoteLoginView(async (addres, port, token) =>
|
||||||
{
|
{
|
||||||
ResetFlowEnvironmentEvent();// 移除事件
|
ResetFlowEnvironmentEvent();// 移除事件
|
||||||
(var isConnect, RemoteEnvControl remoteEnvControl) = await this.EnvDecorator.ConnectRemoteEnv(addres, port, token);
|
(var isConnect, var _) = await this.EnvDecorator.ConnectRemoteEnv(addres, port, token);
|
||||||
InitFlowEnvironmentEvent(); // 重新添加时间(如果没有连接成功,那么依然是原本的环境)
|
InitFlowEnvironmentEvent(); // 重新添加事件(如果没有连接成功,那么依然是原本的环境)
|
||||||
if (isConnect)
|
if (isConnect)
|
||||||
{
|
{
|
||||||
// 连接成功,加载远程项目
|
// 连接成功,加载远程项目
|
||||||
var flowEnvInfo = await EnvDecorator.GetEnvInfoAsync();
|
var flowEnvInfo = await EnvDecorator.GetEnvInfoAsync();
|
||||||
|
await Task.Delay(1000);
|
||||||
EnvDecorator.LoadProject(flowEnvInfo, string.Empty);// 加载远程环境的项目
|
EnvDecorator.LoadProject(flowEnvInfo, string.Empty);// 加载远程环境的项目
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -2635,7 +2617,7 @@ namespace Serein.Workbench
|
|||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 按键监听。esc取消操作
|
/// 窗体按键监听。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="sender"></param>
|
/// <param name="sender"></param>
|
||||||
/// <param name="e"></param>
|
/// <param name="e"></param>
|
||||||
@@ -2647,16 +2629,53 @@ namespace Serein.Workbench
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (e.KeyStates == Keyboard.GetKeyStates(Key.Escape))
|
if (e.KeyStates == Keyboard.GetKeyStates(Key.Escape))
|
||||||
//if (Keyboard.Modifiers == ModifierKeys.Shift)
|
|
||||||
{
|
{
|
||||||
IsConnecting = false;
|
|
||||||
IsControlDragging = false;
|
IsControlDragging = false;
|
||||||
IsCanvasDragging = false;
|
IsCanvasDragging = false;
|
||||||
EndConnection();
|
|
||||||
SelectionRectangle.Visibility = Visibility.Collapsed;
|
SelectionRectangle.Visibility = Visibility.Collapsed;
|
||||||
CancelSelectNode();
|
CancelSelectNode();
|
||||||
|
EndConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(GlobalJunctionData.MyGlobalConnectingData is ConnectingData myData && myData.IsCreateing)
|
||||||
|
{
|
||||||
|
if(myData.Type == JunctionOfConnectionType.Invoke)
|
||||||
|
{
|
||||||
|
ConnectionInvokeType connectionInvokeType = e.KeyStates switch
|
||||||
|
{
|
||||||
|
KeyStates k when k == Keyboard.GetKeyStates(Key.D1) => ConnectionInvokeType.Upstream,
|
||||||
|
KeyStates k when k == Keyboard.GetKeyStates(Key.D2) => ConnectionInvokeType.IsSucceed,
|
||||||
|
KeyStates k when k == Keyboard.GetKeyStates(Key.D3) => ConnectionInvokeType.IsFail,
|
||||||
|
KeyStates k when k == Keyboard.GetKeyStates(Key.D4) => ConnectionInvokeType.IsError,
|
||||||
|
_ => ConnectionInvokeType.None,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (connectionInvokeType != ConnectionInvokeType.None)
|
||||||
|
{
|
||||||
|
myData.ConnectionInvokeType = connectionInvokeType;
|
||||||
|
myData.MyLine.Line.UpdateLineColor(connectionInvokeType.ToLineColor());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (myData.Type == JunctionOfConnectionType.Arg)
|
||||||
|
{
|
||||||
|
ConnectionArgSourceType connectionArgSourceType = e.KeyStates switch
|
||||||
|
{
|
||||||
|
KeyStates k when k == Keyboard.GetKeyStates(Key.D1) => ConnectionArgSourceType.GetOtherNodeData,
|
||||||
|
KeyStates k when k == Keyboard.GetKeyStates(Key.D2) => ConnectionArgSourceType.GetOtherNodeDataOfInvoke,
|
||||||
|
_ => ConnectionArgSourceType.GetPreviousNodeData,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (connectionArgSourceType != ConnectionArgSourceType.GetPreviousNodeData)
|
||||||
|
{
|
||||||
|
myData.ConnectionArgSourceType = connectionArgSourceType;
|
||||||
|
myData.MyLine.Line.UpdateLineColor(connectionArgSourceType.ToLineColor());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
myData.CurrentJunction.InvalidateVisual(); // 刷新目标节点控制点样式
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -2705,12 +2724,13 @@ namespace Serein.Workbench
|
|||||||
}
|
}
|
||||||
ObjDynamicCreateHelper.PrintObjectProperties(result!);
|
ObjDynamicCreateHelper.PrintObjectProperties(result!);
|
||||||
Console.WriteLine( );
|
Console.WriteLine( );
|
||||||
var exp = "@set .Addresses[1].Street = qwq";
|
var exp = "@set .Addresses[1].Street = 233";
|
||||||
var data = SerinExpressionEvaluator.Evaluate(exp, result!, out bool isChange);
|
var data = SerinExpressionEvaluator.Evaluate(exp, result!, out bool isChange);
|
||||||
exp = "@get .Addresses[1].Street";
|
exp = "@get .Addresses[1].Street";
|
||||||
data = SerinExpressionEvaluator.Evaluate(exp,result!, out isChange);
|
data = SerinExpressionEvaluator.Evaluate(exp,result!, out isChange);
|
||||||
Console.WriteLine($"{exp} => {data}");
|
Console.WriteLine($"{exp} => {data}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 卸载DLL文件,清空当前项目
|
/// 卸载DLL文件,清空当前项目
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -2719,9 +2739,8 @@ namespace Serein.Workbench
|
|||||||
private void UnloadAllButton_Click(object sender, RoutedEventArgs e)
|
private void UnloadAllButton_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
EnvDecorator.ClearAll();
|
EnvDecorator.ClearAll();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 卸载DLL文件,清空当前项目
|
/// 卸载DLL文件,清空当前项目
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -2732,23 +2751,10 @@ namespace Serein.Workbench
|
|||||||
Connections.Clear();
|
Connections.Clear();
|
||||||
NodeControls.Clear();
|
NodeControls.Clear();
|
||||||
//currentLine = null;
|
//currentLine = null;
|
||||||
startConnectNodeControl = null;
|
//startConnectNodeControl = null;
|
||||||
MessageBox.Show("所有DLL已卸载。", "信息", MessageBoxButton.OK, MessageBoxImage.Information);
|
MessageBox.Show("所有DLL已卸载。", "信息", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#region 创建两个控件之间的连接关系,在UI层面上显示为 带箭头指向的贝塞尔曲线
|
|
||||||
|
|
||||||
#region 拓展方法 Extension
|
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
using Serein.Library.Api;
|
using Serein.Library.Api;
|
||||||
using Serein.Library.Utils;
|
using Serein.Library.Utils;
|
||||||
using Serein.NodeFlow.Env;
|
using Serein.NodeFlow.Env;
|
||||||
|
using System.ComponentModel;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
|
||||||
namespace Serein.Workbench
|
namespace Serein.Workbench
|
||||||
@@ -9,9 +10,10 @@ namespace Serein.Workbench
|
|||||||
/// 工作台数据视图
|
/// 工作台数据视图
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="window"></param>
|
/// <param name="window"></param>
|
||||||
public class MainWindowViewModel
|
public class MainWindowViewModel: INotifyPropertyChanged
|
||||||
{
|
{
|
||||||
private readonly MainWindow window ;
|
private readonly MainWindow window ;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 运行环境
|
/// 运行环境
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -46,5 +48,54 @@ namespace Serein.Workbench
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private bool _isConnectionInvokeNode = false;
|
||||||
|
/// <summary>
|
||||||
|
/// 是否正在连接节点的方法调用关系
|
||||||
|
/// </summary>
|
||||||
|
public bool IsConnectionInvokeNode { get => _isConnectionInvokeNode; set
|
||||||
|
{
|
||||||
|
if (_isConnectionInvokeNode != value)
|
||||||
|
{
|
||||||
|
SetProperty<bool>(ref _isConnectionInvokeNode, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool _isConnectionArgSouceNode = false;
|
||||||
|
/// <summary>
|
||||||
|
/// 是否正在连接节点的参数传递关系
|
||||||
|
/// </summary>
|
||||||
|
public bool IsConnectionArgSourceNode { get => _isConnectionArgSouceNode; set
|
||||||
|
{
|
||||||
|
if (_isConnectionArgSouceNode != value)
|
||||||
|
{
|
||||||
|
SetProperty<bool>(ref _isConnectionArgSouceNode, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 略
|
||||||
|
/// <para>此事件为自动生成</para>
|
||||||
|
/// </summary>
|
||||||
|
public event PropertyChangedEventHandler? PropertyChanged;
|
||||||
|
/// <summary>
|
||||||
|
/// 通知属性变更
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">类型</typeparam>
|
||||||
|
/// <param name="storage">绑定的变量</param>
|
||||||
|
/// <param name="value">新的数据</param>
|
||||||
|
/// <param name="propertyName"></param>
|
||||||
|
protected void SetProperty<T>(ref T storage, T value, [System.Runtime.CompilerServices.CallerMemberName] string propertyName = null)
|
||||||
|
{
|
||||||
|
if (Equals(storage, value))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
storage = value;
|
||||||
|
PropertyChanged?.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,26 +54,26 @@ namespace Serein.Workbench.Node.ViewModel
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
//private bool isInterrupt;
|
private bool isInterrupt;
|
||||||
/////// <summary>
|
///// <summary>
|
||||||
/////// 控制中断状态的视觉效果
|
///// 控制中断状态的视觉效果
|
||||||
/////// </summary>
|
///// </summary>
|
||||||
//public bool IsInterrupt
|
public bool IsInterrupt
|
||||||
//{
|
{
|
||||||
// get => NodeModel.DebugSetting.IsInterrupt;
|
get => NodeModel.DebugSetting.IsInterrupt;
|
||||||
// set
|
set
|
||||||
// {
|
{
|
||||||
// NodeModel.DebugSetting.IsInterrupt = value;
|
NodeModel.DebugSetting.IsInterrupt = value;
|
||||||
// OnPropertyChanged();
|
OnPropertyChanged();
|
||||||
// }
|
}
|
||||||
//}
|
}
|
||||||
|
|
||||||
//public event PropertyChangedEventHandler? PropertyChanged;
|
public event PropertyChangedEventHandler? PropertyChanged;
|
||||||
//protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||||
//{
|
{
|
||||||
// //Console.WriteLine(propertyName);
|
//Console.WriteLine(propertyName);
|
||||||
// PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||||
//}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:local="clr-namespace:Serein.Workbench.Node.View"
|
xmlns:local="clr-namespace:Serein.Workbench.Node.View"
|
||||||
xmlns:vm="clr-namespace:Serein.Workbench.Node.ViewModel"
|
xmlns:vm="clr-namespace:Serein.Workbench.Node.ViewModel"
|
||||||
xmlns:Converters="clr-namespace:Serein.Workbench.Tool.Converters"
|
xmlns:converters="clr-namespace:Serein.Workbench.Tool.Converters"
|
||||||
xmlns:themes="clr-namespace:Serein.Workbench.Themes"
|
xmlns:themes="clr-namespace:Serein.Workbench.Themes"
|
||||||
d:DataContext="{d:DesignInstance vm:ActionNodeControlViewModel}"
|
d:DataContext="{d:DesignInstance vm:ActionNodeControlViewModel}"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<!--<BooleanToVisibilityConverter x:Key="BoolToVisConverter" />-->
|
<!--<BooleanToVisibilityConverter x:Key="BoolToVisConverter" />-->
|
||||||
<Converters:InvertableBooleanToVisibilityConverter x:Key="InvertedBoolConverter"/>
|
<converters:InvertableBooleanToVisibilityConverter x:Key="InvertedBoolConverter"/>
|
||||||
<!--<ResourceDictionary Source="/Serein.Workbench;Node/View/NodeExecuteJunctionControl.xaml" x:Key="NodeExecuteJunctionControl"/>-->
|
<!--<ResourceDictionary Source="/Serein.Workbench;Node/View/NodeExecuteJunctionControl.xaml" x:Key="NodeExecuteJunctionControl"/>-->
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
|
|
||||||
@@ -27,15 +27,17 @@
|
|||||||
|
|
||||||
|
|
||||||
<!--<TextBlock Text="{Binding NodelModel.DebugSetting.IsInterrupt}}"></TextBlock>-->
|
<!--<TextBlock Text="{Binding NodelModel.DebugSetting.IsInterrupt}}"></TextBlock>-->
|
||||||
<Border x:Name="InterruptBorder">
|
<Border x:Name="InterruptBorder" DataContext="{Binding}">
|
||||||
|
|
||||||
<Border.Style>
|
<Border.Style>
|
||||||
<Style TargetType="Border">
|
<Style TargetType="Border">
|
||||||
<!--默认无边框-->
|
<!--默认无边框-->
|
||||||
<Setter Property="BorderBrush" Value="Transparent" />
|
<Setter Property="BorderBrush" Value="Transparent" />
|
||||||
<Setter Property="BorderThickness" Value="0" />
|
<Setter Property="BorderThickness" Value="0" />
|
||||||
<Style.Triggers>
|
<Style.Triggers>
|
||||||
<DataTrigger Binding="{Binding Path=NodeModel.DebugSetting.IsInterrupt}" Value="True">
|
<!--NodeModel.DebugSetting.IsInterrupt-->
|
||||||
|
<!--<DataTrigger Binding="{Binding DataContext.NodeModel.DebugSetting.IsInterrup, RelativeSource={RelativeSource AncestorType=UserControl}}" Value="True">-->
|
||||||
|
<DataTrigger Binding="{Binding IsInterrupt,Mode=OneTime}" Value="True">
|
||||||
|
<!--<DataTrigger Binding="{Binding NodeModel.DebugSetting.IsInterrup}" Value="True">-->
|
||||||
<Setter Property="BorderBrush" Value="Red" />
|
<Setter Property="BorderBrush" Value="Red" />
|
||||||
<Setter Property="BorderThickness" Value="2" />
|
<Setter Property="BorderThickness" Value="2" />
|
||||||
<Setter Property="Background" Value="#80000000" />
|
<Setter Property="Background" Value="#80000000" />
|
||||||
@@ -53,8 +55,8 @@
|
|||||||
<RowDefinition Height="*"/>
|
<RowDefinition Height="*"/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<!--<Grid Grid.Row="0" Background="#8DE9FD" >-->
|
<Grid Grid.Row="0" Background="#8DE9FD" >
|
||||||
<Grid Grid.Row="0" >
|
<!--<Grid Grid.Row="0" >-->
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="3*"/>
|
<RowDefinition Height="3*"/>
|
||||||
<RowDefinition/>
|
<RowDefinition/>
|
||||||
@@ -64,6 +66,7 @@
|
|||||||
<ColumnDefinition Width="*"/>
|
<ColumnDefinition Width="*"/>
|
||||||
<ColumnDefinition Width="auto"/>
|
<ColumnDefinition Width="auto"/>
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
<local:ExecuteJunctionControl Grid.Column="0" MyNode="{Binding NodeModel}" x:Name="ExecuteJunctionControl" HorizontalAlignment="Left" Grid.RowSpan="2"/>
|
<local:ExecuteJunctionControl Grid.Column="0" MyNode="{Binding NodeModel}" x:Name="ExecuteJunctionControl" HorizontalAlignment="Left" Grid.RowSpan="2"/>
|
||||||
<StackPanel Grid.Column="1" Grid.RowSpan="2" >
|
<StackPanel Grid.Column="1" Grid.RowSpan="2" >
|
||||||
<TextBlock Text="{Binding NodeModel.MethodDetails.MethodTips, Mode=TwoWay}" HorizontalAlignment="Center"/>
|
<TextBlock Text="{Binding NodeModel.MethodDetails.MethodTips, Mode=TwoWay}" HorizontalAlignment="Center"/>
|
||||||
@@ -105,6 +108,7 @@
|
|||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="*"/>
|
<RowDefinition Height="*"/>
|
||||||
<RowDefinition Height="*"/>
|
<RowDefinition Height="*"/>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="auto"/>
|
<ColumnDefinition Width="auto"/>
|
||||||
@@ -114,6 +118,8 @@
|
|||||||
<TextBlock Grid.Row="0" Grid.Column="1" Text="是否使能" HorizontalAlignment="Left" VerticalAlignment="Center"/>
|
<TextBlock Grid.Row="0" Grid.Column="1" Text="是否使能" HorizontalAlignment="Left" VerticalAlignment="Center"/>
|
||||||
<CheckBox Grid.Row="1" Grid.Column="0" IsChecked="{Binding NodeModel.MethodDetails.IsProtectionParameter, Mode=TwoWay}"/>
|
<CheckBox Grid.Row="1" Grid.Column="0" IsChecked="{Binding NodeModel.MethodDetails.IsProtectionParameter, Mode=TwoWay}"/>
|
||||||
<TextBlock Grid.Row="1" Grid.Column="1" Text="参数保护" HorizontalAlignment="Left" VerticalAlignment="Center"/>
|
<TextBlock Grid.Row="1" Grid.Column="1" Text="参数保护" HorizontalAlignment="Left" VerticalAlignment="Center"/>
|
||||||
|
<CheckBox Grid.Row="2" Grid.Column="0" IsChecked="{Binding NodeModel.DebugSetting.IsInterrupt, Mode=TwoWay}"/>
|
||||||
|
<TextBlock Grid.Row="2" Grid.Column="1" Text="中断节点" HorizontalAlignment="Left" VerticalAlignment="Center"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
<Compile Remove="Node\FlipflopRegionControl.xaml.cs" />
|
<Compile Remove="Node\FlipflopRegionControl.xaml.cs" />
|
||||||
<Compile Remove="Node\Junction\NodeJunctionViewBase.cs" />
|
<Compile Remove="Node\Junction\NodeJunctionViewBase.cs" />
|
||||||
<Compile Remove="Node\NodeBase.cs" />
|
<Compile Remove="Node\NodeBase.cs" />
|
||||||
|
<Compile Remove="Node\View\ActionRegionControl.xaml.cs" />
|
||||||
<Compile Remove="Themes\ConditionControl.xaml.cs" />
|
<Compile Remove="Themes\ConditionControl.xaml.cs" />
|
||||||
<Compile Remove="Themes\ConditionControlModel.cs" />
|
<Compile Remove="Themes\ConditionControlModel.cs" />
|
||||||
<Compile Remove="Themes\ConnectionControl.xaml.cs" />
|
<Compile Remove="Themes\ConnectionControl.xaml.cs" />
|
||||||
@@ -36,6 +37,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Page Remove="Node\FlipflopRegionControl.xaml" />
|
<Page Remove="Node\FlipflopRegionControl.xaml" />
|
||||||
|
<Page Remove="Node\View\ActionRegionControl.xaml" />
|
||||||
<Page Remove="Themes\ConditionControl.xaml" />
|
<Page Remove="Themes\ConditionControl.xaml" />
|
||||||
<Page Remove="Themes\ConnectionControl.xaml" />
|
<Page Remove="Themes\ConnectionControl.xaml" />
|
||||||
<Page Remove="Themes\ExplicitDataControl.xaml" />
|
<Page Remove="Themes\ExplicitDataControl.xaml" />
|
||||||
|
|||||||
@@ -16,7 +16,13 @@
|
|||||||
<ItemsControl ItemsSource="{Binding MethodDetails.ParameterDetailss, RelativeSource={RelativeSource TemplatedParent}}">
|
<ItemsControl ItemsSource="{Binding MethodDetails.ParameterDetailss, RelativeSource={RelativeSource TemplatedParent}}">
|
||||||
<ItemsControl.ItemTemplate>
|
<ItemsControl.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<ContentControl Content="{Binding}">
|
<Grid Background="#E3FDFD" >
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="auto"/>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<view:ArgJunctionControl x:Name="ArgJunctionControl" Grid.Column="0" ArgIndex="{Binding Index}" MyNode="{Binding NodeModel}" />
|
||||||
|
<ContentControl Content="{Binding}" Grid.Column="1">
|
||||||
<ContentControl.Style>
|
<ContentControl.Style>
|
||||||
<Style TargetType="ContentControl">
|
<Style TargetType="ContentControl">
|
||||||
<Style.Triggers>
|
<Style.Triggers>
|
||||||
@@ -27,10 +33,8 @@
|
|||||||
</MultiDataTrigger.Conditions>
|
</MultiDataTrigger.Conditions>
|
||||||
<Setter Property="ContentTemplate">
|
<Setter Property="ContentTemplate">
|
||||||
<Setter.Value>
|
<Setter.Value>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<StackPanel Orientation="Horizontal">
|
<Grid>
|
||||||
<view:ArgJunctionControl x:Name="ArgJunctionControl" Grid.Column="0" ArgIndex="{Binding Index}" MyNode="{Binding NodeModel}" />
|
|
||||||
<Grid Background="#E3FDFD">
|
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="50"/>
|
<ColumnDefinition Width="50"/>
|
||||||
<ColumnDefinition Width="30"/>
|
<ColumnDefinition Width="30"/>
|
||||||
@@ -42,7 +46,7 @@
|
|||||||
<TextBlock Grid.Column="2" MinWidth="50" Text="{Binding Name}" HorizontalAlignment="Left" VerticalAlignment="Center"/>
|
<TextBlock Grid.Column="2" MinWidth="50" Text="{Binding Name}" HorizontalAlignment="Left" VerticalAlignment="Center"/>
|
||||||
<TextBlock Grid.Column="3" MinWidth="50" Text="无须指定参数"/>
|
<TextBlock Grid.Column="3" MinWidth="50" Text="无须指定参数"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
</StackPanel>
|
|
||||||
|
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</Setter.Value>
|
</Setter.Value>
|
||||||
@@ -59,8 +63,8 @@
|
|||||||
<Setter.Value>
|
<Setter.Value>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<view:ArgJunctionControl x:Name="ArgJunctionControl" Grid.Column="0" ArgIndex="{Binding Index}" MyNode="{Binding NodeModel}" />
|
<!--<view:ArgJunctionControl x:Name="ArgJunctionControl" Grid.Column="0" ArgIndex="{Binding Index}" MyNode="{Binding NodeModel}" />-->
|
||||||
<Grid Background="#E3FDFD">
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="50"/>
|
<ColumnDefinition Width="50"/>
|
||||||
<ColumnDefinition Width="30"/>
|
<ColumnDefinition Width="30"/>
|
||||||
@@ -90,8 +94,8 @@
|
|||||||
<Setter.Value>
|
<Setter.Value>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<view:ArgJunctionControl x:Name="ArgJunctionControl" Grid.Column="0" ArgIndex="{Binding Index}" MyNode="{Binding NodeModel}" />
|
<!--<view:ArgJunctionControl x:Name="ArgJunctionControl" Grid.Column="0" ArgIndex="{Binding Index}" MyNode="{Binding NodeModel}" />-->
|
||||||
<Grid Background="#E3FDFD">
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="50"/>
|
<ColumnDefinition Width="50"/>
|
||||||
<ColumnDefinition Width="30"/>
|
<ColumnDefinition Width="30"/>
|
||||||
@@ -114,6 +118,7 @@
|
|||||||
</Style>
|
</Style>
|
||||||
</ContentControl.Style>
|
</ContentControl.Style>
|
||||||
</ContentControl>
|
</ContentControl>
|
||||||
|
</Grid>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ItemsControl.ItemTemplate>
|
</ItemsControl.ItemTemplate>
|
||||||
</ItemsControl>
|
</ItemsControl>
|
||||||
|
|||||||
53
Workbench/Extension/LineExtension.cs
Normal file
53
Workbench/Extension/LineExtension.cs
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
using Serein.Library;
|
||||||
|
using Serein.Workbench.Node.View;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Media;
|
||||||
|
|
||||||
|
namespace Serein.Workbench.Extension
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 线条颜色
|
||||||
|
/// </summary>
|
||||||
|
public static class LineExtension
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 根据连接类型指定颜色
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="currentConnectionType"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <exception cref="Exception"></exception>
|
||||||
|
public static SolidColorBrush ToLineColor(this ConnectionInvokeType currentConnectionType)
|
||||||
|
{
|
||||||
|
return currentConnectionType switch
|
||||||
|
{
|
||||||
|
ConnectionInvokeType.IsSucceed => new SolidColorBrush((Color)ColorConverter.ConvertFromString("#04FC10")), // 04FC10 & 027E08
|
||||||
|
ConnectionInvokeType.IsFail => new SolidColorBrush((Color)ColorConverter.ConvertFromString("#F18905")),
|
||||||
|
ConnectionInvokeType.IsError => new SolidColorBrush((Color)ColorConverter.ConvertFromString("#FE1343")),
|
||||||
|
ConnectionInvokeType.Upstream => new SolidColorBrush((Color)ColorConverter.ConvertFromString("#4A82E4")),
|
||||||
|
ConnectionInvokeType.None => new SolidColorBrush((Color)ColorConverter.ConvertFromString("#56CEF6")),
|
||||||
|
_ => throw new Exception(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 根据连接类型指定颜色
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="connection"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <exception cref="Exception"></exception>
|
||||||
|
public static SolidColorBrush ToLineColor(this ConnectionArgSourceType connection)
|
||||||
|
{
|
||||||
|
return connection switch
|
||||||
|
{
|
||||||
|
ConnectionArgSourceType.GetPreviousNodeData => new SolidColorBrush((Color)ColorConverter.ConvertFromString("#56CEF6")), // 04FC10 & 027E08
|
||||||
|
ConnectionArgSourceType.GetOtherNodeData => new SolidColorBrush((Color)ColorConverter.ConvertFromString("#56CEF6")),
|
||||||
|
ConnectionArgSourceType.GetOtherNodeDataOfInvoke => new SolidColorBrush((Color)ColorConverter.ConvertFromString("#B06BBB")),
|
||||||
|
_ => throw new Exception(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,10 +28,12 @@ namespace Serein.Workbench.Node.View
|
|||||||
Semicircle,
|
Semicircle,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 贝塞尔曲线
|
/// 贝塞尔曲线
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class BezierLine : Shape
|
public class ConnectionLineShape : Shape
|
||||||
{
|
{
|
||||||
private readonly double strokeThickness;
|
private readonly double strokeThickness;
|
||||||
|
|
||||||
@@ -40,28 +42,44 @@ namespace Serein.Workbench.Node.View
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 确定起始坐标和目标坐标、外光样式的曲线
|
/// 确定起始坐标和目标坐标、外光样式的曲线
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="start"></param>
|
/// <param name="lineType">线条类型</param>
|
||||||
/// <param name="end"></param>
|
/// <param name="start">起始坐标</param>
|
||||||
/// <param name="brush"></param>
|
/// <param name="end">结束坐标</param>
|
||||||
/// <param name="strokeThickness"></param>
|
/// <param name="brush">颜色</param>
|
||||||
public BezierLine(LineType lineType, Point start, Point end, Brush brush, double strokeThickness = 4)
|
/// <param name="isDotted">是否为虚线</param>
|
||||||
|
public ConnectionLineShape(LineType lineType,
|
||||||
|
Point start,
|
||||||
|
Point end,
|
||||||
|
Brush brush,
|
||||||
|
bool isDotted = false,
|
||||||
|
bool isTop = false)
|
||||||
{
|
{
|
||||||
this.lineType = lineType;
|
this.lineType = lineType;
|
||||||
this.brush = brush;
|
this.brush = brush;
|
||||||
startPoint = start;
|
startPoint = start;
|
||||||
endPoint = end;
|
endPoint = end;
|
||||||
this.strokeThickness = strokeThickness;
|
this.strokeThickness = 4;
|
||||||
InitElementPoint();
|
InitElementPoint(isDotted, isTop);
|
||||||
InvalidateVisual(); // 触发重绘
|
InvalidateVisual(); // 触发重绘
|
||||||
}
|
}
|
||||||
public void InitElementPoint()
|
public void InitElementPoint(bool isDotted , bool isTop = false)
|
||||||
{
|
{
|
||||||
hitVisiblePen = new Pen(Brushes.Transparent, 1.0); // 初始化碰撞检测线
|
hitVisiblePen = new Pen(Brushes.Transparent, 1.0); // 初始化碰撞检测线
|
||||||
hitVisiblePen.Freeze(); // Freeze以提高性能
|
hitVisiblePen.Freeze(); // Freeze以提高性能
|
||||||
visualPen = new Pen(brush, 3.0); // 默认可视化Pen
|
visualPen = new Pen(brush, 3.0); // 默认可视化Pen
|
||||||
|
if (isDotted)
|
||||||
|
{
|
||||||
|
visualPen.DashStyle = DashStyles.Dash; // 选择虚线样式
|
||||||
|
}
|
||||||
visualPen.Freeze(); // Freeze以提高性能
|
visualPen.Freeze(); // Freeze以提高性能
|
||||||
|
|
||||||
linkSize = 4; // 整线条粗细
|
linkSize = 4; // 整线条粗细
|
||||||
Panel.SetZIndex(this, -9999999); // 置底
|
int zIndex = -999999;
|
||||||
|
if (isTop)
|
||||||
|
{
|
||||||
|
zIndex *= -1;
|
||||||
|
}
|
||||||
|
Panel.SetZIndex(this, zIndex); // 置底
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -104,16 +122,17 @@ namespace Serein.Workbench.Node.View
|
|||||||
switch (this.lineType)
|
switch (this.lineType)
|
||||||
{
|
{
|
||||||
case LineType.Bezier:
|
case LineType.Bezier:
|
||||||
DrawBezierCurve(drawingContext, startPoint, endPoint, linkSize);
|
DrawBezierCurve(drawingContext, startPoint, endPoint);
|
||||||
break;
|
break;
|
||||||
case LineType.Semicircle:
|
case LineType.Semicircle:
|
||||||
DrawBezierCurve(drawingContext, startPoint, endPoint);
|
DrawSemicircleCurve(drawingContext, startPoint, endPoint);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
#region 重绘
|
||||||
|
|
||||||
private readonly StreamGeometry streamGeometry = new StreamGeometry();
|
private readonly StreamGeometry streamGeometry = new StreamGeometry();
|
||||||
private Point rightCenterOfStartLocation; // 目标节点选择左侧边缘中心
|
private Point rightCenterOfStartLocation; // 目标节点选择左侧边缘中心
|
||||||
@@ -125,8 +144,12 @@ namespace Serein.Workbench.Node.View
|
|||||||
private Brush brush; // 线条颜色
|
private Brush brush; // 线条颜色
|
||||||
double linkSize; // 根据缩放比例调整线条粗细
|
double linkSize; // 根据缩放比例调整线条粗细
|
||||||
protected override Geometry DefiningGeometry => streamGeometry;
|
protected override Geometry DefiningGeometry => streamGeometry;
|
||||||
|
|
||||||
#region 工具方法
|
public void UpdateLineColor(Brush brush)
|
||||||
|
{
|
||||||
|
visualPen = new Pen(brush, 3.0); // 默认可视化Pen
|
||||||
|
InvalidateVisual(); // 触发重绘
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private Point c0, c1; // 用于计算贝塞尔曲线控制点逻辑
|
private Point c0, c1; // 用于计算贝塞尔曲线控制点逻辑
|
||||||
@@ -134,15 +157,10 @@ namespace Serein.Workbench.Node.View
|
|||||||
private Vector startToEnd;
|
private Vector startToEnd;
|
||||||
private void DrawBezierCurve(DrawingContext drawingContext,
|
private void DrawBezierCurve(DrawingContext drawingContext,
|
||||||
Point start,
|
Point start,
|
||||||
Point end,
|
Point end)
|
||||||
double linkSize,
|
|
||||||
bool isHitTestVisible = false,
|
|
||||||
double strokeThickness = 1.0,
|
|
||||||
bool isMouseOver = false,
|
|
||||||
double dashOffset = 0.0)
|
|
||||||
{
|
{
|
||||||
// 控制点的计算逻辑
|
// 控制点的计算逻辑
|
||||||
double power = 100; // 控制贝塞尔曲线的“拉伸”强度
|
double power = 140; // 控制贝塞尔曲线的“拉伸”强度
|
||||||
|
|
||||||
// 计算轴向向量与起点到终点的向量
|
// 计算轴向向量与起点到终点的向量
|
||||||
//var axis = new Vector(1, 0);
|
//var axis = new Vector(1, 0);
|
||||||
@@ -165,31 +183,16 @@ namespace Serein.Workbench.Node.View
|
|||||||
context.BeginFigure(start, true, false); // 曲线起点
|
context.BeginFigure(start, true, false); // 曲线起点
|
||||||
context.BezierTo(c0, c1, end, true, false); // 画贝塞尔曲线
|
context.BezierTo(c0, c1, end, true, false); // 画贝塞尔曲线
|
||||||
}
|
}
|
||||||
|
|
||||||
drawingContext.DrawGeometry(null, visualPen, streamGeometry);
|
drawingContext.DrawGeometry(null, visualPen, streamGeometry);
|
||||||
|
|
||||||
// 绘制碰撞检测线
|
|
||||||
//if (true)
|
|
||||||
//{
|
|
||||||
// //hitVisiblePen = new Pen(Brushes.Transparent, linkSize + strokeThickness);
|
|
||||||
// //hitVisiblePen.Freeze();
|
|
||||||
// drawingContext.DrawGeometry(null, hitVisiblePen, streamGeometry);
|
|
||||||
//}
|
|
||||||
//else
|
|
||||||
//{
|
|
||||||
|
|
||||||
|
|
||||||
//}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
private void DrawBezierCurve(DrawingContext drawingContext, Point start, Point end)
|
private void DrawSemicircleCurve(DrawingContext drawingContext, Point start, Point end)
|
||||||
{
|
{
|
||||||
// 计算中心点和半径
|
// 计算中心点和半径
|
||||||
// 计算圆心和半径
|
// 计算圆心和半径
|
||||||
double x = 35 ;
|
double x = 35;
|
||||||
// 创建一个弧线路径
|
// 创建一个弧线路径
|
||||||
streamGeometry.Clear();
|
streamGeometry.Clear();
|
||||||
using (var context = streamGeometry.Open())
|
using (var context = streamGeometry.Open())
|
||||||
@@ -216,6 +219,7 @@ namespace Serein.Workbench.Node.View
|
|||||||
drawingContext.DrawGeometry(null, visualPen, streamGeometry);
|
drawingContext.DrawGeometry(null, visualPen, streamGeometry);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -4,6 +4,7 @@ using System;
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
using Serein.Workbench.Extension;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
@@ -16,18 +17,20 @@ namespace Serein.Workbench.Node.View
|
|||||||
|
|
||||||
public abstract class JunctionControlBase : Shape
|
public abstract class JunctionControlBase : Shape
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
protected JunctionControlBase()
|
protected JunctionControlBase()
|
||||||
{
|
{
|
||||||
this.Width = 25;
|
this.Width = 25;
|
||||||
this.Height = 20;
|
this.Height = 20;
|
||||||
this.MouseDown += ControlPointBase_MouseDown;
|
this.MouseDown += JunctionControlBase_MouseDown;
|
||||||
this.MouseMove += ControlPointBase_MouseMove;
|
this.MouseMove += JunctionControlBase_MouseMove;
|
||||||
|
this.MouseLeave += JunctionControlBase_MouseLeave; ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#region 控件属性,所在的节点
|
#region 控件属性,所在的节点
|
||||||
public static readonly DependencyProperty NodeProperty =
|
public static readonly DependencyProperty NodeProperty =
|
||||||
DependencyProperty.Register(nameof(MyNode), typeof(NodeModelBase), typeof(JunctionControlBase), new PropertyMetadata(default(NodeModelBase)));
|
DependencyProperty.Register(nameof(MyNode), typeof(NodeModelBase), typeof(JunctionControlBase), new PropertyMetadata(default(NodeModelBase)));
|
||||||
|
//public NodeModelBase NodeModel;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 所在的节点
|
/// 所在的节点
|
||||||
@@ -52,6 +55,7 @@ namespace Serein.Workbench.Node.View
|
|||||||
set { SetValue(JunctionTypeProperty, value.ToString()); }
|
set { SetValue(JunctionTypeProperty, value.ToString()); }
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
protected readonly StreamGeometry StreamGeometry = new StreamGeometry();
|
protected readonly StreamGeometry StreamGeometry = new StreamGeometry();
|
||||||
protected override Geometry DefiningGeometry => StreamGeometry;
|
protected override Geometry DefiningGeometry => StreamGeometry;
|
||||||
|
|
||||||
@@ -65,15 +69,29 @@ namespace Serein.Workbench.Node.View
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract Point MyCenterPoint { get; }
|
public abstract Point MyCenterPoint { get; }
|
||||||
|
|
||||||
// 处理鼠标悬停状态
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 禁止连接
|
||||||
|
/// </summary>
|
||||||
|
private bool IsConnectionDisable;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 处理鼠标悬停状态
|
||||||
|
/// </summary>
|
||||||
private bool _isMouseOver;
|
private bool _isMouseOver;
|
||||||
public bool IsMouseOver
|
public bool IsMouseOver
|
||||||
{
|
{
|
||||||
get => _isMouseOver;
|
get => _isMouseOver;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_isMouseOver = value;
|
if(_isMouseOver != value)
|
||||||
InvalidateVisual();
|
{
|
||||||
|
GlobalJunctionData.MyGlobalConnectingData.CurrentJunction = this;
|
||||||
|
_isMouseOver = value;
|
||||||
|
InvalidateVisual();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,13 +104,63 @@ namespace Serein.Workbench.Node.View
|
|||||||
Render(drawingContext);
|
Render(drawingContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
protected void ControlPointBase_MouseMove(object sender, MouseEventArgs e)
|
/// 获取背景颜色
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
protected Brush GetBackgrounp()
|
||||||
{
|
{
|
||||||
if (GlobalJunctionData.MyGlobalConnectingData is null) return;
|
var myData = GlobalJunctionData.MyGlobalConnectingData;
|
||||||
GlobalJunctionData.MyGlobalConnectingData.CurrentJunction = this;
|
if(!myData.IsCreateing)
|
||||||
|
{
|
||||||
|
return Brushes.Transparent;
|
||||||
|
}
|
||||||
|
if (IsMouseOver)
|
||||||
|
{
|
||||||
|
if (myData.IsCanConnected)
|
||||||
|
{
|
||||||
|
if (myData.Type == JunctionOfConnectionType.Invoke)
|
||||||
|
{
|
||||||
|
return myData.ConnectionInvokeType.ToLineColor();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return myData.ConnectionArgSourceType.ToLineColor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Brushes.Red;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Brushes.Transparent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private object lockObj = new object();
|
||||||
|
|
||||||
|
// 控件获得鼠标焦点事件
|
||||||
|
private void JunctionControlBase_MouseMove(object sender, MouseEventArgs e)
|
||||||
|
{
|
||||||
|
//if (!GlobalJunctionData.MyGlobalConnectingData.IsCreateing) return;
|
||||||
|
|
||||||
|
//if (IsMouseOver) return;
|
||||||
|
IsMouseOver = true;
|
||||||
|
|
||||||
|
//this.InvalidateVisual();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
// 控件失去鼠标焦点事件
|
||||||
|
private void JunctionControlBase_MouseLeave(object sender, MouseEventArgs e)
|
||||||
|
{
|
||||||
|
IsMouseOver = false;
|
||||||
|
e.Handled = true;
|
||||||
|
//Console.WriteLine("控件失去鼠标焦点");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -100,20 +168,43 @@ namespace Serein.Workbench.Node.View
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="sender"></param>
|
/// <param name="sender"></param>
|
||||||
/// <param name="e"></param>
|
/// <param name="e"></param>
|
||||||
protected void ControlPointBase_MouseDown(object sender, MouseButtonEventArgs e)
|
protected void JunctionControlBase_MouseDown(object sender, MouseButtonEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.LeftButton == MouseButtonState.Pressed)
|
if (e.LeftButton == MouseButtonState.Pressed)
|
||||||
{
|
{
|
||||||
GlobalJunctionData.MyGlobalConnectingData = new ConnectingData();
|
|
||||||
var myDataType = GlobalJunctionData.MyGlobalConnectingData;
|
|
||||||
myDataType.StartJunction = this;
|
|
||||||
var canvas = MainWindow.GetParentOfType<Canvas>(this);
|
var canvas = MainWindow.GetParentOfType<Canvas>(this);
|
||||||
if (canvas != null)
|
if (canvas != null)
|
||||||
{
|
{
|
||||||
//myDataType.StartPoint = this.MyCenterPoint;
|
var myData = GlobalJunctionData.MyGlobalConnectingData;
|
||||||
myDataType.StartPoint = this.TranslatePoint(new Point(this.Width / 2, this.Height / 2), canvas);
|
myData.Reset();
|
||||||
var bezierLine = new BezierLine(LineType.Bezier, myDataType.StartPoint, myDataType.StartPoint, Brushes.Green);
|
myData.IsCreateing = true; // 表示开始连接
|
||||||
myDataType.VirtualLine = new MyLine(canvas, bezierLine);
|
myData.StartJunction = this;
|
||||||
|
myData.CurrentJunction = this;
|
||||||
|
myData.StartPoint = this.TranslatePoint(new Point(this.Width / 2, this.Height / 2), canvas);
|
||||||
|
|
||||||
|
var junctionOfConnectionType = this.JunctionType.ToConnectyionType();
|
||||||
|
ConnectionLineShape bezierLine; // 类别
|
||||||
|
Brush brushColor; // 临时线的颜色
|
||||||
|
if (junctionOfConnectionType == JunctionOfConnectionType.Invoke)
|
||||||
|
{
|
||||||
|
brushColor = ConnectionInvokeType.IsSucceed.ToLineColor();
|
||||||
|
}
|
||||||
|
else if(junctionOfConnectionType == JunctionOfConnectionType.Arg)
|
||||||
|
{
|
||||||
|
brushColor = ConnectionArgSourceType.GetOtherNodeData.ToLineColor();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bezierLine = new ConnectionLineShape(LineType.Bezier,
|
||||||
|
myData.StartPoint,
|
||||||
|
myData.StartPoint,
|
||||||
|
brushColor,
|
||||||
|
isTop: true); // 绘制临时的线
|
||||||
|
|
||||||
|
Mouse.OverrideCursor = Cursors.Cross; // 设置鼠标为正在创建连线
|
||||||
|
myData.MyLine = new MyLine(canvas, bezierLine);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
@@ -123,6 +214,11 @@ namespace Serein.Workbench.Node.View
|
|||||||
{
|
{
|
||||||
return new Point(this.ActualWidth / 2, this.ActualHeight / 2); // 起始节点选择右侧边缘中心
|
return new Point(this.ActualWidth / 2, this.ActualHeight / 2); // 起始节点选择右侧边缘中心
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
using System;
|
using Serein.Library;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
@@ -13,28 +16,60 @@ namespace Serein.Workbench.Node.View
|
|||||||
#region Model,不科学的全局变量
|
#region Model,不科学的全局变量
|
||||||
public class MyLine
|
public class MyLine
|
||||||
{
|
{
|
||||||
public MyLine(Canvas canvas, BezierLine line)
|
public MyLine(Canvas canvas, ConnectionLineShape line)
|
||||||
{
|
{
|
||||||
Canvas = canvas;
|
Canvas = canvas;
|
||||||
VirtualLine = line;
|
Line = line;
|
||||||
canvas?.Children.Add(line);
|
canvas?.Children.Add(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Canvas Canvas { get; set; }
|
public Canvas Canvas { get; set; }
|
||||||
public BezierLine VirtualLine { get; set; }
|
public ConnectionLineShape Line { get; set; }
|
||||||
|
|
||||||
public void Remove()
|
public void Remove()
|
||||||
{
|
{
|
||||||
Canvas?.Children.Remove(VirtualLine);
|
Canvas?.Children.Remove(Line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ConnectingData
|
public class ConnectingData
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否正在创建连线
|
||||||
|
/// </summary>
|
||||||
|
public bool IsCreateing { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 起始控制点
|
||||||
|
/// </summary>
|
||||||
public JunctionControlBase StartJunction { get; set; }
|
public JunctionControlBase StartJunction { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 当前的控制点
|
||||||
|
/// </summary>
|
||||||
public JunctionControlBase CurrentJunction { get; set; }
|
public JunctionControlBase CurrentJunction { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 开始坐标
|
||||||
|
/// </summary>
|
||||||
public Point StartPoint { get; set; }
|
public Point StartPoint { get; set; }
|
||||||
public MyLine VirtualLine { get; set; }
|
/// <summary>
|
||||||
|
/// 线条样式
|
||||||
|
/// </summary>
|
||||||
|
public MyLine MyLine { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 线条类别(方法调用)
|
||||||
|
/// </summary>
|
||||||
|
public ConnectionInvokeType ConnectionInvokeType { get; set; } = ConnectionInvokeType.IsSucceed;
|
||||||
|
/// <summary>
|
||||||
|
/// 线条类别(参数传递)
|
||||||
|
/// </summary>
|
||||||
|
public ConnectionArgSourceType ConnectionArgSourceType { get; set; } = ConnectionArgSourceType.GetOtherNodeData;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 判断当前连接类型
|
||||||
|
/// </summary>
|
||||||
|
public JunctionOfConnectionType Type => StartJunction.JunctionType.ToConnectyionType();
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否允许连接
|
/// 是否允许连接
|
||||||
@@ -42,32 +77,22 @@ namespace Serein.Workbench.Node.View
|
|||||||
|
|
||||||
public bool IsCanConnected { get
|
public bool IsCanConnected { get
|
||||||
{
|
{
|
||||||
|
|
||||||
if(StartJunction is null
|
if(StartJunction is null
|
||||||
|| CurrentJunction is null
|
|| CurrentJunction is null
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!StartPoint.Equals(CurrentJunction))
|
|
||||||
|
|
||||||
|
if (!StartJunction.MyNode.Equals(CurrentJunction.MyNode)
|
||||||
|
&& StartJunction.JunctionType.IsCanConnection(CurrentJunction.JunctionType))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// 自己连接自己的情况下,只能是从arg控制点连接到execute控制点。
|
|
||||||
if (CurrentJunction.JunctionType == Library.JunctionType.Execute
|
|
||||||
&& StartJunction.JunctionType == Library.JunctionType.ArgData)
|
|
||||||
{
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CurrentJunction.JunctionType == Library.JunctionType.ArgData
|
|
||||||
&& StartJunction.JunctionType == Library.JunctionType.Execute)
|
|
||||||
{
|
|
||||||
// 需要是自己连接自己,且只能是从arg控制点连接到execute控制点。
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -88,46 +113,48 @@ namespace Serein.Workbench.Node.View
|
|||||||
if (StartJunction.JunctionType == Library.JunctionType.Execute
|
if (StartJunction.JunctionType == Library.JunctionType.Execute
|
||||||
|| StartJunction.JunctionType == Library.JunctionType.ArgData)
|
|| StartJunction.JunctionType == Library.JunctionType.ArgData)
|
||||||
{
|
{
|
||||||
VirtualLine.VirtualLine.UpdateStartPoints(point);
|
MyLine.Line.UpdateStartPoints(point);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
VirtualLine.VirtualLine.UpdateEndPoints(point);
|
MyLine.Line.UpdateEndPoints(point);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 重置
|
||||||
|
/// </summary>
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
IsCreateing = false;
|
||||||
|
StartJunction = null;
|
||||||
|
CurrentJunction = null;
|
||||||
|
MyLine?.Remove();
|
||||||
|
ConnectionInvokeType = ConnectionInvokeType.IsSucceed;
|
||||||
|
ConnectionArgSourceType = ConnectionArgSourceType.GetOtherNodeData;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class GlobalJunctionData
|
public static class GlobalJunctionData
|
||||||
{
|
{
|
||||||
private static ConnectingData? myGlobalData;
|
//private static ConnectingData? myGlobalData;
|
||||||
private static object _lockObj = new object();
|
//private static object _lockObj = new object();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建节点之间控制点的连接行为
|
/// 创建节点之间控制点的连接行为
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static ConnectingData? MyGlobalConnectingData
|
public static ConnectingData MyGlobalConnectingData { get; } = new ConnectingData();
|
||||||
{
|
|
||||||
get => myGlobalData;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
lock (_lockObj)
|
|
||||||
{
|
|
||||||
myGlobalData ??= value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 删除连接视觉效果
|
/// 删除连接视觉效果
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static void OK()
|
public static void OK()
|
||||||
{
|
{
|
||||||
myGlobalData?.VirtualLine.Remove();
|
MyGlobalConnectingData.Reset();
|
||||||
myGlobalData = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@@ -30,29 +30,27 @@ namespace Serein.Workbench.Node.View
|
|||||||
#endregion
|
#endregion
|
||||||
private Point _myCenterPoint;
|
private Point _myCenterPoint;
|
||||||
public override Point MyCenterPoint { get => _myCenterPoint; }
|
public override Point MyCenterPoint { get => _myCenterPoint; }
|
||||||
|
|
||||||
|
|
||||||
public override void Render(DrawingContext drawingContext)
|
public override void Render(DrawingContext drawingContext)
|
||||||
{
|
{
|
||||||
double width = ActualWidth;
|
double width = ActualWidth;
|
||||||
double height = ActualHeight;
|
double height = ActualHeight;
|
||||||
|
var background = GetBackgrounp();
|
||||||
// 输入连接器的背景
|
// 输入连接器的背景
|
||||||
var connectorBackground = IsMouseOver ? Brushes.DarkCyan : Brushes.Transparent;
|
var connectorRect = new Rect(0, 0, width, height);
|
||||||
var connectorRect = new Rect(4, 4, width - 8, height - 8);
|
drawingContext.DrawRectangle(Brushes.Transparent, null, connectorRect);
|
||||||
drawingContext.DrawRectangle(connectorBackground, null, connectorRect);
|
|
||||||
|
|
||||||
// 定义圆形的大小和位置
|
// 定义圆形的大小和位置
|
||||||
double connectorSize = 10; // 连接器的大小
|
double connectorSize = 10; // 连接器的大小
|
||||||
double circleCenterX = 8; // 圆心 X 坐标
|
double circleCenterX = 8; // 圆心 X 坐标
|
||||||
double circleCenterY = height / 2; // 圆心 Y 坐标
|
double circleCenterY = height / 2; // 圆心 Y 坐标
|
||||||
var circlePoint = new Point(circleCenterX, circleCenterY);
|
var circlePoint = new Point(circleCenterX, circleCenterY);
|
||||||
|
_myCenterPoint = new Point(circleCenterX - connectorSize / 2, circleCenterY); // 中心坐标
|
||||||
|
|
||||||
// 绘制连接器的圆形部分
|
// 绘制连接器的圆形部分
|
||||||
var ellipse = new EllipseGeometry(circlePoint, connectorSize / 2, connectorSize / 2);
|
var ellipse = new EllipseGeometry(circlePoint, connectorSize / 2, connectorSize / 2);
|
||||||
_myCenterPoint = new Point(circleCenterX - connectorSize / 2, circleCenterY);
|
drawingContext.DrawGeometry(background, new Pen(Brushes.Black, 1), ellipse);
|
||||||
drawingContext.DrawGeometry(IsMouseOver ? Brushes.DarkCyan : Brushes.Transparent, new Pen(Brushes.Black, 1), ellipse);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 定义三角形的间距
|
// 定义三角形的间距
|
||||||
double triangleOffsetX = 4; // 三角形与圆形的间距
|
double triangleOffsetX = 4; // 三角形与圆形的间距
|
||||||
@@ -68,7 +66,7 @@ namespace Serein.Workbench.Node.View
|
|||||||
context.LineTo(new Point(triangleCenterX, triangleCenterY + 4.5), true, false);
|
context.LineTo(new Point(triangleCenterX, triangleCenterY + 4.5), true, false);
|
||||||
context.LineTo(new Point(triangleCenterX, triangleCenterY - 4.5), true, false);
|
context.LineTo(new Point(triangleCenterX, triangleCenterY - 4.5), true, false);
|
||||||
}
|
}
|
||||||
drawingContext.DrawGeometry(IsMouseOver ? Brushes.DarkCyan : Brushes.Transparent, new Pen(Brushes.Black, 1), pathGeometry);
|
drawingContext.DrawGeometry(background, new Pen(Brushes.Black, 1), pathGeometry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ namespace Serein.Workbench.Node.View
|
|||||||
{
|
{
|
||||||
double width = ActualWidth;
|
double width = ActualWidth;
|
||||||
double height = ActualHeight;
|
double height = ActualHeight;
|
||||||
|
var background = GetBackgrounp();
|
||||||
// 绘制边框
|
// 绘制边框
|
||||||
//var borderBrush = new SolidColorBrush(Colors.Black);
|
//var borderBrush = new SolidColorBrush(Colors.Black);
|
||||||
//var borderThickness = 1.0;
|
//var borderThickness = 1.0;
|
||||||
@@ -31,22 +31,22 @@ namespace Serein.Workbench.Node.View
|
|||||||
//drawingContext.DrawRectangle(null, new Pen(borderBrush, borderThickness), borderRect);
|
//drawingContext.DrawRectangle(null, new Pen(borderBrush, borderThickness), borderRect);
|
||||||
|
|
||||||
// 输入连接器的背景
|
// 输入连接器的背景
|
||||||
var connectorBackground = IsMouseOver ? Brushes.DarkCyan : Brushes.Transparent;
|
var connectorRect = new Rect(0, 0, width, height);
|
||||||
var connectorRect = new Rect(4, 4, width - 8, height - 8);
|
drawingContext.DrawRectangle(Brushes.Transparent,null, connectorRect);
|
||||||
drawingContext.DrawRectangle(connectorBackground, null, connectorRect);
|
//drawingContext.DrawRectangle(Brushes.Transparent, new Pen(background,2), connectorRect);
|
||||||
|
|
||||||
// 定义圆形的大小和位置
|
// 定义圆形的大小和位置
|
||||||
double connectorSize = 10; // 连接器的大小
|
double connectorSize = 10; // 连接器的大小
|
||||||
double circleCenterX = 8; // 圆心 X 坐标
|
double circleCenterX = 8; // 圆心 X 坐标
|
||||||
double circleCenterY = height / 2; // 圆心 Y 坐标
|
double circleCenterY = height / 2; // 圆心 Y 坐标
|
||||||
|
_myCenterPoint = new Point(circleCenterX - connectorSize / 2, circleCenterY); // 中心坐标
|
||||||
|
|
||||||
var circlePoint = new Point(circleCenterX, circleCenterY);
|
var circlePoint = new Point(circleCenterX, circleCenterY);
|
||||||
// 绘制连接器的圆形部分
|
// 绘制连接器的圆形部分
|
||||||
var ellipse = new EllipseGeometry(circlePoint, connectorSize / 2, connectorSize / 2);
|
var ellipse = new EllipseGeometry(circlePoint, connectorSize / 2, connectorSize / 2);
|
||||||
_myCenterPoint = new Point(circleCenterX - connectorSize / 2, circleCenterY);
|
|
||||||
|
|
||||||
|
|
||||||
drawingContext.DrawGeometry(IsMouseOver ? Brushes.DarkCyan : Brushes.Transparent, new Pen(Brushes.Black, 1), ellipse);
|
drawingContext.DrawGeometry(background, new Pen(Brushes.Black, 1), ellipse);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ namespace Serein.Workbench.Node.View
|
|||||||
context.LineTo(new Point(triangleCenterX, triangleCenterY + 4.5), true, false);
|
context.LineTo(new Point(triangleCenterX, triangleCenterY + 4.5), true, false);
|
||||||
context.LineTo(new Point(triangleCenterX, triangleCenterY - 4.5), true, false);
|
context.LineTo(new Point(triangleCenterX, triangleCenterY - 4.5), true, false);
|
||||||
}
|
}
|
||||||
drawingContext.DrawGeometry(IsMouseOver ? Brushes.DarkCyan : Brushes.Transparent, new Pen(Brushes.Black, 1), pathGeometry);
|
drawingContext.DrawGeometry(background, new Pen(Brushes.Black, 1), pathGeometry);
|
||||||
|
|
||||||
// 绘制标签
|
// 绘制标签
|
||||||
//var formattedText = new FormattedText(
|
//var formattedText = new FormattedText(
|
||||||
|
|||||||
@@ -20,26 +20,25 @@ namespace Serein.Workbench.Node.View
|
|||||||
{
|
{
|
||||||
double width = ActualWidth;
|
double width = ActualWidth;
|
||||||
double height = ActualHeight;
|
double height = ActualHeight;
|
||||||
|
var background = GetBackgrounp();
|
||||||
// 输入连接器的背景
|
// 输入连接器的背景
|
||||||
var connectorBackground = IsMouseOver ? Brushes.DarkCyan : Brushes.Transparent;
|
var connectorRect = new Rect(0, 0, width, height);
|
||||||
var connectorRect = new Rect(4, 4, width - 8, height - 8);
|
drawingContext.DrawRectangle(Brushes.Transparent, null, connectorRect);
|
||||||
drawingContext.DrawRectangle(connectorBackground, null, connectorRect);
|
|
||||||
|
|
||||||
// 定义圆形的大小和位置
|
// 定义圆形的大小和位置
|
||||||
double connectorSize = 10; // 连接器的大小
|
double connectorSize = 10; // 连接器的大小
|
||||||
double circleCenterX = 8; // 圆心 X 坐标
|
double circleCenterX = 8; // 圆心 X 坐标
|
||||||
double circleCenterY = height / 2; // 圆心 Y 坐标
|
double circleCenterY = height / 2; // 圆心 Y 坐标
|
||||||
|
_myCenterPoint = new Point(circleCenterX - connectorSize / 2, circleCenterY); // 中心坐标
|
||||||
|
|
||||||
var circlePoint = new Point(circleCenterX, circleCenterY);
|
var circlePoint = new Point(circleCenterX, circleCenterY);
|
||||||
// 绘制连接器的圆形部分
|
// 绘制连接器的圆形部分
|
||||||
var ellipse = new EllipseGeometry(circlePoint, connectorSize / 2, connectorSize / 2);
|
var ellipse = new EllipseGeometry(circlePoint, connectorSize / 2, connectorSize / 2);
|
||||||
drawingContext.DrawGeometry(IsMouseOver ? Brushes.DarkCyan : Brushes.Transparent, new Pen(Brushes.Black, 1), ellipse);
|
drawingContext.DrawGeometry(background, new Pen(Brushes.Black, 1), ellipse);
|
||||||
_myCenterPoint = new Point(circleCenterX + connectorSize / 2, circleCenterY);
|
|
||||||
|
|
||||||
// 绘制连接器的圆形部分
|
// 绘制连接器的圆形部分
|
||||||
//var ellipse = new EllipseGeometry(circlePoint, connectorSize / 2, connectorSize / 2);
|
//var ellipse = new EllipseGeometry(circlePoint, connectorSize / 2, connectorSize / 2);
|
||||||
|
|
||||||
|
|
||||||
// 定义三角形的间距
|
// 定义三角形的间距
|
||||||
double triangleOffsetX = 4; // 三角形与圆形的间距
|
double triangleOffsetX = 4; // 三角形与圆形的间距
|
||||||
@@ -55,7 +54,7 @@ namespace Serein.Workbench.Node.View
|
|||||||
context.LineTo(new Point(triangleCenterX, triangleCenterY + 4.5), true, false);
|
context.LineTo(new Point(triangleCenterX, triangleCenterY + 4.5), true, false);
|
||||||
context.LineTo(new Point(triangleCenterX, triangleCenterY - 4.5), true, false);
|
context.LineTo(new Point(triangleCenterX, triangleCenterY - 4.5), true, false);
|
||||||
}
|
}
|
||||||
drawingContext.DrawGeometry(IsMouseOver ? Brushes.DarkCyan : Brushes.Transparent, new Pen(Brushes.Black, 1), pathGeometry);
|
drawingContext.DrawGeometry(background, new Pen(Brushes.Black, 1), pathGeometry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,9 +24,10 @@ namespace Serein.Workbench.Node.View
|
|||||||
double height = ActualHeight;
|
double height = ActualHeight;
|
||||||
|
|
||||||
// 输入连接器的背景
|
// 输入连接器的背景
|
||||||
var connectorBackground = IsMouseOver ? Brushes.DarkCyan : Brushes.Transparent;
|
var connectorRect = new Rect(0, 0, width, height);
|
||||||
var connectorRect = new Rect(4, 4, width - 8, height - 8);
|
drawingContext.DrawRectangle(Brushes.Transparent, null, connectorRect);
|
||||||
drawingContext.DrawRectangle(connectorBackground, null, connectorRect);
|
|
||||||
|
var background = GetBackgrounp();
|
||||||
|
|
||||||
// 定义圆形的大小和位置
|
// 定义圆形的大小和位置
|
||||||
double connectorSize = 10; // 连接器的大小
|
double connectorSize = 10; // 连接器的大小
|
||||||
@@ -34,10 +35,11 @@ namespace Serein.Workbench.Node.View
|
|||||||
double circleCenterY = height / 2; // 圆心 Y 坐标
|
double circleCenterY = height / 2; // 圆心 Y 坐标
|
||||||
var circlePoint = new Point(circleCenterX, circleCenterY);
|
var circlePoint = new Point(circleCenterX, circleCenterY);
|
||||||
|
|
||||||
|
_myCenterPoint = new Point(circleCenterX - connectorSize / 2 , circleCenterY); // 中心坐标
|
||||||
|
|
||||||
// 绘制连接器的圆形部分
|
// 绘制连接器的圆形部分
|
||||||
var ellipse = new EllipseGeometry(circlePoint, connectorSize / 2, connectorSize / 2);
|
var ellipse = new EllipseGeometry(circlePoint, connectorSize / 2, connectorSize / 2);
|
||||||
_myCenterPoint = new Point(circleCenterX - connectorSize / 2, circleCenterY);
|
drawingContext.DrawGeometry(background, new Pen(Brushes.Black, 1), ellipse);
|
||||||
drawingContext.DrawGeometry(IsMouseOver ? Brushes.DarkCyan : Brushes.Transparent, new Pen(Brushes.Black, 1), ellipse);
|
|
||||||
|
|
||||||
// 定义三角形的间距
|
// 定义三角形的间距
|
||||||
double triangleOffsetX = 4; // 三角形与圆形的间距
|
double triangleOffsetX = 4; // 三角形与圆形的间距
|
||||||
@@ -53,7 +55,7 @@ namespace Serein.Workbench.Node.View
|
|||||||
context.LineTo(new Point(triangleCenterX, triangleCenterY + 4.5), true, false);
|
context.LineTo(new Point(triangleCenterX, triangleCenterY + 4.5), true, false);
|
||||||
context.LineTo(new Point(triangleCenterX, triangleCenterY - 4.5), true, false);
|
context.LineTo(new Point(triangleCenterX, triangleCenterY - 4.5), true, false);
|
||||||
}
|
}
|
||||||
drawingContext.DrawGeometry(IsMouseOver ? Brushes.DarkCyan : Brushes.Transparent, new Pen(Brushes.Black, 1), pathGeometry);
|
drawingContext.DrawGeometry(background, new Pen(Brushes.Black, 1), pathGeometry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -112,52 +112,6 @@ namespace Serein.Workbench.Node.View
|
|||||||
|
|
||||||
private readonly Action RemoteCallback;
|
private readonly Action RemoteCallback;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 关于调用
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="Canvas"></param>
|
|
||||||
/// <param name="Type"></param>
|
|
||||||
public ConnectionControl(Canvas Canvas,
|
|
||||||
ConnectionInvokeType Type,
|
|
||||||
JunctionControlBase Start,
|
|
||||||
JunctionControlBase End,
|
|
||||||
Action remoteCallback)
|
|
||||||
{
|
|
||||||
this.LineType = LineType.Bezier;
|
|
||||||
this.RemoteCallback = remoteCallback;
|
|
||||||
this.Canvas = Canvas;
|
|
||||||
this.Type = Type;
|
|
||||||
this.Start = Start;
|
|
||||||
this.End = End;
|
|
||||||
//this.Start.Background = GetLineColor(Type); // 线条颜色
|
|
||||||
//this.End.Background = GetLineColor(Type); // 线条颜色
|
|
||||||
InitElementPoint();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 关于入参
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="Canvas"></param>
|
|
||||||
/// <param name="Type"></param>
|
|
||||||
public ConnectionControl(LineType LineType,
|
|
||||||
Canvas Canvas,
|
|
||||||
int argIndex,
|
|
||||||
ConnectionArgSourceType connectionArgSourceType,
|
|
||||||
JunctionControlBase Start,
|
|
||||||
JunctionControlBase End,
|
|
||||||
Action remoteCallback)
|
|
||||||
{
|
|
||||||
this.LineType = LineType;
|
|
||||||
this.RemoteCallback = remoteCallback;
|
|
||||||
this.Canvas = Canvas;
|
|
||||||
this.ArgIndex = ArgIndex;
|
|
||||||
this.ConnectionArgSourceType = connectionArgSourceType;
|
|
||||||
this.Start = Start;
|
|
||||||
this.End = End;
|
|
||||||
//this.Start.Background = GetLineColor(Type); // 线条颜色
|
|
||||||
//this.End.Background = GetLineColor(Type); // 线条颜色
|
|
||||||
InitElementPoint();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 所在的画布
|
/// 所在的画布
|
||||||
@@ -167,7 +121,7 @@ namespace Serein.Workbench.Node.View
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 调用方法类型,连接类型
|
/// 调用方法类型,连接类型
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ConnectionInvokeType Type { get; }
|
public ConnectionInvokeType InvokeType { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取参数类型,第几个参数
|
/// 获取参数类型,第几个参数
|
||||||
@@ -177,7 +131,7 @@ namespace Serein.Workbench.Node.View
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 参数来源(决定了连接线的样式)
|
/// 参数来源(决定了连接线的样式)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ConnectionArgSourceType ConnectionArgSourceType { get; set; }
|
public ConnectionArgSourceType ArgSourceType { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 起始控制点
|
/// 起始控制点
|
||||||
@@ -192,14 +146,86 @@ namespace Serein.Workbench.Node.View
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 连接线
|
/// 连接线
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private BezierLine BezierLine;
|
private ConnectionLineShape BezierLine;
|
||||||
|
|
||||||
private LineType LineType;
|
private LineType LineType;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 关于调用
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Canvas"></param>
|
||||||
|
/// <param name="invokeType"></param>
|
||||||
|
public ConnectionControl(Canvas Canvas,
|
||||||
|
ConnectionInvokeType invokeType,
|
||||||
|
JunctionControlBase Start,
|
||||||
|
JunctionControlBase End,
|
||||||
|
Action remoteCallback)
|
||||||
|
{
|
||||||
|
this.LineType = LineType.Bezier;
|
||||||
|
this.RemoteCallback = remoteCallback;
|
||||||
|
this.Canvas = Canvas;
|
||||||
|
this.InvokeType = invokeType;
|
||||||
|
this.Start = Start;
|
||||||
|
this.End = End;
|
||||||
|
InitElementPoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 关于入参
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Canvas"></param>
|
||||||
|
/// <param name="Type"></param>
|
||||||
|
public ConnectionControl(LineType LineType,
|
||||||
|
Canvas Canvas,
|
||||||
|
int argIndex,
|
||||||
|
ConnectionArgSourceType argSourceType,
|
||||||
|
JunctionControlBase Start,
|
||||||
|
JunctionControlBase End,
|
||||||
|
Action remoteCallback)
|
||||||
|
{
|
||||||
|
this.LineType = LineType;
|
||||||
|
this.RemoteCallback = remoteCallback;
|
||||||
|
this.Canvas = Canvas;
|
||||||
|
this.ArgIndex = ArgIndex;
|
||||||
|
this.ArgSourceType = argSourceType;
|
||||||
|
this.Start = Start;
|
||||||
|
this.End = End;
|
||||||
|
InitElementPoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 绘制
|
||||||
|
/// </summary>
|
||||||
|
public void InitElementPoint()
|
||||||
|
{
|
||||||
|
leftCenterOfEndLocation = Start.MyCenterPoint;
|
||||||
|
rightCenterOfStartLocation = End.MyCenterPoint;
|
||||||
|
|
||||||
|
(Point startPoint, Point endPoint) = RefreshPoint(Canvas, Start, End);
|
||||||
|
var connectionType = Start.JunctionType.ToConnectyionType();
|
||||||
|
bool isDotted;
|
||||||
|
Brush brush;
|
||||||
|
if(connectionType == JunctionOfConnectionType.Invoke)
|
||||||
|
{
|
||||||
|
brush = InvokeType.ToLineColor();
|
||||||
|
isDotted = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
brush = ArgSourceType.ToLineColor();
|
||||||
|
isDotted = true; // 如果为参数,则绘制虚线
|
||||||
|
}
|
||||||
|
BezierLine = new ConnectionLineShape(LineType, startPoint, endPoint, brush, isDotted);
|
||||||
|
Grid.SetZIndex(BezierLine, -9999999); // 置底
|
||||||
|
Canvas.Children.Add(BezierLine);
|
||||||
|
|
||||||
|
ConfigureLineContextMenu(); //配置右键菜单
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 配置连接曲线的右键菜单
|
/// 配置连接曲线的右键菜单
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="line"></param>
|
|
||||||
private void ConfigureLineContextMenu()
|
private void ConfigureLineContextMenu()
|
||||||
{
|
{
|
||||||
var contextMenu = new ContextMenu();
|
var contextMenu = new ContextMenu();
|
||||||
@@ -213,17 +239,15 @@ namespace Serein.Workbench.Node.View
|
|||||||
/// <param name="line"></param>
|
/// <param name="line"></param>
|
||||||
public void DeleteConnection()
|
public void DeleteConnection()
|
||||||
{
|
{
|
||||||
if(this.Start is JunctionControlBase startJunctionControlBase)
|
|
||||||
{
|
|
||||||
//startJunctionControlBase.Background = Brushes.Transparent;
|
|
||||||
}
|
|
||||||
if (this.End is JunctionControlBase endJunctionControlBase)
|
|
||||||
{
|
|
||||||
//endJunctionControlBase.Background = Brushes.Transparent;
|
|
||||||
}
|
|
||||||
Canvas.Children.Remove(BezierLine); // 移除线
|
|
||||||
RemoteCallback?.Invoke();
|
RemoteCallback?.Invoke();
|
||||||
}
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 删除该连线
|
||||||
|
/// </summary>
|
||||||
|
public void Remote()
|
||||||
|
{
|
||||||
|
Canvas.Children.Remove(BezierLine);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 重新绘制
|
/// 重新绘制
|
||||||
@@ -232,38 +256,8 @@ namespace Serein.Workbench.Node.View
|
|||||||
{
|
{
|
||||||
(Point startPoint, Point endPoint) = RefreshPoint(Canvas, Start, End);
|
(Point startPoint, Point endPoint) = RefreshPoint(Canvas, Start, End);
|
||||||
BezierLine.UpdatePoints(startPoint, endPoint);
|
BezierLine.UpdatePoints(startPoint, endPoint);
|
||||||
//BezierLine.UpdatePoints(startPoint, endPoint);
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// 删除该连线
|
|
||||||
/// </summary>
|
|
||||||
public void Remote()
|
|
||||||
{
|
|
||||||
Canvas.Children.Remove(BezierLine);
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// 绘制
|
|
||||||
/// </summary>
|
|
||||||
public void InitElementPoint()
|
|
||||||
{
|
|
||||||
leftCenterOfEndLocation = Start.MyCenterPoint;
|
|
||||||
rightCenterOfStartLocation = End.MyCenterPoint;
|
|
||||||
//leftCenterOfEndLocation = new Point(0, End.ActualHeight / 2); // 目标节点选择左侧边缘中心
|
|
||||||
//rightCenterOfStartLocation = new Point(Start.ActualWidth, Start.ActualHeight / 2); // 起始节点选择右侧边缘中心
|
|
||||||
|
|
||||||
|
|
||||||
linkSize = 4; // 整线条粗细
|
|
||||||
(Point startPoint, Point endPoint) = RefreshPoint(Canvas, Start, End);
|
|
||||||
BezierLine = new BezierLine(LineType, startPoint, endPoint, GetLineColor(Type), linkSize);
|
|
||||||
Grid.SetZIndex(BezierLine, -9999999); // 置底
|
|
||||||
Canvas.Children.Add(BezierLine);
|
|
||||||
|
|
||||||
|
|
||||||
ConfigureLineContextMenu(); //配置右键菜单
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
double linkSize; // 根据缩放比例调整线条粗细
|
|
||||||
private Point rightCenterOfStartLocation; // 目标节点选择左侧边缘中心
|
private Point rightCenterOfStartLocation; // 目标节点选择左侧边缘中心
|
||||||
private Point leftCenterOfEndLocation; // 起始节点选择右侧边缘中心
|
private Point leftCenterOfEndLocation; // 起始节点选择右侧边缘中心
|
||||||
|
|
||||||
@@ -275,24 +269,8 @@ namespace Serein.Workbench.Node.View
|
|||||||
return (startPoint, endPoint);
|
return (startPoint, endPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 根据连接类型指定颜色
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="currentConnectionType"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
/// <exception cref="Exception"></exception>
|
|
||||||
public static SolidColorBrush GetLineColor(ConnectionInvokeType currentConnectionType)
|
|
||||||
{
|
|
||||||
return currentConnectionType switch
|
|
||||||
{
|
|
||||||
ConnectionInvokeType.IsSucceed => new SolidColorBrush((Color)ColorConverter.ConvertFromString("#04FC10")),
|
|
||||||
ConnectionInvokeType.IsFail => new SolidColorBrush((Color)ColorConverter.ConvertFromString("#F18905")),
|
|
||||||
ConnectionInvokeType.IsError => new SolidColorBrush((Color)ColorConverter.ConvertFromString("#FE1343")),
|
|
||||||
ConnectionInvokeType.Upstream => new SolidColorBrush((Color)ColorConverter.ConvertFromString("#4A82E4")),
|
|
||||||
_ => new SolidColorBrush((Color)ColorConverter.ConvertFromString("#56CEF6")),
|
|
||||||
//_ => throw new Exception(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user