修改了无法添加基础节点的bug,增加WebSocket JSON ID字段,远程环境交互使用消息ID作为响应key。

This commit is contained in:
fengjiayi
2024-10-22 00:13:13 +08:00
parent 838158f446
commit 0a7e24d318
48 changed files with 1209 additions and 500 deletions

View File

@@ -0,0 +1,10 @@
{
"profiles": {
"Serein.FlowStartTool": {
"commandName": "Project"
},
"配置文件 1": {
"commandName": "DebugRoslynComponent"
}
}
}

View File

@@ -9,6 +9,9 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<AssemblyName>starter</AssemblyName> <AssemblyName>starter</AssemblyName>
<!--<IsRoslynComponent>true</IsRoslynComponent>-->
<!--<GenerateDocumentationFile>true</GenerateDocumentationFile>-->
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net8.0|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net8.0|AnyCPU'">
@@ -23,8 +26,16 @@
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup> </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> <ItemGroup>
<ProjectReference Include="..\Library\Serein.Library.csproj" /> <!--<ProjectReference Include="..\Serein.Library.MyGenerator\Serein.Library.NodeGenerator.csproj" OutputItemType="Analyzer" />-->
<ProjectReference Include="..\NodeFlow\Serein.NodeFlow.csproj" /> <ProjectReference Include="..\NodeFlow\Serein.NodeFlow.csproj" />
</ItemGroup> </ItemGroup>

View File

@@ -6,9 +6,16 @@ using System.Threading.Tasks;
namespace Serein.Library namespace Serein.Library
{ {
/// <summary>
/// 标识一个类中的某些字段需要生成相应代码
/// </summary>
[AttributeUsage(AttributeTargets.Class, Inherited = true)] [AttributeUsage(AttributeTargets.Class, Inherited = true)]
internal sealed class AutoPropertyAttribute : Attribute public sealed class AutoPropertyAttribute : Attribute
{ {
/// <summary>
/// <para>属性路径</para>
/// <para>CustomNode : 自定义节点</para>
/// </summary>
public string ValuePath = string.Empty; public string ValuePath = string.Empty;
} }
@@ -16,10 +23,19 @@ namespace Serein.Library
/// 自动生成环境的属性 /// 自动生成环境的属性
/// </summary> /// </summary>
[AttributeUsage(AttributeTargets.Field, Inherited = true)] [AttributeUsage(AttributeTargets.Field, Inherited = true)]
internal sealed class PropertyInfoAttribute : Attribute public sealed class PropertyInfoAttribute : Attribute
{ {
/// <summary>
/// 是否通知UI
/// </summary>
public bool IsNotification = false; public bool IsNotification = false;
/// <summary>
/// 是否使用Console.WriteLine打印
/// </summary>
public bool IsPrint = false; public bool IsPrint = false;
/// <summary>
/// 是否禁止参数进行修改初始化后不能再通过setter修改
/// </summary>
public bool IsProtection = false; public bool IsProtection = false;
} }

View File

@@ -9,7 +9,7 @@ namespace Serein.Library
/// <summary> /// <summary>
/// 每个节点有独自的MethodDetails实例 /// 每个节点有独自的MethodDetails实例
/// </summary> /// </summary>
[AutoProperty(ValuePath = nameof(MethodDetails))] [NodeProperty(ValuePath = NodeValuePath.Method)]
public partial class MethodDetails public partial class MethodDetails
{ {
private readonly IFlowEnvironment env; private readonly IFlowEnvironment env;
@@ -142,7 +142,7 @@ namespace Serein.Library
MethodLockName = this.MethodLockName, MethodLockName = this.MethodLockName,
IsProtectionParameter = this.IsProtectionParameter, IsProtectionParameter = this.IsProtectionParameter,
}; };
md.ParameterDetailss = this.ParameterDetailss.Select(p => p.CloneOfClone(env, nodeModel)).ToArray(); // 拷贝属于节点方法的新入参描述 md.ParameterDetailss = this.ParameterDetailss?.Select(p => p?.CloneOfClone(env, nodeModel)).ToArray(); // 拷贝属于节点方法的新入参描述
return md; return md;
} }

View File

@@ -9,7 +9,7 @@ namespace Serein.Library
/// <summary> /// <summary>
/// 节点调试设置,用于中断节点的运行 /// 节点调试设置,用于中断节点的运行
/// </summary> /// </summary>
[AutoProperty(ValuePath = nameof(NodeDebugSetting))] [NodeProperty(ValuePath = NodeValuePath.DebugSetting)]
public partial class NodeDebugSetting public partial class NodeDebugSetting
{ {
private readonly NodeModelBase nodeModel; private readonly NodeModelBase nodeModel;
@@ -33,6 +33,13 @@ namespace Serein.Library
[PropertyInfo] [PropertyInfo]
private InterruptClass _interruptClass = InterruptClass.None; private InterruptClass _interruptClass = InterruptClass.None;
/// <summary>
/// 中断级别,暂时停止继续执行后继分支。
/// </summary>
[PropertyInfo(IsNotification = true)]
private bool _isInterrupt = false;
/// <summary> /// <summary>
/// 取消中断的回调函数 /// 取消中断的回调函数
/// </summary> /// </summary>

View File

@@ -1,4 +1,5 @@
using Serein.Library.Api; using Serein.Library.Api;
using Serein.Library.NodeGenerator;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
@@ -10,7 +11,7 @@ namespace Serein.Library
/// <summary> /// <summary>
/// 节点基类(数据):条件控件,动作控件,条件区域,动作区域 /// 节点基类(数据):条件控件,动作控件,条件区域,动作区域
/// </summary> /// </summary>
[AutoProperty(ValuePath = nameof(NodeModelBase))] // 是否更名为 NodeProperty? [NodeProperty(ValuePath = NodeValuePath.None)]
public abstract partial class NodeModelBase : IDynamicFlowNode public abstract partial class NodeModelBase : IDynamicFlowNode
{ {

View File

@@ -86,7 +86,13 @@ namespace Serein.Library
/// <returns></returns> /// <returns></returns>
public virtual NodeModelBase LoadInfo(NodeInfo nodeInfo) public virtual NodeModelBase LoadInfo(NodeInfo nodeInfo)
{ {
this.Guid = nodeInfo.Guid; this.Guid = nodeInfo.Guid;
if (nodeInfo.Position is null)
{
nodeInfo.Position = new PositionOfUI(0, 0);
}
this.Position = nodeInfo.Position;// 加载位置信息
if (this.MethodDetails != null) if (this.MethodDetails != null)
{ {
for (int i = 0; i < nodeInfo.ParameterData.Length; i++) for (int i = 0; i < nodeInfo.ParameterData.Length; i++)
@@ -96,7 +102,6 @@ namespace Serein.Library
this.MethodDetails.ParameterDetailss[i].DataValue = pd.Value; this.MethodDetails.ParameterDetailss[i].DataValue = pd.Value;
} }
} }
this.Position = nodeInfo.Position;// 加载位置信息
return this; return this;
} }

View File

@@ -11,7 +11,7 @@ namespace Serein.Library
/// <summary> /// <summary>
/// 节点入参参数详情 /// 节点入参参数详情
/// </summary> /// </summary>
[AutoProperty(ValuePath = nameof(ParameterDetails))] [NodeProperty(ValuePath = NodeValuePath.Parameter)]
public partial class ParameterDetails public partial class ParameterDetails
{ {
private readonly IFlowEnvironment env; private readonly IFlowEnvironment env;

View File

@@ -11,7 +11,7 @@ namespace Serein.Library
{ {
/// <summary> /// <summary>
/// 环境信息(远程控制用) /// 环境信息
/// </summary> /// </summary>
public class FlowEnvInfo public class FlowEnvInfo
{ {
@@ -27,10 +27,18 @@ namespace Serein.Library
// IOC节点对象信息 // IOC节点对象信息
} }
/// <summary>
/// 程序集相关的方法信息
/// </summary>
public class LibraryMds public class LibraryMds
{ {
/// <summary>
/// 程序集FullName
/// </summary>
public string LibraryName { get; set; } public string LibraryName { get; set; }
/// <summary>
/// 相关的方法详情
/// </summary>
public MethodDetailsInfo[] Mds { get; set; } public MethodDetailsInfo[] Mds { get; set; }
} }
@@ -70,7 +78,7 @@ namespace Serein.Library
} }
/// <summary> /// <summary>
/// 基础 /// 基础,项目文件相关
/// </summary> /// </summary>
public class Basic public class Basic
{ {
@@ -87,7 +95,7 @@ namespace Serein.Library
public string Versions { get; set; } public string Versions { get; set; }
} }
/// <summary> /// <summary>
/// 画布 /// 画布信息,项目文件相关
/// </summary> /// </summary>
public class FlowCanvas public class FlowCanvas
{ {
@@ -122,7 +130,7 @@ namespace Serein.Library
} }
/// <summary> /// <summary>
/// DLL /// 项目依赖的程序集,项目文件相关
/// </summary> /// </summary>
public class Library public class Library
{ {
@@ -144,7 +152,7 @@ namespace Serein.Library
} }
/// <summary> /// <summary>
/// 节点 /// 节点信息,项目文件相关
/// </summary> /// </summary>
public class NodeInfo public class NodeInfo
{ {
@@ -215,7 +223,7 @@ namespace Serein.Library
} }
/// <summary> /// <summary>
/// 显示参数 /// 显示参数,项目文件相关
/// </summary> /// </summary>
public class Parameterdata public class Parameterdata
{ {

View File

@@ -27,6 +27,7 @@ namespace Serein.Library.Network.WebSocketCommunication
{ {
public string ThemeKey; public string ThemeKey;
public string DataKey; public string DataKey;
public string MsgIdKey;
} }
@@ -71,13 +72,19 @@ namespace Serein.Library.Network.WebSocketCommunication
} }
/// <summary> /// <summary>
/// 使用消息DataKey整体数据 /// 使用 DataKey 整体数据
/// </summary> /// </summary>
[AttributeUsage(AttributeTargets.Parameter)] [AttributeUsage(AttributeTargets.Parameter)]
public sealed class UseMsgDataAttribute : Attribute public sealed class UseDataAttribute : Attribute
{
}
/// <summary>
/// 使用 MsgIdKey 整体数据
/// </summary>
[AttributeUsage(AttributeTargets.Parameter)]
public sealed class UseMsgIdAttribute : Attribute
{ {
} }
internal class SocketHandleModule internal class SocketHandleModule
{ {

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Serein.Library.Network.WebSocketCommunication.Handle namespace Serein.Library.Network.WebSocketCommunication.Handle
@@ -12,4 +13,55 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
public sealed class NeedfulAttribute : Attribute public sealed class NeedfulAttribute : Attribute
{ {
} }
/// <summary>
/// 消息ID生成器
/// </summary>
public class MsgIdHelper
{
private static readonly long _epoch = new DateTime(2023, 1, 1).Ticks; // 自定义起始时间
private static long _lastTimestamp = -1L; // 上一次生成 ID 的时间戳
private static long _sequence = 0L; // 序列号
/// <summary>
/// 获取新的ID
/// </summary>
public static long NewId => GenerateId();
/// <summary>
/// 生成消息ID
/// </summary>
/// <returns></returns>
public static long GenerateId()
{
long timestamp = DateTime.UtcNow.Ticks;
// 如果时间戳是一样的,递增序列号
if (timestamp == _lastTimestamp)
{
// 使用原子操作增加序列号
_sequence = Interlocked.Increment(ref _sequence);
if (_sequence > 999999) // 序列号最大值6位
{
// 等待下一毫秒
while (timestamp <= _lastTimestamp)
{
timestamp = DateTime.UtcNow.Ticks;
}
}
}
else
{
_sequence = 0; // 重置序列号
}
_lastTimestamp = timestamp;
// 生成 ID时间戳和序列号拼接
return (timestamp - _epoch) * 1000 + _sequence; // 返回 ID
}
}
} }

View File

@@ -41,7 +41,8 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
this.OnExceptionTracking = onExceptionTracking; this.OnExceptionTracking = onExceptionTracking;
this.ArgNotNull = ArgNotNull; this.ArgNotNull = ArgNotNull;
this.useMsgData = parameterInfos.Select(p => p.GetCustomAttribute<UseMsgDataAttribute>() != null).ToArray(); this.useData = parameterInfos.Select(p => p.GetCustomAttribute<UseDataAttribute>() != null).ToArray();
this.useMsgId = parameterInfos.Select(p => p.GetCustomAttribute<UseMsgIdAttribute>() != null).ToArray();
#if NET5_0_OR_GREATER #if NET5_0_OR_GREATER
this.IsCheckArgNotNull = parameterInfos.Select(p => p.GetCustomAttribute<NotNullAttribute>() != null).ToArray(); this.IsCheckArgNotNull = parameterInfos.Select(p => p.GetCustomAttribute<NotNullAttribute>() != null).ToArray();
#endif #endif
@@ -101,17 +102,24 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
/// </summary> /// </summary>
private readonly Type[] ParameterType; private readonly Type[] ParameterType;
/// <summary> /// <summary>
/// 是否使用整体data参数 /// 是否使Data整体内容作为入参参数
/// </summary> /// </summary>
private readonly bool[] useMsgData; private readonly bool[] useData;
/// <summary>
/// 是否使用消息ID作为入参参数
/// </summary>
private readonly bool[] useMsgId;
/// <summary> /// <summary>
/// 是否检查变量为空 /// 是否检查变量为空
/// </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, 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;; // 表示是否可以调用方法
@@ -119,10 +127,17 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
{ {
var type = ParameterType[i]; var type = ParameterType[i];
var argName = ParameterName[i]; var argName = ParameterName[i];
if (useMsgData[i]) #region DATA JSON数据
if (useData[i])
{ {
args[i] = jsonObject.ToObject(type); args[i] = jsonObject.ToObject(type);
}
#endregion
else if (useMsgId[i])
{
args[i] = msgId;
} }
#region
else if (type.IsValueType) else if (type.IsValueType)
{ {
var jsonValue = jsonObject.GetValue(argName); var jsonValue = jsonObject.GetValue(argName);
@@ -143,7 +158,9 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
break; break;
} }
} }
} }
#endregion
#region
else if (type.IsClass) else if (type.IsClass)
{ {
var jsonValue = jsonObject.GetValue(argName); var jsonValue = jsonObject.GetValue(argName);
@@ -164,7 +181,9 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
break; break;
} }
} }
} }
#endregion
#region
else if (type.IsGenericType) // 传递SendAsync委托 else if (type.IsGenericType) // 传递SendAsync委托
{ {
if (type.IsAssignableFrom(typeof(Func<object, Task>))) if (type.IsAssignableFrom(typeof(Func<object, Task>)))
@@ -198,7 +217,8 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
await SendAsync.Invoke(jsonText); await SendAsync.Invoke(jsonText);
}); });
} }
} }
#endregion
} }
if (!isCanInvoke) if (!isCanInvoke)
@@ -212,8 +232,6 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
if (EmitMethodType == EmitHelper.EmitMethodType.HasResultTask && EmitDelegate is Func<object, object[], Task<object>> hasResultTask) if (EmitMethodType == EmitHelper.EmitMethodType.HasResultTask && EmitDelegate is Func<object, object[], Task<object>> hasResultTask)
{ {
result = await hasResultTask(Instance, args); result = await hasResultTask(Instance, args);
//Console.WriteLine(result);
// why not data?
} }
else if (EmitMethodType == EmitHelper.EmitMethodType.Task && EmitDelegate is Func<object, object[], Task> task) else if (EmitMethodType == EmitHelper.EmitMethodType.Task && EmitDelegate is Func<object, object[], Task> task)
{ {
@@ -233,34 +251,30 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
{ {
result = null; result = null;
await Console.Out.WriteLineAsync(ex.Message); await Console.Out.WriteLineAsync(ex.Message);
this.OnExceptionTracking.Invoke(ex, (async data => this.OnExceptionTracking.Invoke(ex, (async exData =>
{ {
await SendAsync.Invoke(exData);
var jsonText = JsonConvert.SerializeObject(data);
await SendAsync.Invoke(jsonText);
})); }));
} }
//sw.Stop(); //sw.Stop();
//Console.WriteLine($"Emit Invoke{sw.ElapsedTicks * 1000000F / Stopwatch.Frequency:n3}μs"); //Console.WriteLine($"Emit Invoke{sw.ElapsedTicks * 1000000F / Stopwatch.Frequency:n3}μs");
if(result is null)
if (Module.IsReturnValue)
{ {
return; if (result is null)
}
else
{
if (Module.IsReturnValue)
{ {
_ = SendAsync.Invoke(result); result = "null";
} }
_ = SendAsync.Invoke(result);
} }
//if( && result != null && result.GetType().IsClass) //if( && result != null && result.GetType().IsClass)
//{ //{
// //var reusltJsonText = JsonConvert.SerializeObject(result); // //var reusltJsonText = JsonConvert.SerializeObject(result);
// //_ = SendAsync.Invoke($"{reusltJsonText}"); // //_ = SendAsync.Invoke($"{reusltJsonText}");
//} //}
} }

View File

@@ -19,21 +19,27 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
/// <summary> /// <summary>
/// Json消息处理模块 /// Json消息处理模块
/// </summary> /// </summary>
public WebSocketHandleModule(string ThemeJsonKey, string DataJsonKey) public WebSocketHandleModule(string themeJsonKey, string dataJsonKey, string msgIdJsonKey)
{ {
this.ThemeJsonKey = ThemeJsonKey; this.ThemeJsonKey = themeJsonKey;
this.DataJsonKey = DataJsonKey; this.DataJsonKey = dataJsonKey;
this.MsgIdJsonKey = msgIdJsonKey;
} }
/// <summary> /// <summary>
/// 指示处理模块该使用json中的哪个key作为业务区别字段 /// 指示处理模块该使用 Json 中的哪个 Key 作为业务区别字段
/// </summary> /// </summary>
public string ThemeJsonKey { get; } public string ThemeJsonKey { get; }
/// <summary> /// <summary>
/// 指示处理模块该使用json中的哪个key作为业务数据字段 /// 指示处理模块该使用 Json 中的哪个 Key 作为业务数据字段
/// </summary> /// </summary>
public string DataJsonKey { get; } public string DataJsonKey { get; }
/// <summary>
/// 指示处理模块该使用 Json 中的哪个 Key 作为业务消息ID字段
/// </summary>
public string MsgIdJsonKey { get; }
/// <summary> /// <summary>
/// 存储处理数据的配置 /// 存储处理数据的配置
@@ -88,34 +94,28 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
/// <summary> /// <summary>
/// 处理JSON数据 /// 处理JSON数据
/// </summary> /// </summary>
/// <param name="tSendAsync"></param> /// <param name="sendAsync"></param>
/// <param name="jsonObject"></param> /// <param name="jsonObject"></param>
public void HandleSocketMsg(Func<string, Task> tSendAsync, JObject jsonObject) public void HandleSocketMsg(Func<string, Task> sendAsync, JObject jsonObject)
{ {
// 获取到消息 // 获取到消息
string themeKeyName = jsonObject.GetValue(ThemeJsonKey)?.ToString(); string theme = jsonObject.GetValue(ThemeJsonKey)?.ToString();
if (!MyHandleConfigs.TryGetValue(themeKeyName, out var handldConfig)) if (!MyHandleConfigs.TryGetValue(theme, out var handldConfig))
{ {
// 没有主题 // 没有主题
return; return;
} }
string msgId = jsonObject.GetValue(MsgIdJsonKey)?.ToString();
Func<object, Task> SendAsync = async (data) =>
{
var sendMsg = new
{
theme = themeKeyName,
token = "",
data = data,
};
var msg = JsonConvert.SerializeObject(sendMsg);
await tSendAsync(msg);
};
try try
{ {
JObject dataObj = jsonObject.GetValue(DataJsonKey).ToObject<JObject>(); JObject dataObj = jsonObject.GetValue(DataJsonKey)?.ToObject<JObject>();
handldConfig.Handle(SendAsync, dataObj); handldConfig.Handle(async (data) =>
{
await this.SendAsync(sendAsync, msgId, theme, data);
}, msgId, dataObj);
} }
catch (Exception ex) catch (Exception ex)
@@ -123,12 +123,64 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
Console.WriteLine($"error in ws : {ex.Message}{Environment.NewLine}json value:{jsonObject}"); Console.WriteLine($"error in ws : {ex.Message}{Environment.NewLine}json value:{jsonObject}");
return; return;
} }
} }
/// <summary>
/// 发送消息
/// </summary>
/// <param name="sendAsync"></param>
/// <param name="msgId"></param>
/// <param name="theme"></param>
/// <param name="data"></param>
/// <returns></returns>
public async Task SendAsync(Func<string, Task> sendAsync,string msgId, string theme, object data)
{
JObject jsonData;
if (data is null)
{
jsonData = new JObject()
{
[MsgIdJsonKey] = msgId,
[ThemeJsonKey] = theme,
};
}
else
{
JToken dataToken;
if ((data is System.Collections.IEnumerable || data is Array))
{
dataToken = JArray.FromObject(data);
}
else
{
dataToken = JObject.FromObject(data);
}
jsonData = new JObject()
{
[MsgIdJsonKey] = msgId,
[ThemeJsonKey] = theme,
[DataJsonKey] = dataToken
};
}
var msg = jsonData.ToString();
//Console.WriteLine(msg);
//Console.WriteLine();
await sendAsync.Invoke(msg);
}
} }
} }

View File

@@ -41,13 +41,14 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
/// </summary> /// </summary>
/// <param name="themeKeyName"></param> /// <param name="themeKeyName"></param>
/// <param name="dataKeyName"></param> /// <param name="dataKeyName"></param>
/// <param name="msgIdKeyName"></param>
/// <returns></returns> /// <returns></returns>
private WebSocketHandleModule AddMyHandleModule(string themeKeyName, string dataKeyName) private WebSocketHandleModule AddMyHandleModule(string themeKeyName, string dataKeyName, string msgIdKeyName)
{ {
var key = (themeKeyName, dataKeyName); var key = (themeKeyName, dataKeyName);
if (!MyHandleModuleDict.TryGetValue(key, out var myHandleModule)) if (!MyHandleModuleDict.TryGetValue(key, out var myHandleModule))
{ {
myHandleModule = new WebSocketHandleModule(themeKeyName, dataKeyName); myHandleModule = new WebSocketHandleModule(themeKeyName, dataKeyName, msgIdKeyName);
MyHandleModuleDict[key] = myHandleModule; MyHandleModuleDict[key] = myHandleModule;
} }
return myHandleModule; return myHandleModule;
@@ -93,8 +94,9 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
var themeKey = moduleAttribute.ThemeKey; var themeKey = moduleAttribute.ThemeKey;
var dataKey = moduleAttribute.DataKey; var dataKey = moduleAttribute.DataKey;
var msgIdKey = moduleAttribute.MsgIdKey;
var handlemodule = AddMyHandleModule(themeKey, dataKey); var handleModule = AddMyHandleModule(themeKey, dataKey, msgIdKey);
var methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) var methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.Select(method => .Select(method =>
{ {
@@ -135,7 +137,7 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
try try
{ {
var jsonMsgHandleConfig = new JsonMsgHandleConfig(module, socketControlBase, method, onExceptionTracking, argNotNull); var jsonMsgHandleConfig = new JsonMsgHandleConfig(module, socketControlBase, method, onExceptionTracking, argNotNull);
var result = handlemodule.AddHandleConfigs(module,jsonMsgHandleConfig); var result = handleModule.AddHandleConfigs(module,jsonMsgHandleConfig);
if (!result) if (!result)
{ {
throw new Exception("添加失败,已经添加过相同的配置"); throw new Exception("添加失败,已经添加过相同的配置");
@@ -158,6 +160,7 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
/// <returns></returns> /// <returns></returns>
public async Task HandleMsgAsync(Func<string, Task> SendAsync, string message) public async Task HandleMsgAsync(Func<string, Task> SendAsync, string message)
{ {
//Console.WriteLine(message);
JObject json = JObject.Parse(message); JObject json = JObject.Parse(message);
await Task.Run(() => await Task.Run(() =>
{ {

View File

@@ -96,7 +96,7 @@ namespace Serein.Library.Network.WebSocketCommunication
{ {
var completeMessage = receivedMessage.ToString(); var completeMessage = receivedMessage.ToString();
_ = MsgHandleHelper.HandleMsgAsync(SendAsync, completeMessage); // 处理消息 _ = MsgHandleHelper.HandleMsgAsync(SendAsync, completeMessage); // 处理消息
Debug.WriteLine($"Received: {completeMessage}"); //Debug.WriteLine($"Received: {completeMessage}");
} }
// 清空 StringBuilder 为下一条消息做准备 // 清空 StringBuilder 为下一条消息做准备

View File

@@ -180,10 +180,10 @@ namespace Serein.Library.Network.WebSocketCommunication
return; return;
} }
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 buffer = new byte[1024];
var receivedMessage = new StringBuilder(); // 用于拼接长消息 var receivedMessage = new StringBuilder(); // 用于拼接长消息
@@ -209,7 +209,7 @@ namespace Serein.Library.Network.WebSocketCommunication
if (result.MessageType == WebSocketMessageType.Close) if (result.MessageType == WebSocketMessageType.Close)
{ {
SendAsync = null; //SendAsync = null;
await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None); await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None);
if (IsCheckToken) if (IsCheckToken)
{ {
@@ -233,7 +233,10 @@ namespace Serein.Library.Network.WebSocketCommunication
} }
// 消息处理 // 消息处理
_ = MsgHandleHelper.HandleMsgAsync(SendAsync, message); // 处理消息 _ = MsgHandleHelper.HandleMsgAsync(async (text) =>
{
await WebSocketServer.SendAsync(webSocket, text);
}, message); // 处理消息
} }
// 清空 StringBuilder 为下一条消息做准备 // 清空 StringBuilder 为下一条消息做准备

View File

@@ -12,8 +12,8 @@
<RepositoryUrl>https://github.com/fhhyyp/serein-flow</RepositoryUrl> <RepositoryUrl>https://github.com/fhhyyp/serein-flow</RepositoryUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression> <PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance> <PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
<GenerateDocumentationFile>true</GenerateDocumentationFile> <GenerateDocumentationFile>true</GenerateDocumentationFile>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles> <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>.\obj\g</CompilerGeneratedFilesOutputPath> <CompilerGeneratedFilesOutputPath>.\obj\g</CompilerGeneratedFilesOutputPath>
</PropertyGroup> </PropertyGroup>
@@ -30,6 +30,10 @@
<None Remove="Utils\SerinExpression\**" /> <None Remove="Utils\SerinExpression\**" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Compile Remove="FlowNode\Attribute.cs" />
</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" />

View File

@@ -1,4 +1,5 @@
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Serein.Library.Network.WebSocketCommunication; using Serein.Library.Network.WebSocketCommunication;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -15,29 +16,52 @@ namespace Serein.Library.Utils
public class RemoteEnvControl public class RemoteEnvControl
{ {
/// <summary> /// <summary>
/// 配置远程连接IP端口 /// 远程环境配置
/// </summary> /// </summary>
public RemoteEnvControl(string addres, int port, object token) public class ControlConfiguration
{ {
this.Addres = addres; /// <summary>
this.Port = port; /// 远程环境的网络地址
this.Token = token; /// </summary>
public string Addres { get; set; }
/// <summary>
/// 远程环境的对外端口
/// </summary>
public int Port { get; set; }
/// <summary>
/// 登录远程环境必须携带的token(可以为可序列化的JSON对象)
/// </summary>
public object Token { get; set; }
/// <summary>
/// 有关消息ID的 Json Key
/// </summary>
public string MsgIdJsonKey { get; set; }
/// <summary>
/// 有关消息主题的 Json Key
/// </summary>
public string ThemeJsonKey { get; set; }
/// <summary>
/// 有关数据的 Json Key
/// </summary>
public string DataJsonKey { get; set; }
} }
/// <summary> /// <summary>
/// 远程环境的网络地址 /// 配置远程连接IP端口
/// </summary> /// </summary>
public string Addres { get; } public RemoteEnvControl(ControlConfiguration controlConfiguration)
{
Config = controlConfiguration;
}
/// <summary> /// <summary>
/// 远程环境的对外端口 /// 配置信息
/// </summary> /// </summary>
public int Port { get; } public ControlConfiguration Config { get; }
/// <summary>
/// 登录远程环境必须携带的token(可以为可序列化的JSON对象)
/// </summary>
public object Token { get; }
@@ -49,8 +73,8 @@ namespace Serein.Library.Utils
/// <summary> /// <summary>
/// 是否连接到了远程环境 /// 是否连接到了远程环境
/// </summary> /// </summary>
public bool IsConnectdRemoteEnv { get => isConnectdRemoteEnv; } //public bool IsConnectdRemoteEnv { get => isConnectdRemoteEnv; }
private bool isConnectdRemoteEnv = false; //private bool isConnectdRemoteEnv = false;
/// <summary> /// <summary>
/// 尝试连接到远程环境 /// 尝试连接到远程环境
@@ -59,12 +83,12 @@ namespace Serein.Library.Utils
public async Task<bool> ConnectAsync() public async Task<bool> ConnectAsync()
{ {
// 第2种WebSocket连接到远程环境实时接收远程环境的响应 // 第2种WebSocket连接到远程环境实时接收远程环境的响应
Console.WriteLine($"准备连接:{Addres}:{Port},{Token}"); Console.WriteLine($"准备连接:{Config.Addres}:{Config.Port},{Config.Token}");
bool success = false; bool success = false;
try try
{ {
var tcpClient = new TcpClient(); var tcpClient = new TcpClient();
var result = tcpClient.BeginConnect(Addres, Port, null, null); var result = tcpClient.BeginConnect(Config.Addres, Config.Port, null, null);
success = result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(3)); success = result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(3));
} }
finally finally
@@ -73,14 +97,14 @@ namespace Serein.Library.Utils
} }
if (!success) if (!success)
{ {
Console.WriteLine($"无法连通远程端口 {Addres}:{Port}"); Console.WriteLine($"无法连通远程端口 {Config.Addres}:{Config.Port}");
return false; return false;
} }
else else
{ {
var url = $"ws://{Addres}:{Port}/"; var url = $"ws://{Config.Addres}:{Config.Port}/";
var result = await EnvClient.ConnectAsync(url); // 尝试连接远程环境 var result = await EnvClient.ConnectAsync(url); // 尝试连接远程环境
this.isConnectdRemoteEnv = result; //this.isConnectdRemoteEnv = result;
return result; return result;
} }
} }
@@ -90,18 +114,53 @@ namespace Serein.Library.Utils
/// <summary> /// <summary>
/// 发送消息 /// 发送消息
/// </summary> /// </summary>
/// <param name="msgId"></param>
/// <param name="theme"></param> /// <param name="theme"></param>
/// <param name="data"></param> /// <param name="data"></param>
/// <returns></returns> /// <returns></returns>
public async Task SendAsync(string theme, object data) public async Task SendAsync(string msgId , string theme, object data)
{ {
var sendMsg = new //var sendMsg = new
//{
// theme = theme,
// token = this.Token,
// data = data,
//};
//var msg = JsonConvert.SerializeObject(sendMsg);
JObject jsonData;
if (data is null)
{ {
theme = theme, jsonData = new JObject()
token = this.Token, {
data = data, [Config.MsgIdJsonKey] = msgId,
}; [Config.ThemeJsonKey] = theme,
var msg = JsonConvert.SerializeObject(sendMsg); };
}
else
{
JToken dataToken;
if (data is System.Collections.IEnumerable || data is Array)
{
dataToken = JArray.FromObject(data);
}
else
{
dataToken = JObject.FromObject(data);
}
jsonData = new JObject()
{
[Config.MsgIdJsonKey] = msgId,
[Config.ThemeJsonKey] = theme,
[Config.DataJsonKey] = dataToken
};
}
var msg = jsonData.ToString();
//Console.WriteLine(msg);
//Console.WriteLine();
await EnvClient.SendAsync(msg); await EnvClient.SendAsync(msg);
} }
@@ -113,8 +172,6 @@ namespace Serein.Library.Utils
} }

View File

@@ -1,10 +1,4 @@
using System; namespace Serein.NodeFlow.Env
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serein.NodeFlow.Env
{ {
/// <summary> /// <summary>
/// 消息主题 /// 消息主题

View File

@@ -1,28 +1,15 @@
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Bson;
using Newtonsoft.Json.Linq;
using Serein.Library; using Serein.Library;
using Serein.Library.Api; using Serein.Library.Api;
using Serein.Library.Network.WebSocketCommunication;
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;
using Serein.NodeFlow.Tool; using Serein.NodeFlow.Tool;
using System;
using System.Collections;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Sockets;
using System.Numerics;
using System.Reflection; using System.Reflection;
using System.Security.Cryptography;
using System.Threading;
using System.Xml.Linq; using System.Xml.Linq;
using static Serein.Library.Utils.ChannelFlowInterrupt; using static Serein.Library.Utils.ChannelFlowInterrupt;
using static Serein.NodeFlow.FlowStarter;
using static System.Runtime.InteropServices.JavaScript.JSType;
namespace Serein.NodeFlow.Env namespace Serein.NodeFlow.Env
{ {
@@ -41,6 +28,7 @@ namespace Serein.NodeFlow.Env
public const string SpaceName = $"{nameof(Serein)}.{nameof(NodeFlow)}.{nameof(Model)}"; public const string SpaceName = $"{nameof(Serein)}.{nameof(NodeFlow)}.{nameof(Model)}";
public const string ThemeKey = "theme"; public const string ThemeKey = "theme";
public const string DataKey = "data"; public const string DataKey = "data";
public const string MsgIdKey = "msgid";
/// <summary> /// <summary>
/// 流程运行环境 /// 流程运行环境
@@ -80,10 +68,6 @@ namespace Serein.NodeFlow.Env
/// <summary> /// <summary>
/// 打开远程管理 /// 打开远程管理
/// </summary> /// </summary>
@@ -112,6 +96,7 @@ namespace Serein.NodeFlow.Env
Console.WriteLine("结束远程管理异常:" + ex); Console.WriteLine("结束远程管理异常:" + ex);
} }
} }
#endregion #endregion
#region #region
@@ -347,7 +332,6 @@ namespace Serein.NodeFlow.Env
} }
/// <summary> /// <summary>
/// 异步运行 /// 异步运行
/// </summary> /// </summary>
@@ -566,8 +550,17 @@ namespace Serein.NodeFlow.Env
} }
else else
{ {
MethodDetails? methodDetails = null;
if (!string.IsNullOrEmpty(nodeInfo.MethodName))
{
MethodDetailss.TryGetValue(nodeInfo.MethodName, out methodDetails);// 加载项目时尝试获取方法信息
}
else
{
MethodDetailss.TryGetValue(nodeInfo.MethodName, out var methodDetails);// 加载项目时尝试获取方法信息 }
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)
@@ -575,6 +568,8 @@ namespace Serein.NodeFlow.Env
nodeInfo.Guid = string.Empty; nodeInfo.Guid = string.Empty;
continue; continue;
} }
TryAddNode(nodeModel); // 加载项目时将节点加载到环境中 TryAddNode(nodeModel); // 加载项目时将节点加载到环境中
if (nodeInfo.ChildNodeGuids?.Length > 0) if (nodeInfo.ChildNodeGuids?.Length > 0)
{ {
@@ -662,9 +657,6 @@ namespace Serein.NodeFlow.Env
} }
/// <summary> /// <summary>
/// 加载远程环境 /// 加载远程环境
/// </summary> /// </summary>
@@ -679,7 +671,17 @@ namespace Serein.NodeFlow.Env
return (false, null); return (false, null);
} }
// 没有连接远程环境,可以重新连接 // 没有连接远程环境,可以重新连接
var remoteEnvControl = new RemoteEnvControl(addres, port, token);
var controlConfiguration = new RemoteEnvControl.ControlConfiguration
{
Addres = addres,
Port = port,
Token = token,
ThemeJsonKey = FlowEnvironment.ThemeKey,
MsgIdJsonKey = FlowEnvironment.MsgIdKey,
DataJsonKey = FlowEnvironment.DataKey,
};
var remoteEnvControl = new RemoteEnvControl(controlConfiguration);
var result = await remoteEnvControl.ConnectAsync(); var result = await remoteEnvControl.ConnectAsync();
if (!result) if (!result)
{ {
@@ -805,7 +807,6 @@ namespace Serein.NodeFlow.Env
} }
} }
TryAddNode(nodeModel); TryAddNode(nodeModel);
nodeModel.Position = position; nodeModel.Position = position;
@@ -1199,30 +1200,11 @@ namespace Serein.NodeFlow.Env
} }
NodeValueChangeLogger.Add((nodeGuid, path, value)); NodeValueChangeLogger.Add((nodeGuid, path, value));
var setExp = $"@Set .{path} = {value}"; // 生成 set 表达式 var setExp = $"@Set .{path} = {value}"; // 生成 set 表达式
SerinExpressionEvaluator.Evaluate(setExp, nodeModel, out _); // 更改对应的数据
//Console.WriteLine($"本地环境收到数据更改通知:{value}");
//var getExp = $"@Get .{path}"; //var getExp = $"@Get .{path}";
////Console.WriteLine($"取值表达式:{getExp}"); SerinExpressionEvaluator.Evaluate(setExp, nodeModel, out _); // 更改对应的数据
//var getResult = SerinExpressionEvaluator.Evaluate(getExp, nodeModel, out _); //var getResult = SerinExpressionEvaluator.Evaluate(getExp, nodeModel, out _);
////Console.WriteLine($"原数据 :{getResult}"); //Console.WriteLine($"Set表达式{setExp},result : {getResult}");
//if (getResult.Equals(value))
//{
// Console.WriteLine("无须修改");
// return;
//}
//NodeValueChangeLogger.Add((nodeGuid, path, value));
//var setExp = $"@Set .{path} = {value}";
////Console.WriteLine($"设值表达式:{setExp}");
//SerinExpressionEvaluator.Evaluate(setExp, nodeModel, out _);
//getResult = SerinExpressionEvaluator.Evaluate(getExp, nodeModel, out _);
//Console.WriteLine($"新数据 :{getResult}");
} }

View File

@@ -1,14 +1,6 @@
using Serein.Library; using Serein.Library;
using Serein.Library.Api; using Serein.Library.Api;
using Serein.Library.Utils; using Serein.Library.Utils;
using Serein.Library.Web;
using Serein.NodeFlow.Tool;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serein.NodeFlow.Env namespace Serein.NodeFlow.Env
{ {

View File

@@ -1,12 +1,6 @@
using Serein.Library; using Serein.Library;
using Serein.Library.Api; using Serein.Library.Api;
using Serein.NodeFlow.Model; using Serein.NodeFlow.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace Serein.NodeFlow.Env namespace Serein.NodeFlow.Env
{ {

View File

@@ -1,12 +1,7 @@
using Newtonsoft.Json; using Serein.Library;
using Serein.Library;
using Serein.Library.Network.WebSocketCommunication; using Serein.Library.Network.WebSocketCommunication;
using Serein.Library.Network.WebSocketCommunication.Handle;
using Serein.Library.Utils; using Serein.Library.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serein.NodeFlow.Env namespace Serein.NodeFlow.Env
{ {
@@ -17,33 +12,43 @@ namespace Serein.NodeFlow.Env
/// 客户端的消息管理(用于处理服务端的响应) /// 客户端的消息管理(用于处理服务端的响应)
/// </summary> /// </summary>
[AutoSocketModule(ThemeKey = FlowEnvironment.ThemeKey, DataKey = FlowEnvironment.DataKey)] [AutoSocketModule(ThemeKey = FlowEnvironment.ThemeKey,
DataKey = FlowEnvironment.DataKey,
MsgIdKey = FlowEnvironment.MsgIdKey)]
public class MsgControllerOfClient : ISocketHandleModule public class MsgControllerOfClient : ISocketHandleModule
{ {
public Guid HandleGuid => new Guid(); public Guid HandleGuid => new Guid();
private readonly Func<string, object?, Task> SendCommandAsync;
// 消息主题data - task等待
private readonly Func<string, string, object?, Task> SendCommandFunc;
private readonly RemoteFlowEnvironment remoteFlowEnvironment; private readonly RemoteFlowEnvironment remoteFlowEnvironment;
public MsgControllerOfClient(RemoteFlowEnvironment remoteFlowEnvironment, Func<string, object?, Task> func) public MsgControllerOfClient(RemoteFlowEnvironment remoteFlowEnvironment, Func<string, string, object?, Task> func)
{ {
this.remoteFlowEnvironment = remoteFlowEnvironment; this.remoteFlowEnvironment = remoteFlowEnvironment;
SendCommandAsync = func; SendCommandFunc = func;
}
private async Task SendCommandAsync(string msgId, string theme, object? data)
{
await SendCommandFunc.Invoke(msgId, theme, data);
} }
/// <summary> /// <summary>
/// 发送请求并等待远程环境响应 /// 发送请求
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
/// <exception cref="NotImplementedException">超时触发</exception> /// <exception cref="NotImplementedException">超时触发</exception>
public async Task SendAsync(string signal, object? sendData = null, int overtimeInMs = 100) public async Task SendAsync(string signal, object? data = null, int overtimeInMs = 100)
{ {
//Console.WriteLine($"指令[{signal}]value{JsonConvert.SerializeObject(sendData)}"); //Console.WriteLine($"指令[{signal}]value{JsonConvert.SerializeObject(sendData)}");
if (!DebounceHelper.CanExecute(signal, overtimeInMs)) if (!DebounceHelper.CanExecute(signal, overtimeInMs))
{ {
return; return;
} }
await SendCommandAsync.Invoke(signal, sendData); var msgId = MsgIdHelper.GenerateId().ToString();
await SendCommandAsync(msgId, signal, data);
} }
/// <summary> /// <summary>
@@ -51,11 +56,13 @@ namespace Serein.NodeFlow.Env
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
/// <exception cref="NotImplementedException">超时触发</exception> /// <exception cref="NotImplementedException">超时触发</exception>
public async Task<TResult> SendAndWaitDataAsync<TResult>(string signal, object? sendData = 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)}"); //Console.WriteLine($"指令[{signal}]value{JsonConvert.SerializeObject(sendData)}");
_ = SendCommandAsync.Invoke(signal, sendData);
return await remoteFlowEnvironment.WaitData<TResult>(signal); var msgId = MsgIdHelper.GenerateId().ToString();
_ = SendCommandAsync(msgId, theme, data);
return await remoteFlowEnvironment.WaitData<TResult>(msgId);
//if (DebounceHelper.CanExecute(signal, overtimeInMs)) //if (DebounceHelper.CanExecute(signal, overtimeInMs))
//{ //{
@@ -86,63 +93,63 @@ namespace Serein.NodeFlow.Env
/// <summary> /// <summary>
/// 远程环境发来项目信息 /// 远程环境发来项目信息
/// </summary> /// </summary>
/// <param name="msgId"></param>
/// <param name="flowEnvInfo"></param> /// <param name="flowEnvInfo"></param>
[AutoSocketHandle(ThemeValue = EnvMsgTheme.GetEnvInfo)] [AutoSocketHandle(ThemeValue = EnvMsgTheme.GetEnvInfo)]
public void GetEnvInfo([UseMsgData] FlowEnvInfo flowEnvInfo) public void GetEnvInfo([UseMsgId] string msgId, [UseData] FlowEnvInfo flowEnvInfo)
{ {
remoteFlowEnvironment.TriggerSignal(EnvMsgTheme.GetEnvInfo, flowEnvInfo); remoteFlowEnvironment.TriggerSignal(msgId, flowEnvInfo);
} }
/// <summary> /// <summary>
/// 远程环境发来项目信息 /// 远程环境发来项目信息
/// </summary> /// </summary>
/// <param name="msgId"></param>
/// <param name="sereinProjectData"></param> /// <param name="sereinProjectData"></param>
[AutoSocketHandle(ThemeValue = EnvMsgTheme.GetProjectInfo)] [AutoSocketHandle(ThemeValue = EnvMsgTheme.GetProjectInfo)]
public void GetProjectInfo([UseMsgData] SereinProjectData sereinProjectData) public void GetProjectInfo([UseMsgId] string msgId, [UseData] SereinProjectData sereinProjectData)
{ {
remoteFlowEnvironment.TriggerSignal(EnvMsgTheme.GetProjectInfo, sereinProjectData); remoteFlowEnvironment.TriggerSignal(msgId, sereinProjectData);
} }
[AutoSocketHandle(ThemeValue = EnvMsgTheme.SetNodeInterrupt)] [AutoSocketHandle(ThemeValue = EnvMsgTheme.SetNodeInterrupt)]
public void SetNodeInterrupt() public void SetNodeInterrupt([UseMsgId] string msgId)
{ {
remoteFlowEnvironment.TriggerSignal(EnvMsgTheme.GetProjectInfo, null); remoteFlowEnvironment.TriggerSignal(msgId, null);
} }
[AutoSocketHandle(ThemeValue = EnvMsgTheme.AddInterruptExpression)] [AutoSocketHandle(ThemeValue = EnvMsgTheme.AddInterruptExpression)]
public void AddInterruptExpression() public void AddInterruptExpression([UseMsgId] string msgId)
{ {
remoteFlowEnvironment.TriggerSignal(EnvMsgTheme.AddInterruptExpression, null); remoteFlowEnvironment.TriggerSignal(msgId, null);
} }
[AutoSocketHandle(ThemeValue = EnvMsgTheme.CreateNode)] [AutoSocketHandle(ThemeValue = EnvMsgTheme.CreateNode)]
public void CreateNode([UseMsgData] NodeInfo nodeInfo) public void CreateNode([UseMsgId] string msgId, [UseData] NodeInfo nodeInfo)
{ {
remoteFlowEnvironment.TriggerSignal(EnvMsgTheme.CreateNode, nodeInfo); remoteFlowEnvironment.TriggerSignal(msgId, nodeInfo);
} }
[AutoSocketHandle(ThemeValue = EnvMsgTheme.RemoveNode)] [AutoSocketHandle(ThemeValue = EnvMsgTheme.RemoveNode)]
public void RemoveNode(bool state) public void RemoveNode([UseMsgId] string msgId, bool state)
{ {
remoteFlowEnvironment.TriggerSignal(EnvMsgTheme.RemoveNode, state); remoteFlowEnvironment.TriggerSignal(msgId, state);
} }
[AutoSocketHandle(ThemeValue = EnvMsgTheme.ConnectNode)] [AutoSocketHandle(ThemeValue = EnvMsgTheme.ConnectNode)]
public void ConnectNode(bool state) public void ConnectNode([UseMsgId] string msgId, bool state)
{ {
remoteFlowEnvironment.TriggerSignal(EnvMsgTheme.ConnectNode, state); remoteFlowEnvironment.TriggerSignal(msgId, state);
} }
[AutoSocketHandle(ThemeValue = EnvMsgTheme.RemoveConnect)] [AutoSocketHandle(ThemeValue = EnvMsgTheme.RemoveConnect)]
public void RemoveConnect(bool state) public void RemoveConnect([UseMsgId] string msgId, bool state)
{ {
remoteFlowEnvironment.TriggerSignal(EnvMsgTheme.RemoveConnect, state); remoteFlowEnvironment.TriggerSignal(msgId, state);
} }

View File

@@ -1,22 +1,18 @@
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using Serein.Library.Api;
using Serein.Library; using Serein.Library;
using Serein.Library.Api;
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;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serein.NodeFlow.Env namespace Serein.NodeFlow.Env
{ {
/// <summary> /// <summary>
/// 服务端的消息管理(用于处理客户端的请求) /// 服务端的消息管理(用于处理客户端的请求)
/// </summary> /// </summary>
[AutoSocketModule(ThemeKey = FlowEnvironment.ThemeKey, DataKey = FlowEnvironment.DataKey)] [AutoSocketModule(ThemeKey = FlowEnvironment.ThemeKey,
DataKey = FlowEnvironment.DataKey,
MsgIdKey = FlowEnvironment.MsgIdKey)]
public class MsgControllerOfServer : ISocketHandleModule public class MsgControllerOfServer : ISocketHandleModule
{ {
/// <summary> /// <summary>
@@ -225,7 +221,7 @@ namespace Serein.NodeFlow.Env
/// <summary> /// <summary>
/// 获取当前环境信息(远程连接) /// 获取当前环境信息
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
[AutoSocketHandle(ThemeValue = EnvMsgTheme.GetEnvInfo)] [AutoSocketHandle(ThemeValue = EnvMsgTheme.GetEnvInfo)]
@@ -316,6 +312,7 @@ namespace Serein.NodeFlow.Env
var nodeInfo = await environment.CreateNodeAsync(nodeControlType, position, mdInfo); // 监听到客户端创建节点的请求 var nodeInfo = await environment.CreateNodeAsync(nodeControlType, position, mdInfo); // 监听到客户端创建节点的请求
return nodeInfo; return nodeInfo;
} }
/// <summary> /// <summary>
/// 从远程环境移除节点 /// 从远程环境移除节点
/// </summary> /// </summary>
@@ -464,10 +461,6 @@ namespace Serein.NodeFlow.Env
} }
} }

View File

@@ -3,8 +3,6 @@ using Serein.Library.Api;
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.Threading;
using System.Xml.Linq;
namespace Serein.NodeFlow.Env namespace Serein.NodeFlow.Env
{ {
@@ -104,9 +102,8 @@ namespace Serein.NodeFlow.Env
public void LoadProject(FlowEnvInfo flowEnvInfo, string filePath) public void LoadProject(FlowEnvInfo flowEnvInfo, string filePath)
{ {
Console.WriteLine("远程环境尚未实现的接口LoadProject"); //Console.WriteLine("远程环境尚未实现的接口LoadProject");
// dll面板 // dll面板
var libmds = flowEnvInfo.LibraryMds; var libmds = flowEnvInfo.LibraryMds;
foreach (var lib in libmds) foreach (var lib in libmds)
@@ -143,8 +140,11 @@ namespace Serein.NodeFlow.Env
else else
{ {
MethodDetails? methodDetails; MethodDetails? methodDetails = null;
MethodDetailss.TryGetValue(nodeInfo.MethodName, out methodDetails);// 尝试获取方法信息 if (!string.IsNullOrEmpty(nodeInfo.MethodName))
{
MethodDetailss.TryGetValue(nodeInfo.MethodName, out methodDetails);// 加载远程环境时尝试获取方法信息
}
var nodeModel = FlowFunc.CreateNode(this, controlType, methodDetails); // 加载远程项目时创建节点 var nodeModel = FlowFunc.CreateNode(this, controlType, methodDetails); // 加载远程项目时创建节点
nodeModel.LoadInfo(nodeInfo); // 创建节点model nodeModel.LoadInfo(nodeInfo); // 创建节点model
@@ -160,7 +160,6 @@ namespace Serein.NodeFlow.Env
{ {
regionChildNodes.Add((nodeModel, nodeInfo.ChildNodeGuids)); regionChildNodes.Add((nodeModel, nodeInfo.ChildNodeGuids));
UIContextOperation?.Invoke(() => OnNodeCreate?.Invoke(new NodeCreateEventArgs(nodeModel, nodeInfo.Position))); UIContextOperation?.Invoke(() => OnNodeCreate?.Invoke(new NodeCreateEventArgs(nodeModel, nodeInfo.Position)));
//OnNodeCreate?.Invoke(new NodeCreateEventArgs(nodeModel, nodeInfo.Position));
} }
else else
{ {
@@ -181,7 +180,6 @@ namespace Serein.NodeFlow.Env
continue; continue;
} }
// 存在节点 // 存在节点
//OnNodeCreate?.Invoke(new NodeCreateEventArgs(childNode, true, item.region.Guid));
UIContextOperation?.Invoke(() => OnNodeCreate?.Invoke(new NodeCreateEventArgs(childNode, true, item.region.Guid))); UIContextOperation?.Invoke(() => OnNodeCreate?.Invoke(new NodeCreateEventArgs(childNode, true, item.region.Guid)));
} }
} }
@@ -252,7 +250,10 @@ namespace Serein.NodeFlow.Env
}); });
SetStartNode(projectData.StartNode); SetStartNode(projectData.StartNode);
OnProjectLoaded?.Invoke(new ProjectLoadedEventArgs()); UIContextOperation?.Invoke(() =>
{
OnProjectLoaded?.Invoke(new ProjectLoadedEventArgs());
});
} }
private bool TryAddNode(NodeModelBase nodeModel) private bool TryAddNode(NodeModelBase nodeModel)
@@ -394,7 +395,10 @@ namespace Serein.NodeFlow.Env
public void MoveNode(string nodeGuid, double x, double y) public void MoveNode(string nodeGuid, double x, double y)
{ {
OnNodeMoved.Invoke(new NodeMovedEventArgs(nodeGuid, x, y)); UIContextOperation.Invoke(() =>
{
OnNodeMoved.Invoke(new NodeMovedEventArgs(nodeGuid, x, y));
});
_ = msgClient.SendAsync(EnvMsgTheme.MoveNode, _ = msgClient.SendAsync(EnvMsgTheme.MoveNode,
new new
{ {
@@ -404,13 +408,14 @@ namespace Serein.NodeFlow.Env
}); });
} }
public void SetStartNode(string nodeGuid) public void SetStartNode(string nodeGuid)
{ {
_ = msgClient.SendAsync(EnvMsgTheme.SetStartNode, new _ = msgClient.SendAsync(EnvMsgTheme.SetStartNode, new
{ {
nodeGuid nodeGuid
}); });
// UIContextOperation?.Invoke(() => OnStartNodeChange?.Invoke(new StartNodeChangeEventArgs(oldNodeGuid, StartNode.Guid))); //UIContextOperation?.Invoke(() => OnStartNodeChange?.Invoke(new StartNodeChangeEventArgs(nodeGuid,nodeGuid)));
} }
public async Task<bool> ConnectNodeAsync(string fromNodeGuid, string toNodeGuid, ConnectionType connectionType) public async Task<bool> ConnectNodeAsync(string fromNodeGuid, string toNodeGuid, ConnectionType connectionType)
@@ -440,13 +445,22 @@ namespace Serein.NodeFlow.Env
mdInfo = methodDetailsInfo, mdInfo = methodDetailsInfo,
}); });
MethodDetailss.TryGetValue(methodDetailsInfo.MethodName, out var methodDetails);// 加载项目时尝试获取方法信息 MethodDetails? methodDetails = null;
if (!string.IsNullOrEmpty(nodeInfo.MethodName))
{
MethodDetailss.TryGetValue(nodeInfo.MethodName, out methodDetails);// 加载远程环境时尝试获取方法信息
}
//MethodDetailss.TryGetValue(methodDetailsInfo.MethodName, out var methodDetails);// 加载项目时尝试获取方法信息
var nodeModel = FlowFunc.CreateNode(this, nodeControlType, methodDetails); // 远程环境下加载节点 var nodeModel = FlowFunc.CreateNode(this, nodeControlType, methodDetails); // 远程环境下加载节点
nodeModel.LoadInfo(nodeInfo); nodeModel.LoadInfo(nodeInfo);
TryAddNode(nodeModel); TryAddNode(nodeModel);
// 通知UI更改 // 通知UI更改
OnNodeCreate?.Invoke(new NodeCreateEventArgs(nodeModel, position)); UIContextOperation.Invoke(() =>
{
OnNodeCreate?.Invoke(new NodeCreateEventArgs(nodeModel, position));
});
return nodeInfo; return nodeInfo;
} }
@@ -460,10 +474,13 @@ namespace Serein.NodeFlow.Env
}); });
if (result) if (result)
{ {
OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNodeGuid, UIContextOperation.Invoke(() =>
{
OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNodeGuid,
toNodeGuid, toNodeGuid,
connectionType, connectionType,
NodeConnectChangeEventArgs.ConnectChangeType.Remote)); NodeConnectChangeEventArgs.ConnectChangeType.Remote));
});
} }
return result; return result;
} }
@@ -476,7 +493,10 @@ namespace Serein.NodeFlow.Env
}); });
if (result) if (result)
{ {
OnNodeRemove?.Invoke(new NodeRemoveEventArgs(nodeGuid)); UIContextOperation.Invoke(() =>
{
OnNodeRemove?.Invoke(new NodeRemoveEventArgs(nodeGuid));
});
} }
else else
{ {

View File

@@ -4,20 +4,38 @@ using Serein.Library.Api;
namespace Serein.NodeFlow.Model namespace Serein.NodeFlow.Model
{ {
/// <summary> /// <summary>
/// 组合条件节点(用于条件区域) /// 组合条件节点(用于条件区域)
/// </summary> /// </summary>
public class CompositeConditionNode : NodeModelBase [NodeProperty(ValuePath = NodeValuePath.Node)]
public partial class CompositeConditionNode : NodeModelBase
{
/// <summary>
/// 条件节点集合
/// </summary>
[PropertyInfo]
private List<SingleConditionNode> _conditionNodes;
}
/// <summary>
/// 组合条件节点(用于条件区域)
/// </summary>
public partial class CompositeConditionNode : NodeModelBase
{ {
public CompositeConditionNode(IFlowEnvironment environment):base(environment) public CompositeConditionNode(IFlowEnvironment environment):base(environment)
{ {
} }
public List<SingleConditionNode> ConditionNodes { get; } = [];
public void AddNode(SingleConditionNode node) public void AddNode(SingleConditionNode node)
{ {
if(ConditionNodes is null)
{
ConditionNodes = new List<SingleConditionNode>();
}
ConditionNodes.Add(node); ConditionNodes.Add(node);
MethodDetails ??= node.MethodDetails; MethodDetails ??= node.MethodDetails;
} }
@@ -93,6 +111,7 @@ namespace Serein.NodeFlow.Model
ParameterData = parameterData.ToArray(), ParameterData = parameterData.ToArray(),
ErrorNodes = errorNodes.ToArray(), ErrorNodes = errorNodes.ToArray(),
ChildNodeGuids = ConditionNodes.Select(node => node.Guid).ToArray(), ChildNodeGuids = ConditionNodes.Select(node => node.Guid).ToArray(),
Position = Position,
}; };
} }

View File

@@ -1,35 +1,51 @@
using Serein.Library; using Serein.Library;
using Serein.Library.Api; using Serein.Library.Api;
using Serein.Library.Utils.SereinExpression; using Serein.Library.Utils.SereinExpression;
using System.ComponentModel;
namespace Serein.NodeFlow.Model namespace Serein.NodeFlow.Model
{ {
/// <summary> /// <summary>
/// 条件节点(用于条件控件) /// 条件节点(用于条件控件)
/// </summary> /// </summary>
public class SingleConditionNode : NodeModelBase [NodeProperty(ValuePath = NodeValuePath.Node)]
public partial class SingleConditionNode : NodeModelBase
{ {
public SingleConditionNode(IFlowEnvironment environment):base(environment)
{
}
/// <summary> /// <summary>
/// 是否为自定义参数 /// 是否为自定义参数
/// </summary> /// </summary>
public bool IsCustomData { get; set; } [PropertyInfo(IsNotification = true)]
private bool _isCustomData;
/// <summary> /// <summary>
/// 自定义参数值 /// 自定义参数值
/// </summary> /// </summary>
public object? CustomData { get; set; } [PropertyInfo(IsNotification = true)]
private object? _customData;
/// <summary> /// <summary>
/// 条件表达式 /// 条件表达式
/// </summary> /// </summary>
[PropertyInfo(IsNotification = true)]
private string _expression;
public string Expression { get; set; } }
public partial class SingleConditionNode : NodeModelBase
{
public SingleConditionNode(IFlowEnvironment environment):base(environment)
{
this.IsCustomData = false;
this.CustomData = null;
this.Expression = "PASS";
}
//public override object? Executing(IDynamicContext context) /// <summary>
/// 重写节点的方法执行
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public override Task<object?> ExecutingAsync(IDynamicContext context) public override Task<object?> ExecutingAsync(IDynamicContext context)
{ {
// 接收上一节点参数or自定义参数内容 // 接收上一节点参数or自定义参数内容
@@ -94,46 +110,20 @@ namespace Serein.NodeFlow.Model
public override NodeModelBase LoadInfo(NodeInfo nodeInfo) public override NodeModelBase LoadInfo(NodeInfo nodeInfo)
{ {
var node = this; var node = this;
if (node != null) node.Guid = nodeInfo.Guid;
this.Position = nodeInfo.Position;// 加载位置信息
for (int i = 0; i < nodeInfo.ParameterData.Length; i++)
{ {
node.Guid = nodeInfo.Guid; Parameterdata? pd = nodeInfo.ParameterData[i];
for (int i = 0; i < nodeInfo.ParameterData.Length; i++) node.IsCustomData = pd.State;
{ node.CustomData = pd.Value;
Parameterdata? pd = nodeInfo.ParameterData[i]; node.Expression = pd.Expression;
node.IsCustomData = pd.State;
node.CustomData = pd.Value;
node.Expression = pd.Expression;
}
} }
return this; return this;
} }
//public override void Execute(DynamicContext context)
//{
// CurrentState = Judge(context, base.MethodDetails);
//}
//private bool Judge(DynamicContext context, MethodDetails md)
//{
// try
// {
// if (DelegateCache.GlobalDicDelegates.TryGetValue(md.MethodName, out Delegate del))
// {
// object[] parameters = GetParameters(context, md);
// var temp = del.DynamicInvoke(parameters);
// //context.GetData(GetDyPreviousKey());
// return (bool)temp;
// }
// }
// catch (Exception ex)
// {
// Debug.Write(ex.Message);
// }
// return false;
//}
} }

View File

@@ -1,23 +1,32 @@
using Serein.Library; using Serein.Library;
using Serein.Library.Api; using Serein.Library.Api;
using Serein.Library.Utils.SereinExpression; using Serein.Library.Utils.SereinExpression;
using System.Reactive;
namespace Serein.NodeFlow.Model namespace Serein.NodeFlow.Model
{ {
/// <summary> /// <summary>
/// Expression Operation - 表达式操作 /// Expression Operation - 表达式操作
/// </summary> /// </summary>
public class SingleExpOpNode : NodeModelBase [NodeProperty(ValuePath = NodeValuePath.Node)]
public partial class SingleExpOpNode : NodeModelBase
{ {
public SingleExpOpNode(IFlowEnvironment environment) : base(environment)
{
}
/// <summary> /// <summary>
/// 表达式 /// 表达式
/// </summary> /// </summary>
public string Expression { get; set; } [PropertyInfo(IsNotification = true)]
private string _expression;
}
public partial class SingleExpOpNode : NodeModelBase
{
public SingleExpOpNode(IFlowEnvironment environment) : base(environment)
{
}
//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)
@@ -31,7 +40,7 @@ namespace Serein.NodeFlow.Model
object? result = null; object? result = null;
if (isChange) if (isChange)
{ {
result = newData; result = newData;
} }
else else
{ {
@@ -52,7 +61,7 @@ namespace Serein.NodeFlow.Model
public override Parameterdata[] GetParameterdatas() public override Parameterdata[] GetParameterdatas()
{ {
return [new Parameterdata{ Expression = Expression}]; return [new Parameterdata { Expression = Expression }];
} }
@@ -60,13 +69,11 @@ namespace Serein.NodeFlow.Model
public override NodeModelBase LoadInfo(NodeInfo nodeInfo) public override NodeModelBase LoadInfo(NodeInfo nodeInfo)
{ {
var node = this; var node = this;
if (node != null) this.Position = nodeInfo.Position;// 加载位置信息
node.Guid = nodeInfo.Guid;
for (int i = 0; i < nodeInfo.ParameterData.Length; i++)
{ {
node.Guid = nodeInfo.Guid; node.Expression = nodeInfo.ParameterData[i].Expression;
for (int i = 0; i < nodeInfo.ParameterData.Length; i++)
{
node.Expression = nodeInfo.ParameterData[i].Expression;
}
} }
return this; return this;
} }

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<Version>1.0.16</Version> <Version>1.0.17</Version>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
@@ -16,7 +16,10 @@
<PackageLicenseExpression>MIT</PackageLicenseExpression> <PackageLicenseExpression>MIT</PackageLicenseExpression>
<GenerateDocumentationFile>true</GenerateDocumentationFile> <GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance> <PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>.\obj\g</CompilerGeneratedFilesOutputPath>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
@@ -63,6 +66,8 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Serein.Library.MyGenerator\Serein.Library.NodeGenerator.csproj" OutputItemType="Analyzer" />
<ProjectReference Include="..\Library.Core\Serein.Library.Core.csproj" /> <ProjectReference Include="..\Library.Core\Serein.Library.Core.csproj" />
<ProjectReference Include="..\Library.Framework\Serein.Library.Framework.csproj" /> <ProjectReference Include="..\Library.Framework\Serein.Library.Framework.csproj" />
<ProjectReference Include="..\Library\Serein.Library.csproj" /> <ProjectReference Include="..\Library\Serein.Library.csproj" />

View File

@@ -6,7 +6,8 @@ namespace Serein.NodeFlow.Tool
{ {
public class ObjDynamicCreateHelper public class ObjDynamicCreateHelper
{// 类型缓存,键为类型的唯一名称(可以根据实际需求调整生成方式) {
// 类型缓存,键为类型的唯一名称(可以根据实际需求调整生成方式)
static Dictionary<string, Type> typeCache = new Dictionary<string, Type>(); static Dictionary<string, Type> typeCache = new Dictionary<string, Type>();
public static object Resolve(Dictionary<string, object> properties, string typeName) public static object Resolve(Dictionary<string, object> properties, string typeName)

View File

@@ -0,0 +1,73 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serein.Library
{
/// <summary>
/// 通过枚举来区分该怎么生成代码
/// </summary>
public enum NodeValuePath
{
/// <summary>
/// 默认值
/// </summary>
None,
/// <summary>
/// 节点本身
/// </summary>
Node,
/// <summary>
/// 节点对应的方法
/// </summary>
Method,
/// <summary>
/// 节点方法对应的入参
/// </summary>
Parameter,
/// <summary>
/// 节点的调试设置
/// </summary>
DebugSetting,
}
/// <summary>
/// 标识一个类中的某些字段需要生成相应代码
/// </summary>
[AttributeUsage(AttributeTargets.Class, Inherited = true)]
public sealed class NodePropertyAttribute : Attribute
{
/// <summary>
/// <para>属性路径</para>
/// <para>CustomNode : 自定义节点</para>
/// </summary>
public NodeValuePath ValuePath = NodeValuePath.None;
}
/// <summary>
/// 自动生成环境的属性
/// </summary>
[AttributeUsage(AttributeTargets.Field, Inherited = true)]
public sealed class PropertyInfoAttribute : Attribute
{
/// <summary>
/// 是否通知UI
/// </summary>
public bool IsNotification = false;
/// <summary>
/// 是否使用Console.WriteLine打印
/// </summary>
public bool IsPrint = false;
/// <summary>
/// 是否禁止参数进行修改(初始化后不能再通过 Setter 修改)
/// </summary>
public bool IsProtection = false;
}
}

View File

@@ -6,6 +6,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
@@ -20,6 +21,8 @@ namespace Serein.Library.NodeGenerator
[Generator] [Generator]
public class MyPropertyGenerator : IIncrementalGenerator public class MyPropertyGenerator : IIncrementalGenerator
{ {
internal static NodePropertyAttribute NodeProperty = new NodePropertyAttribute();
internal static PropertyInfoAttribute PropertyInfo = new PropertyInfoAttribute();
/// <summary> /// <summary>
/// 初始化生成器,定义需要执行的生成逻辑。 /// 初始化生成器,定义需要执行的生成逻辑。
@@ -48,7 +51,7 @@ namespace Serein.Library.NodeGenerator
// 检查类的特性列表,看看是否存在 MyClassAttribute // 检查类的特性列表,看看是否存在 MyClassAttribute
if (classDeclaration.AttributeLists if (classDeclaration.AttributeLists
.SelectMany(attrList => attrList.Attributes) .SelectMany(attrList => attrList.Attributes)
.Any(attr => semanticModel.GetSymbolInfo(attr).Symbol?.ContainingType.Name == "AutoPropertyAttribute")) .Any(attr => semanticModel.GetSymbolInfo(attr).Symbol?.ContainingType.Name == nameof(NodePropertyAttribute)))
{ {
var classSymbol = semanticModel.GetDeclaredSymbol(classDeclaration); // 获取类的符号 var classSymbol = semanticModel.GetDeclaredSymbol(classDeclaration); // 获取类的符号
var classInfo = classSymbol.BuildCacheOfClass(); var classInfo = classSymbol.BuildCacheOfClass();
@@ -127,7 +130,7 @@ namespace Serein.Library.NodeGenerator
sb.AppendLine($" public partial class {className} : System.ComponentModel.INotifyPropertyChanged"); sb.AppendLine($" public partial class {className} : System.ComponentModel.INotifyPropertyChanged");
sb.AppendLine(" {"); sb.AppendLine(" {");
var path = classInfo["AutoPropertyAttribute"]["ValuePath"]; var path = classInfo[nameof(NodePropertyAttribute)]["ValuePath"];
// //
@@ -156,10 +159,10 @@ 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("PropertyInfo", "IsProtection", "true"); // 是否为保护字段
// 生成 getter / setter // 生成 getter / setter
sb.AppendLine(leadingTrivia); sb.AppendLine(leadingTrivia);
sb.AppendLine($" public {fieldType} {propertyName}"); sb.AppendLine($" public {fieldType} {propertyName}");
@@ -169,34 +172,40 @@ 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("PropertyInfo", "IsPrint", "true")) // 是否打印 if (attributeInfo.Search(nameof(PropertyInfo), nameof(PropertyInfo.IsPrint), "true")) // 是否打印
{ {
sb.AddCode(5, $"Console.WriteLine({fieldName});"); sb.AddCode(5, $"Console.WriteLine({fieldName});");
} }
if (attributeInfo.Search("PropertyInfo", "IsNotification", "true")) // 是否通知 if (attributeInfo.Search(nameof(PropertyInfo), nameof(PropertyInfo.IsNotification), "true")) // 是否通知
{ {
if (classInfo.ExitsPath("NodeModelBase")) if (classInfo.ExitsPath(nameof(NodeValuePath.Node))) // 节点 or 自定义节点
{ {
sb.AddCode(5, $"this.env?.NotificationNodeValueChangeAsync(this.Guid, .nameof({propertyName}), value);"); sb.AddCode(5, $"((NodeModelBase)this).Env?.NotificationNodeValueChangeAsync(this.Guid, nameof({propertyName}), value); // 通知远程环境属性发生改变了");
} }
else if (classInfo.ExitsPath("MethodDetails")) else if (classInfo.ExitsPath(nameof(NodeValuePath.Method))) // 节点方法详情
{ {
sb.AddCode(5, $"nodeModel?.Env?.NotificationNodeValueChangeAsync(nodeModel.Guid, \"MethodDetails.\"+nameof({propertyName}), value);"); sb.AddCode(5, $"nodeModel?.Env?.NotificationNodeValueChangeAsync(nodeModel.Guid, \"MethodDetails.\"+nameof({propertyName}), value); // 通知远程环境属性发生改变了");
} }
else if (classInfo.ExitsPath("ParameterDetails")) else if (classInfo.ExitsPath(nameof(NodeValuePath.Parameter))) // 节点方法入参参数描述
{ {
sb.AddCode(5, "nodeModel?.Env?.NotificationNodeValueChangeAsync(nodeModel.Guid, \"MethodDetails.ParameterDetailss[\"+$\"{Index}\"+\"]." + $"\"+nameof({propertyName}),value);"); sb.AddCode(5, "nodeModel?.Env?.NotificationNodeValueChangeAsync(nodeModel.Guid, \"MethodDetails.ParameterDetailss[\"+$\"{Index}\"+\"]." + $"\"+nameof({propertyName}),value); // 通知远程环境属性发生改变了");
} }
else if (classInfo.ExitsPath("NodeDebugSetting")) else if (classInfo.ExitsPath(nameof(NodeValuePath.DebugSetting))) // 节点的调试信息
{ {
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($" {fieldName} = value;"); sb.AppendLine($" SetProperty<{fieldType}>(ref {fieldName}, value); // 通知UI属性发生改变了");
sb.AppendLine($" OnPropertyChanged(); // 先更改属性,然后通知属性发生改变了"); //sb.AppendLine($" {fieldName} = value;");
//sb.AppendLine($" OnPropertyChanged(); // 通知UI属性发生改变了");
sb.AppendLine(" }"); sb.AppendLine(" }");
sb.AppendLine(" }"); sb.AppendLine(" }");
sb.AppendLine(" }"); // 属性的结尾大括号 sb.AppendLine(" }"); // 属性的结尾大括号
//if (!isProtection && field.TryGetDefaultValue(out var defaultValue))
//{
// sb.AppendLine($" }} = {defaultValue}");
//}
} }
@@ -206,19 +215,29 @@ namespace Serein.Library.NodeGenerator
sb.AppendLine(" /// </summary>"); sb.AppendLine(" /// </summary>");
sb.AppendLine(" public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;"); sb.AppendLine(" public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;");
sb.AppendLine(" /// <summary>"); sb.AppendLine(" protected void SetProperty<T>(ref T storage, T value, [System.Runtime.CompilerServices.CallerMemberName] string propertyName = null) ");
sb.AppendLine(" /// 略"); sb.AppendLine(" { ");
sb.AppendLine(" /// <para>此方法为自动生成</para>"); sb.AppendLine(" if (Equals(storage, value)) ");
sb.AppendLine(" { ");
sb.AppendLine(" return; ");
sb.AppendLine(" } ");
sb.AppendLine(" ");
sb.AppendLine(" storage = value; ");
sb.AppendLine(" OnPropertyChanged(propertyName); ");
sb.AppendLine(" } ");
sb.AppendLine(" /// <summary> ");
sb.AppendLine(" /// 略 ");
sb.AppendLine(" /// <para>此方法为自动生成</para> ");
sb.AppendLine(" /// </summary>"); sb.AppendLine(" /// </summary>");
sb.AppendLine(" /// <param name=\"propertyName\"></param>"); sb.AppendLine(" /// <param name=\"propertyName\"></param> ");
sb.AppendLine(" "); sb.AppendLine(" ");
sb.AppendLine(" protected void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = null)"); sb.AppendLine(" protected void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = null) ");
sb.AppendLine(" {"); sb.AppendLine(" {");
//sb.AppendLine(" Console.WriteLine(\"测试:\"+ propertyName);"); //sb.AppendLine(" Console.WriteLine(\"测试:\"+ propertyName);");
sb.AppendLine(" PropertyChanged?.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));"); sb.AppendLine(" PropertyChanged?.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName)); ");
sb.AppendLine(" }"); sb.AppendLine(" }");
} }
finally finally
{ {
@@ -347,7 +366,12 @@ namespace Serein.Library.NodeGenerator
{ {
var key = cata.Key; var key = cata.Key;
var value = cata.Value.Value; var value = cata.Value.Value;
if (!attributeInfo.ContainsKey(key)) if (nameof(NodePropertyAttribute).Equals(attributeName))
{
string literal = Enum.GetName(typeof(NodeValuePath), cata.Value.Value);
attributeInfo.Add(key, literal);
}
else
{ {
attributeInfo.Add(key, value); attributeInfo.Add(key, value);
} }
@@ -374,6 +398,29 @@ namespace Serein.Library.NodeGenerator
var propertyName = fieldName.StartsWith("_") ? char.ToUpper(fieldName[1]) + fieldName.Substring(2) : char.ToUpper(fieldName[0]) + fieldName.Substring(1); // 创建属性名称 var propertyName = fieldName.StartsWith("_") ? char.ToUpper(fieldName[1]) + fieldName.Substring(2) : char.ToUpper(fieldName[0]) + fieldName.Substring(1); // 创建属性名称
return propertyName; return propertyName;
} }
/// <summary>
/// 判断字段是否有默认值
/// </summary>
/// <param name="field"></param>
/// <param name="defaultValue"></param>
/// <returns></returns>
public static bool TryGetDefaultValue(this FieldDeclarationSyntax field ,out string defaultValue)
{
if (field.Declaration.Variables.First().Initializer != null)
{
defaultValue = field.Declaration.Variables.First().Initializer.Value.ToString();
return true;
}
else
{
defaultValue = null;
return false;
}
}
/// <summary> /// <summary>
/// 判断字段是否为只读 /// 判断字段是否为只读
/// </summary> /// </summary>
@@ -500,14 +547,13 @@ namespace Serein.Library.NodeGenerator
public static bool ExitsPath(this Dictionary<string, Dictionary<string, object>> classInfo, string valuePath) public static bool ExitsPath(this Dictionary<string, Dictionary<string, object>> classInfo, string valuePath)
{ {
// var path = classInfo["AutoPropertyAttribute"]["ValuePath"];
if (!classInfo.TryGetValue(nameof(NodePropertyAttribute), out var keyValuePairs))
if (!classInfo.TryGetValue("AutoPropertyAttribute", out var keyValuePairs))
{ {
return false; return false;
} }
if (!keyValuePairs.TryGetValue("ValuePath", out var value)) if (!keyValuePairs.TryGetValue(nameof(MyPropertyGenerator.NodeProperty.ValuePath), out var value))
{ {
return false; return false;
} }

View File

@@ -1,7 +1 @@
{ {}
"profiles": {
"配置文件 2": {
"commandName": "DebugRoslynComponent"
}
}
}

View File

@@ -3,6 +3,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<IsRoslynComponent>true</IsRoslynComponent> <IsRoslynComponent>true</IsRoslynComponent>
<BaseOutputPath>D:\Project\C#\DynamicControl\SereinFlow\.Output</BaseOutputPath> <BaseOutputPath>D:\Project\C#\DynamicControl\SereinFlow\.Output</BaseOutputPath>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild> <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<Title>SereinFow</Title> <Title>SereinFow</Title>
@@ -12,7 +13,6 @@
<PackageLicenseExpression>MIT</PackageLicenseExpression> <PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance> <PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
<GenerateDocumentationFile>true</GenerateDocumentationFile> <GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.11.0" PrivateAssets="all" /> <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.11.0" PrivateAssets="all" />

View File

@@ -10,7 +10,9 @@ namespace Serein.Workbench
/// </summary> /// </summary>
public partial class App : Application public partial class App : Application
{ {
#if DEBUG
#endif
public static SereinProjectData? FlowProjectData { get; set; } public static SereinProjectData? FlowProjectData { get; set; }
public static string FileDataPath { get; set; } = ""; public static string FileDataPath { get; set; } = "";
@@ -66,7 +68,7 @@ namespace Serein.Workbench
} }
#if DEBUG #if DEBUG
else if(1 == 1) else if(1 == 11)
{ {
//string filePath = @"F:\临时\project\new project.dnf"; //string filePath = @"F:\临时\project\new project.dnf";

View File

@@ -461,6 +461,11 @@ namespace Serein.Workbench
return; return;
} }
if(nodeModelBase is null)
{
Console.WriteLine("OnNodeCreateEvent事件接收到意外的返回值");
return;
}
// MethodDetails methodDetailss = eventArgs.MethodDetailss; // MethodDetails methodDetailss = eventArgs.MethodDetailss;
PositionOfUI position = eventArgs.Position; PositionOfUI position = eventArgs.Position;
@@ -577,15 +582,15 @@ namespace Serein.Workbench
{ {
string nodeGuid = eventArgs.NodeGuid; string nodeGuid = eventArgs.NodeGuid;
if (!TryGetControl(nodeGuid, out var nodeControl)) return; if (!TryGetControl(nodeGuid, out var nodeControl)) return;
if (eventArgs.Class == InterruptClass.None)
{
nodeControl.ViewModel.IsInterrupt = false;
} //if (eventArgs.Class == InterruptClass.None)
else //{
{ // nodeControl.ViewModel.IsInterrupt = false;
nodeControl.ViewModel.IsInterrupt = true; //}
} //else
//{
// nodeControl.ViewModel.IsInterrupt = true;
//}
foreach (var menuItem in nodeControl.ContextMenu.Items) foreach (var menuItem in nodeControl.ContextMenu.Items)
{ {
@@ -1203,35 +1208,48 @@ namespace Serein.Workbench
/// </summary> /// </summary>
/// <param name="sender"></param> /// <param name="sender"></param>
/// <param name="e"></param> /// <param name="e"></param>
private async void FlowChartCanvas_Drop(object sender, DragEventArgs e) private void FlowChartCanvas_Drop(object sender, DragEventArgs e)
{ {
var canvasDropPosition = e.GetPosition(FlowChartCanvas); // 更新画布落点 try
PositionOfUI position = new PositionOfUI(canvasDropPosition.X, canvasDropPosition.Y);
if (e.Data.GetDataPresent(MouseNodeType.CreateDllNodeInCanvas))
{ {
if (e.Data.GetData(MouseNodeType.CreateDllNodeInCanvas) is MoveNodeData nodeData) var canvasDropPosition = e.GetPosition(FlowChartCanvas); // 更新画布落点
PositionOfUI position = new PositionOfUI(canvasDropPosition.X, canvasDropPosition.Y);
if (e.Data.GetDataPresent(MouseNodeType.CreateDllNodeInCanvas))
{ {
await EnvDecorator.CreateNodeAsync(nodeData.NodeControlType, position, nodeData.MethodDetailsInfo); // 创建DLL文件的节点对象 if (e.Data.GetData(MouseNodeType.CreateDllNodeInCanvas) is MoveNodeData nodeData)
}
}
else if (e.Data.GetDataPresent(MouseNodeType.CreateBaseNodeInCanvas))
{
if (e.Data.GetData(MouseNodeType.CreateBaseNodeInCanvas) is Type droppedType)
{
NodeControlType nodeControlType = droppedType switch
{ {
Type when typeof(ConditionRegionControl).IsAssignableFrom(droppedType) => NodeControlType.ConditionRegion, // 条件区域 Task.Run(async () =>
Type when typeof(ConditionNodeControl).IsAssignableFrom(droppedType) => NodeControlType.ExpCondition, {
Type when typeof(ExpOpNodeControl).IsAssignableFrom(droppedType) => NodeControlType.ExpOp, await EnvDecorator.CreateNodeAsync(nodeData.NodeControlType, position, nodeData.MethodDetailsInfo); // 创建DLL文件的节点对象
_ => NodeControlType.None, });
};
if(nodeControlType != NodeControlType.None)
{
await EnvDecorator.CreateNodeAsync(nodeControlType, position); // 创建基础节点对象
} }
} }
else if (e.Data.GetDataPresent(MouseNodeType.CreateBaseNodeInCanvas))
{
if (e.Data.GetData(MouseNodeType.CreateBaseNodeInCanvas) is Type droppedType)
{
NodeControlType nodeControlType = droppedType switch
{
Type when typeof(ConditionRegionControl).IsAssignableFrom(droppedType) => NodeControlType.ConditionRegion, // 条件区域
Type when typeof(ConditionNodeControl).IsAssignableFrom(droppedType) => NodeControlType.ExpCondition,
Type when typeof(ExpOpNodeControl).IsAssignableFrom(droppedType) => NodeControlType.ExpOp,
_ => NodeControlType.None,
};
if (nodeControlType != NodeControlType.None)
{
Task.Run(async () =>
{
await EnvDecorator.CreateNodeAsync(nodeControlType, position); // 创建基础节点对象
});
}
}
}
e.Handled = true;
}
catch (Exception ex)
{
Console.WriteLine(ex);
} }
e.Handled = true;
} }
/// <summary> /// <summary>
@@ -1897,7 +1915,7 @@ namespace Serein.Workbench
//Console.WriteLine($"一共选取了{selectNodeControls.Count}个控件"); //Console.WriteLine($"一共选取了{selectNodeControls.Count}个控件");
foreach (var node in selectNodeControls) foreach (var node in selectNodeControls)
{ {
node.ViewModel.IsSelect =true; //node.ViewModel.IsSelect =true;
// node.ViewModel.CancelSelect(); // node.ViewModel.CancelSelect();
node.BorderBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#FFC700")); node.BorderBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#FFC700"));
node.BorderThickness = new Thickness(4); node.BorderThickness = new Thickness(4);
@@ -1908,7 +1926,7 @@ namespace Serein.Workbench
IsSelectControl = false; IsSelectControl = false;
foreach (var nodeControl in selectNodeControls) foreach (var nodeControl in selectNodeControls)
{ {
nodeControl.ViewModel.IsSelect = false; //nodeControl.ViewModel.IsSelect = false;
nodeControl.BorderBrush = Brushes.Black; nodeControl.BorderBrush = Brushes.Black;
nodeControl.BorderThickness = new Thickness(0); nodeControl.BorderThickness = new Thickness(0);
if (nodeControl.ViewModel.NodeModel.IsStart) if (nodeControl.ViewModel.NodeModel.IsStart)

View File

@@ -40,6 +40,7 @@ namespace Serein.Workbench
else else
{ {
FlowEnvironment = new FlowEnvironmentDecorator(uIContextOperation); FlowEnvironment = new FlowEnvironmentDecorator(uIContextOperation);
//_ = FlowEnvironment.StartRemoteServerAsync();
this.window = window; this.window = window;
} }
} }

View File

@@ -9,83 +9,97 @@ namespace Serein.Workbench.Node.ViewModel
public NodeControlViewModelBase(NodeModelBase nodeModel) public NodeControlViewModelBase(NodeModelBase nodeModel)
{ {
NodeModel = nodeModel; NodeModel = nodeModel;
MethodDetails = NodeModel.MethodDetails;
// 订阅来自 NodeModel 的通知事件 // 订阅来自 NodeModel 的通知事件
} }
private NodeModelBase _nodeModelBase;
/// <summary> /// <summary>
/// 对应的节点实体类 /// 对应的节点实体类
/// </summary> /// </summary>
internal NodeModelBase NodeModel { get; } public NodeModelBase NodeModel
private bool isSelect;
/// <summary>
/// 表示节点控件是否被选中
/// </summary>
internal bool IsSelect
{ {
get => isSelect; get => _nodeModelBase; set
set
{ {
isSelect = value; if (value != null)
OnPropertyChanged(); {
_nodeModelBase = value;
OnPropertyChanged();
}
} }
} }
//private bool isSelect;
///// <summary>
///// 表示节点控件是否被选中
///// </summary>
//internal bool IsSelect
//{
// get => isSelect;
// set
// {
// isSelect = value;
// OnPropertyChanged();
// }
//}
//private bool isInterrupt;
/////// <summary>
/////// 控制中断状态的视觉效果
/////// </summary>
//public bool IsInterrupt
//{
// get => NodeModel.DebugSetting.IsInterrupt;
// set
// {
// NodeModel.DebugSetting.IsInterrupt = value;
// OnPropertyChanged();
// }
//}
public event PropertyChangedEventHandler? PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
//Console.WriteLine(propertyName);
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
/// <summary> /// <summary>
/// 使节点获得中断能力(以及是否启用节点) /// 使节点获得中断能力(以及是否启用节点)
/// </summary> /// </summary>
public NodeDebugSetting DebugSetting //public NodeDebugSetting DebugSetting
{ //{
get => NodeModel.DebugSetting; // get => Node.DebugSetting;
set // set
{ // {
if (value != null) // if (value != null)
{ // {
NodeModel.DebugSetting = value; // Node.DebugSetting = value;
OnPropertyChanged(); // OnPropertyChanged();
} // }
} // }
} //}
/// <summary> /// <summary>
/// 使节点能够表达方法信息 /// 使节点能够表达方法信息
/// </summary> /// </summary>
public MethodDetails MethodDetails //public MethodDetails MethodDetails
{ //{
get => NodeModel.MethodDetails; // get => Node.MethodDetails;
set // set
{ // {
if(value != null) // if(value != null)
{ // {
NodeModel.MethodDetails = value; // Node.MethodDetails = value;
OnPropertyChanged(); // OnPropertyChanged();
} // }
} // }
} //}
private bool isInterrupt;
/// <summary>
/// 控制中断状态的视觉效果
/// </summary>
public bool IsInterrupt
{
get => isInterrupt;
set
{
isInterrupt = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler? PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
} }
} }

View File

@@ -21,17 +21,20 @@
<Grid> <Grid>
<Grid.ToolTip> <Grid.ToolTip>
<ToolTip Background="LightYellow" Foreground="#071042" Content="{Binding MethodDetails.MethodTips, UpdateSourceTrigger=PropertyChanged}" /> <ToolTip Background="LightYellow" Foreground="#071042" Content="{Binding NodeModel.MethodDetails.MethodTips}" />
</Grid.ToolTip> </Grid.ToolTip>
<Border>
<!--<TextBlock Text="{Binding NodelModel.DebugSetting.IsInterrupt}}"></TextBlock>-->
<Border x:Name="InterruptBorder">
<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 IsInterrupt}" Value="True"> <DataTrigger Binding="{Binding Path=NodeModel.DebugSetting.IsInterrupt}" 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" />
@@ -48,15 +51,16 @@
</Grid.RowDefinitions> </Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal" Background="#8DE9FD"> <StackPanel Grid.Row="0" Orientation="Horizontal" Background="#8DE9FD">
<CheckBox IsChecked="{Binding DebugSetting.IsEnable, Mode=TwoWay}" VerticalContentAlignment="Center"/> <CheckBox IsChecked="{Binding NodeModel.DebugSetting.IsEnable, Mode=TwoWay}" VerticalContentAlignment="Center"/>
<CheckBox IsChecked="{Binding MethodDetails.IsProtectionParameter, Mode=TwoWay}" VerticalContentAlignment="Center"/> <CheckBox IsChecked="{Binding NodeModel.MethodDetails.IsProtectionParameter, Mode=TwoWay}" VerticalContentAlignment="Center"/>
<TextBlock Text="{Binding MethodDetails.MethodTips}" HorizontalAlignment="Center" VerticalAlignment="Center"/> <TextBlock Text="{Binding NodeModel.MethodDetails.MethodTips, Mode=TwoWay}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</StackPanel> </StackPanel>
<themes:MethodDetailsControl Grid.Row="1" MethodDetails="{Binding MethodDetails}"/> <themes:MethodDetailsControl Grid.Row="1" MethodDetails="{Binding NodeModel.MethodDetails}"/>
<!-- ParameterProtectionMask 参数保护 --> <!-- ParameterProtectionMask 参数保护 -->
<!--取反 Visibility="{Binding DebugSetting.IsEnable, Converter={StaticResource InvertedBoolConverter}, ConverterParameter=Inverted}"--> <!--取反 Visibility="{Binding DebugSetting.IsEnable, Converter={StaticResource InvertedBoolConverter}, ConverterParameter=Inverted}"-->
<Border Grid.Row="1" x:Name="ParameterProtectionMask" Background="LightBlue" Opacity="0.5" BorderBrush="#0A4651" BorderThickness="0" <Border Grid.Row="1" x:Name="ParameterProtectionMask" Background="LightBlue" Opacity="0.5" BorderBrush="#0A4651" BorderThickness="0"
Visibility="{Binding MethodDetails.IsProtectionParameter, Converter={StaticResource InvertedBoolConverter},ConverterParameter=Normal}" /> Visibility="{Binding NodeModel.MethodDetails.IsProtectionParameter, Mode=TwoWay,
Converter={StaticResource InvertedBoolConverter},ConverterParameter=Normal}" />
<Grid Grid.Row="2" Background="#D5F0FC" > <Grid Grid.Row="2" Background="#D5F0FC" >
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="50"/> <ColumnDefinition Width="50"/>
@@ -66,7 +70,7 @@
<TextBlock Text="result" HorizontalAlignment="Center" VerticalAlignment="Center" /> <TextBlock Text="result" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border> </Border>
<Border Grid.Column="1" BorderThickness="1"> <Border Grid.Column="1" BorderThickness="1">
<TextBlock Text="{Binding MethodDetails.ReturnType}" HorizontalAlignment="Left" VerticalAlignment="Center"/> <TextBlock Text="{Binding NodeModel.MethodDetails.ReturnType, Mode=TwoWay}" HorizontalAlignment="Left" VerticalAlignment="Center"/>
</Border> </Border>
</Grid> </Grid>

View File

@@ -17,7 +17,7 @@
<Grid> <Grid>
<Grid.ToolTip> <Grid.ToolTip>
<ToolTip Background="LightYellow" Foreground="Black" Content="{Binding MethodDetails.MethodTips, UpdateSourceTrigger=PropertyChanged}" /> <ToolTip Background="LightYellow" Foreground="Black" Content="{Binding NodeModel.MethodDetails.MethodTips, UpdateSourceTrigger=PropertyChanged}" />
</Grid.ToolTip> </Grid.ToolTip>
<Grid.RowDefinitions> <Grid.RowDefinitions>
@@ -33,14 +33,14 @@
<ColumnDefinition Width="20"/> <ColumnDefinition Width="20"/>
<ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<CheckBox Grid.Column="0" IsChecked="{Binding IsCustomData, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/> <!--Converter={StaticResource BoolToVis}--> <CheckBox Grid.Column="0" IsChecked="{Binding NodeModel.IsCustomData, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/> <!--Converter={StaticResource BoolToVis}-->
<TextBox Grid.Column="1" MinWidth="50" Text="{Binding CustomData, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" <TextBox Grid.Column="1" MinWidth="50" Text="{Binding NodeModel.CustomData, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
HorizontalAlignment="Stretch" VerticalAlignment="Center"> HorizontalAlignment="Stretch" VerticalAlignment="Center">
<TextBox.Style> <TextBox.Style>
<Style TargetType="TextBox"> <Style TargetType="TextBox">
<Setter Property="Visibility" Value="Collapsed" /> <Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers> <Style.Triggers>
<DataTrigger Binding="{Binding IsCustomData}" Value="True"> <DataTrigger Binding="{Binding NodeModel.IsCustomData}" Value="True">
<Setter Property="Visibility" Value="Visible" /> <Setter Property="Visibility" Value="Visible" />
</DataTrigger> </DataTrigger>
</Style.Triggers> </Style.Triggers>
@@ -53,7 +53,7 @@
<Style TargetType="TextBlock"> <Style TargetType="TextBlock">
<Setter Property="Visibility" Value="Collapsed" /> <Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers> <Style.Triggers>
<DataTrigger Binding="{Binding IsCustomData}" Value="False"> <DataTrigger Binding="{Binding NodeModel.IsCustomData}" Value="False">
<Setter Property="Visibility" Value="Visible" /> <Setter Property="Visibility" Value="Visible" />
</DataTrigger> </DataTrigger>
</Style.Triggers> </Style.Triggers>
@@ -61,7 +61,7 @@
</TextBlock.Style> </TextBlock.Style>
</TextBlock> </TextBlock>
</Grid> </Grid>
<TextBox Grid.Row="2" Background="#f1F66F" MinWidth="100" Text="{Binding Expression, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" <TextBox Grid.Row="2" Background="#f1F66F" MinWidth="100" Text="{Binding NodeModel.Expression, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
HorizontalAlignment="Stretch" VerticalAlignment="Center"/> HorizontalAlignment="Stretch" VerticalAlignment="Center"/>
<!--<themes:MethodDetailsControl Grid.Row="1" MethodDetails="{Binding MethodDetails}" /> <!--<themes:MethodDetailsControl Grid.Row="1" MethodDetails="{Binding MethodDetails}" />

View File

@@ -16,7 +16,7 @@
<StackPanel Grid.Row="0" Orientation="Vertical" Background="LightSteelBlue"> <StackPanel Grid.Row="0" Orientation="Vertical" Background="LightSteelBlue">
<TextBlock Grid.Row="2" Text="表达式"></TextBlock> <TextBlock Grid.Row="2" Text="表达式"></TextBlock>
<TextBox Text="{Binding Expression, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Stretch"></TextBox> <TextBox Text="{Binding NodeModel.Expression, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Stretch"></TextBox>
</StackPanel> </StackPanel>
</Grid> </Grid>
</local:NodeControlBase> </local:NodeControlBase>

View File

@@ -22,7 +22,7 @@
<Grid> <Grid>
<Grid.ToolTip> <Grid.ToolTip>
<ToolTip Background="LightYellow" Foreground="#071042" Content="{Binding MethodDetails.MethodName, UpdateSourceTrigger=PropertyChanged}" /> <ToolTip Background="LightYellow" Foreground="#071042" Content="{Binding NodeModel.MethodDetails.MethodName, UpdateSourceTrigger=PropertyChanged}" />
</Grid.ToolTip> </Grid.ToolTip>
<Grid.RowDefinitions> <Grid.RowDefinitions>
@@ -32,15 +32,16 @@
</Grid.RowDefinitions> </Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal" Background="#FCB334"> <StackPanel Grid.Row="0" Orientation="Horizontal" Background="#FCB334">
<CheckBox IsChecked="{Binding DebugSetting.IsEnable, Mode=TwoWay}" VerticalContentAlignment="Center"/> <CheckBox IsChecked="{Binding NodeModel.DebugSetting.IsEnable, Mode=TwoWay}" VerticalContentAlignment="Center"/>
<CheckBox IsChecked="{Binding MethodDetails.IsProtectionParameter, Mode=TwoWay}" VerticalContentAlignment="Center"/> <CheckBox IsChecked="{Binding NodeModel.MethodDetails.IsProtectionParameter, Mode=TwoWay}" VerticalContentAlignment="Center"/>
<TextBlock Text="{Binding MethodDetails.MethodTips, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center" VerticalAlignment="Center"/> <TextBlock Text="{Binding NodeModel.MethodDetails.MethodTips, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</StackPanel> </StackPanel>
<themes:MethodDetailsControl Grid.Row="1" MethodDetails="{Binding MethodDetails}" />
<themes:MethodDetailsControl Grid.Row="1" MethodDetails="{Binding NodeModel.MethodDetails}" />
<Border Grid.Row="1" x:Name="ParameterProtectionMask" Background="LightBlue" Opacity="0.5" BorderBrush="#0A4651" BorderThickness="0" <Border Grid.Row="1" x:Name="ParameterProtectionMask" Background="LightBlue" Opacity="0.5" BorderBrush="#0A4651" BorderThickness="0"
Visibility="{Binding MethodDetails.IsProtectionParameter, Converter={StaticResource InvertedBoolConverter},ConverterParameter=Normal}" /> Visibility="{Binding NodeModel.MethodDetails.IsProtectionParameter, Converter={StaticResource InvertedBoolConverter},ConverterParameter=Normal}" />
<!--<Border Grid.Row="0" Background="#FCB334" > <!--<Border Grid.Row="0" Background="#FCB334" >
</Border>--> </Border>-->
@@ -54,7 +55,7 @@
<TextBlock Text="result" HorizontalAlignment="Center" VerticalAlignment="Center"/> <TextBlock Text="result" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border> </Border>
<Border Grid.Column="1" BorderThickness="1"> <Border Grid.Column="1" BorderThickness="1">
<TextBlock Text="{Binding MethodDetails.ReturnType}" HorizontalAlignment="Left" VerticalAlignment="Center"/> <TextBlock Text="{Binding NodeModel.MethodDetails.ReturnType}" HorizontalAlignment="Left" VerticalAlignment="Center"/>
</Border> </Border>
</Grid> </Grid>
<!--<themes:ConditionControl Grid.Row="2" ></themes:ConditionControl>--> <!--<themes:ConditionControl Grid.Row="2" ></themes:ConditionControl>-->

View File

@@ -1,4 +1,5 @@
using Serein.Library.Api; using Serein.Library;
using Serein.Library.Api;
using Serein.Workbench.Node.ViewModel; using Serein.Workbench.Node.ViewModel;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Media; using System.Windows.Media;
@@ -13,9 +14,8 @@ namespace Serein.Workbench.Node.View
{ {
public NodeControlViewModelBase ViewModel { get; set; } public NodeControlViewModelBase ViewModel { get; set; }
protected NodeControlBase() protected NodeControlBase()
{ {
this.Background = Brushes.Transparent; this.Background = Brushes.Transparent;
} }
@@ -23,6 +23,7 @@ namespace Serein.Workbench.Node.View
{ {
ViewModel = viewModelBase; ViewModel = viewModelBase;
this.Background = Brushes.Transparent; this.Background = Brushes.Transparent;
this.DataContext = viewModelBase;
} }
} }

View File

@@ -5,11 +5,20 @@ namespace Serein.Workbench.Node.ViewModel
{ {
public class ActionNodeControlViewModel : NodeControlViewModelBase public class ActionNodeControlViewModel : NodeControlViewModelBase
{ {
private readonly SingleActionNode node; //public SingleActionNode NodelModel
//{
// get => (SingleActionNode)base.NodeModel; set
// {
// if (base.NodeModel == null)
// {
// base.NodeModel = value;
// }
// }
//}
public ActionNodeControlViewModel(SingleActionNode node):base(node) public ActionNodeControlViewModel(SingleActionNode node):base(node)
{ {
this.node = node; // this.NodelModel = node;
} }
} }
} }

View File

@@ -8,32 +8,32 @@ namespace Serein.Workbench.Node.ViewModel
/// </summary> /// </summary>
public class ConditionNodeControlViewModel : NodeControlViewModelBase public class ConditionNodeControlViewModel : NodeControlViewModelBase
{ {
private readonly SingleConditionNode singleConditionNode; public new SingleConditionNode NodeModel { get; }
/// <summary> ///// <summary>
/// 是否为自定义参数 ///// 是否为自定义参数
/// </summary> ///// </summary>
public bool IsCustomData //public bool IsCustomData
{ //{
get => singleConditionNode.IsCustomData; // get => Node.IsCustomData;
set { singleConditionNode.IsCustomData= value; OnPropertyChanged(); } // set { Node.IsCustomData= value; OnPropertyChanged(); }
} //}
/// <summary> ///// <summary>
/// 自定义参数值 // /// 自定义参数值
/// </summary> // /// </summary>
public object? CustomData //public object? CustomData
{ //{
get => singleConditionNode.CustomData; // get => Node.CustomData;
set { singleConditionNode.CustomData = value ; OnPropertyChanged(); } // set { Node.CustomData = value ; OnPropertyChanged(); }
} //}
/// <summary> ///// <summary>
/// 表达式 ///// 表达式
/// </summary> ///// </summary>
public string Expression //public string Expression
{ //{
get => singleConditionNode.Expression; // get => Node.Expression;
set { singleConditionNode.Expression = value; OnPropertyChanged(); } // set { Node.Expression = value; OnPropertyChanged(); }
} //}
/// <summary> /// <summary>
/// 条件节点 /// 条件节点
@@ -41,7 +41,7 @@ namespace Serein.Workbench.Node.ViewModel
/// <param name="node"></param> /// <param name="node"></param>
public ConditionNodeControlViewModel(SingleConditionNode node) : base(node) public ConditionNodeControlViewModel(SingleConditionNode node) : base(node)
{ {
this.singleConditionNode = node; this.NodeModel = node;
//IsCustomData = false; //IsCustomData = false;
//CustomData = ""; //CustomData = "";
//Expression = "PASS"; //Expression = "PASS";

View File

@@ -5,22 +5,22 @@ namespace Serein.Workbench.Node.ViewModel
{ {
public class ExpOpNodeViewModel: NodeControlViewModelBase public class ExpOpNodeViewModel: NodeControlViewModelBase
{ {
public readonly SingleExpOpNode node; public new SingleExpOpNode NodeModel { get; }
public string Expression //public string Expression
{ //{
get => node.Expression; // get => node.Expression;
set // set
{ // {
node.Expression = value; // node.Expression = value;
OnPropertyChanged(); // OnPropertyChanged();
} // }
} //}
public ExpOpNodeViewModel(SingleExpOpNode node) : base(node) public ExpOpNodeViewModel(SingleExpOpNode nodeModel) : base(nodeModel)
{ {
this.node = node; this.NodeModel = nodeModel;
} }
} }
} }

View File

@@ -5,10 +5,10 @@ namespace Serein.Workbench.Node.ViewModel
{ {
public class FlipflopNodeControlViewModel : NodeControlViewModelBase public class FlipflopNodeControlViewModel : NodeControlViewModelBase
{ {
private readonly SingleFlipflopNode node; public new SingleFlipflopNode NodelModel { get;}
public FlipflopNodeControlViewModel(SingleFlipflopNode node) : base(node) public FlipflopNodeControlViewModel(SingleFlipflopNode node) : base(node)
{ {
this.node = node; this.NodelModel = node;
} }
} }
} }

View File

@@ -0,0 +1,292 @@
<Project>
<PropertyGroup>
<AssemblyName>Serein.Workbench</AssemblyName>
<IntermediateOutputPath>obj\Release\</IntermediateOutputPath>
<BaseIntermediateOutputPath>obj\</BaseIntermediateOutputPath>
<MSBuildProjectExtensionsPath>D:\Project\C#\DynamicControl\SereinFlow\WorkBench\obj\</MSBuildProjectExtensionsPath>
<_TargetAssemblyProjectName>Serein.Workbench</_TargetAssemblyProjectName>
<RootNamespace>Serein.Workbench</RootNamespace>
</PropertyGroup>
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UseWPF>True</UseWPF>
<BaseOutputPath>D:\Project\C#\DynamicControl\SereinFlow\.Output</BaseOutputPath>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<!--<IsRoslynComponent>true</IsRoslynComponent>-->
</PropertyGroup>
<ItemGroup>
<Compile Remove="Node\NodeModel\**" />
<Compile Remove="Themes\Condition\**" />
<EmbeddedResource Remove="Node\NodeModel\**" />
<EmbeddedResource Remove="Themes\Condition\**" />
<None Remove="Node\NodeModel\**" />
<None Remove="Themes\Condition\**" />
</ItemGroup>
<ItemGroup>
<Compile Remove="Node\FlipflopRegionControl.xaml.cs" />
<Compile Remove="Node\NodeBase.cs" />
<Compile Remove="Themes\ConditionControl.xaml.cs" />
<Compile Remove="Themes\ConditionControlModel.cs" />
<Compile Remove="Themes\ExplicitDataControl.xaml.cs" />
<Compile Remove="Themes\ObjectViewerControl1.xaml.cs" />
</ItemGroup>
<ItemGroup>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Library.Core\Serein.Library.Core.csproj" />
<ProjectReference Include="..\Library.Framework\Serein.Library.Framework.csproj" />
<ProjectReference Include="..\Library\Serein.Library.csproj" />
<ProjectReference Include="..\NodeFlow\Serein.NodeFlow.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
<ItemGroup>
<Compile Update="Themes\MethodDetailsControl.xaml.cs">
<SubType>Code</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\8.0.10\ref\net8.0\Accessibility.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\Microsoft.CSharp.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\Microsoft.VisualBasic.Core.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\Microsoft.VisualBasic.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\Microsoft.Win32.Primitives.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\8.0.10\ref\net8.0\Microsoft.Win32.Registry.AccessControl.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\Microsoft.Win32.Registry.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\8.0.10\ref\net8.0\Microsoft.Win32.SystemEvents.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\mscorlib.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\netstandard.dll" />
<ReferencePath Include="C:\Users\Az\.nuget\packages\newtonsoft.json\13.0.3\lib\net6.0\Newtonsoft.Json.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\8.0.10\ref\net8.0\PresentationCore.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\8.0.10\ref\net8.0\PresentationFramework.Aero.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\8.0.10\ref\net8.0\PresentationFramework.Aero2.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\8.0.10\ref\net8.0\PresentationFramework.AeroLite.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\8.0.10\ref\net8.0\PresentationFramework.Classic.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\8.0.10\ref\net8.0\PresentationFramework.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\8.0.10\ref\net8.0\PresentationFramework.Luna.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\8.0.10\ref\net8.0\PresentationFramework.Royale.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\8.0.10\ref\net8.0\PresentationUI.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\8.0.10\ref\net8.0\ReachFramework.dll" />
<ReferencePath Include="D:\Project\C#\DynamicControl\SereinFlow\.Output\Release\net8.0\Serein.Library.Core.dll" />
<ReferencePath Include="D:\Project\C#\DynamicControl\SereinFlow\.Output\Release\net8.0\Serein.Library.dll" />
<ReferencePath Include="D:\Project\C#\DynamicControl\SereinFlow\.Output\Release\librarynet462\Serein.Library.Framework.dll" />
<ReferencePath Include="D:\Project\C#\DynamicControl\SereinFlow\.Output\Release\netstandard2.0\Serein.Library.NodeGenerator.dll" />
<ReferencePath Include="D:\Project\C#\DynamicControl\SereinFlow\.Output\Release\net8.0\Serein.NodeFlow.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.AppContext.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Buffers.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\8.0.10\ref\net8.0\System.CodeDom.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Collections.Concurrent.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Collections.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Collections.Immutable.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Collections.NonGeneric.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Collections.Specialized.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.ComponentModel.Annotations.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.ComponentModel.DataAnnotations.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.ComponentModel.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.ComponentModel.EventBasedAsync.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.ComponentModel.Primitives.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.ComponentModel.TypeConverter.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\8.0.10\ref\net8.0\System.Configuration.ConfigurationManager.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Configuration.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Console.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Core.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Data.Common.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Data.DataSetExtensions.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Data.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Diagnostics.Contracts.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Diagnostics.Debug.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Diagnostics.DiagnosticSource.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\8.0.10\ref\net8.0\System.Diagnostics.EventLog.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Diagnostics.FileVersionInfo.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\8.0.10\ref\net8.0\System.Diagnostics.PerformanceCounter.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Diagnostics.Process.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Diagnostics.StackTrace.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Diagnostics.TextWriterTraceListener.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Diagnostics.Tools.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Diagnostics.TraceSource.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Diagnostics.Tracing.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\8.0.10\ref\net8.0\System.DirectoryServices.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Drawing.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Drawing.Primitives.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Dynamic.Runtime.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Formats.Asn1.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Formats.Tar.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Globalization.Calendars.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Globalization.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Globalization.Extensions.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.IO.Compression.Brotli.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.IO.Compression.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.IO.Compression.FileSystem.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.IO.Compression.ZipFile.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.IO.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.IO.FileSystem.AccessControl.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.IO.FileSystem.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.IO.FileSystem.DriveInfo.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.IO.FileSystem.Primitives.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.IO.FileSystem.Watcher.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.IO.IsolatedStorage.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.IO.MemoryMappedFiles.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\8.0.10\ref\net8.0\System.IO.Packaging.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.IO.Pipes.AccessControl.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.IO.Pipes.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.IO.UnmanagedMemoryStream.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Linq.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Linq.Expressions.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Linq.Parallel.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Linq.Queryable.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Memory.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Net.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Net.Http.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Net.Http.Json.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Net.HttpListener.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Net.Mail.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Net.NameResolution.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Net.NetworkInformation.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Net.Ping.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Net.Primitives.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Net.Quic.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Net.Requests.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Net.Security.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Net.ServicePoint.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Net.Sockets.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Net.WebClient.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Net.WebHeaderCollection.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Net.WebProxy.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Net.WebSockets.Client.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Net.WebSockets.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Numerics.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Numerics.Vectors.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.ObjectModel.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\8.0.10\ref\net8.0\System.Printing.dll" />
<ReferencePath Include="C:\Users\Az\.nuget\packages\system.reactive\6.0.1\lib\net6.0\System.Reactive.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Reflection.DispatchProxy.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Reflection.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Reflection.Emit.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Reflection.Emit.ILGeneration.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Reflection.Emit.Lightweight.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Reflection.Extensions.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Reflection.Metadata.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Reflection.Primitives.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Reflection.TypeExtensions.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\8.0.10\ref\net8.0\System.Resources.Extensions.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Resources.Reader.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Resources.ResourceManager.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Resources.Writer.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Runtime.CompilerServices.Unsafe.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Runtime.CompilerServices.VisualC.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Runtime.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Runtime.Extensions.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Runtime.Handles.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Runtime.InteropServices.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Runtime.InteropServices.JavaScript.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Runtime.InteropServices.RuntimeInformation.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Runtime.Intrinsics.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Runtime.Loader.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Runtime.Numerics.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Runtime.Serialization.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Runtime.Serialization.Formatters.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Runtime.Serialization.Json.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Runtime.Serialization.Primitives.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Runtime.Serialization.Xml.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Security.AccessControl.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Security.Claims.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Security.Cryptography.Algorithms.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Security.Cryptography.Cng.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Security.Cryptography.Csp.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Security.Cryptography.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Security.Cryptography.Encoding.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Security.Cryptography.OpenSsl.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\8.0.10\ref\net8.0\System.Security.Cryptography.Pkcs.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Security.Cryptography.Primitives.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\8.0.10\ref\net8.0\System.Security.Cryptography.ProtectedData.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Security.Cryptography.X509Certificates.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\8.0.10\ref\net8.0\System.Security.Cryptography.Xml.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Security.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\8.0.10\ref\net8.0\System.Security.Permissions.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Security.Principal.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Security.Principal.Windows.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Security.SecureString.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.ServiceModel.Web.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.ServiceProcess.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Text.Encoding.CodePages.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Text.Encoding.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Text.Encoding.Extensions.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Text.Encodings.Web.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Text.Json.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Text.RegularExpressions.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\8.0.10\ref\net8.0\System.Threading.AccessControl.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Threading.Channels.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Threading.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Threading.Overlapped.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Threading.Tasks.Dataflow.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Threading.Tasks.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Threading.Tasks.Extensions.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Threading.Tasks.Parallel.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Threading.Thread.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Threading.ThreadPool.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Threading.Timer.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Transactions.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Transactions.Local.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.ValueTuple.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Web.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Web.HttpUtility.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\8.0.10\ref\net8.0\System.Windows.Controls.Ribbon.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Windows.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\8.0.10\ref\net8.0\System.Windows.Extensions.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\8.0.10\ref\net8.0\System.Windows.Input.Manipulations.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\8.0.10\ref\net8.0\System.Windows.Presentation.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\8.0.10\ref\net8.0\System.Xaml.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Xml.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Xml.Linq.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Xml.ReaderWriter.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Xml.Serialization.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Xml.XDocument.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Xml.XmlDocument.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Xml.XmlSerializer.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Xml.XPath.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\ref\net8.0\System.Xml.XPath.XDocument.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\8.0.10\ref\net8.0\UIAutomationClient.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\8.0.10\ref\net8.0\UIAutomationClientSideProviders.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\8.0.10\ref\net8.0\UIAutomationProvider.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\8.0.10\ref\net8.0\UIAutomationTypes.dll" />
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\8.0.10\ref\net8.0\WindowsBase.dll" />
</ItemGroup>
<ItemGroup>
<Compile Include="D:\Project\C#\DynamicControl\SereinFlow\WorkBench\obj\Release\net8.0-windows\LogWindow.g.cs" />
<Compile Include="D:\Project\C#\DynamicControl\SereinFlow\WorkBench\obj\Release\net8.0-windows\MainWindow.g.cs" />
<Compile Include="D:\Project\C#\DynamicControl\SereinFlow\WorkBench\obj\Release\net8.0-windows\Node\View\ActionNodeControl.g.cs" />
<Compile Include="D:\Project\C#\DynamicControl\SereinFlow\WorkBench\obj\Release\net8.0-windows\Node\View\ActionRegionControl.g.cs" />
<Compile Include="D:\Project\C#\DynamicControl\SereinFlow\WorkBench\obj\Release\net8.0-windows\Node\View\ConditionNodeControl.g.cs" />
<Compile Include="D:\Project\C#\DynamicControl\SereinFlow\WorkBench\obj\Release\net8.0-windows\Node\View\ConditionRegionControl.g.cs" />
<Compile Include="D:\Project\C#\DynamicControl\SereinFlow\WorkBench\obj\Release\net8.0-windows\Node\View\DllControlControl.g.cs" />
<Compile Include="D:\Project\C#\DynamicControl\SereinFlow\WorkBench\obj\Release\net8.0-windows\Node\View\ExpOpNodeControl.g.cs" />
<Compile Include="D:\Project\C#\DynamicControl\SereinFlow\WorkBench\obj\Release\net8.0-windows\Node\View\FlipflopNodeControl.g.cs" />
<Compile Include="D:\Project\C#\DynamicControl\SereinFlow\WorkBench\obj\Release\net8.0-windows\Themes\InputDialog.g.cs" />
<Compile Include="D:\Project\C#\DynamicControl\SereinFlow\WorkBench\obj\Release\net8.0-windows\Themes\IOCObjectViewControl.g.cs" />
<Compile Include="D:\Project\C#\DynamicControl\SereinFlow\WorkBench\obj\Release\net8.0-windows\Themes\NodeTreeItemViewControl.g.cs" />
<Compile Include="D:\Project\C#\DynamicControl\SereinFlow\WorkBench\obj\Release\net8.0-windows\Themes\NodeTreeViewControl.g.cs" />
<Compile Include="D:\Project\C#\DynamicControl\SereinFlow\WorkBench\obj\Release\net8.0-windows\Themes\ObjectViewerControl.g.cs" />
<Compile Include="D:\Project\C#\DynamicControl\SereinFlow\WorkBench\obj\Release\net8.0-windows\Themes\TypeViewerWindow.g.cs" />
<Compile Include="D:\Project\C#\DynamicControl\SereinFlow\WorkBench\obj\Release\net8.0-windows\Themes\WindowDialogInput.g.cs" />
<Compile Include="D:\Project\C#\DynamicControl\SereinFlow\WorkBench\obj\Release\net8.0-windows\App.g.cs" />
<Compile Include="D:\Project\C#\DynamicControl\SereinFlow\WorkBench\obj\Release\net8.0-windows\GeneratedInternalTypeHelper.g.cs" />
</ItemGroup>
<ItemGroup>
<Analyzer Include="C:\Program Files\dotnet\sdk\9.0.100-rc.2.24474.11\Sdks\Microsoft.NET.Sdk\targets\..\analyzers\Microsoft.CodeAnalysis.CSharp.NetAnalyzers.dll" />
<Analyzer Include="C:\Program Files\dotnet\sdk\9.0.100-rc.2.24474.11\Sdks\Microsoft.NET.Sdk\targets\..\analyzers\Microsoft.CodeAnalysis.NetAnalyzers.dll" />
<Analyzer Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\analyzers/dotnet/cs/Microsoft.Interop.ComInterfaceGenerator.dll" />
<Analyzer Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\analyzers/dotnet/cs/Microsoft.Interop.JavaScript.JSImportGenerator.dll" />
<Analyzer Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\analyzers/dotnet/cs/Microsoft.Interop.LibraryImportGenerator.dll" />
<Analyzer Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\analyzers/dotnet/cs/Microsoft.Interop.SourceGeneration.dll" />
<Analyzer Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\analyzers/dotnet/cs/System.Text.Json.SourceGeneration.dll" />
<Analyzer Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.10\analyzers/dotnet/cs/System.Text.RegularExpressions.Generator.dll" />
</ItemGroup>
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
</Project>