diff --git a/Library/Api/IFlowEnvironment.cs b/Library/Api/IFlowEnvironment.cs
index 67108cd..d356e40 100644
--- a/Library/Api/IFlowEnvironment.cs
+++ b/Library/Api/IFlowEnvironment.cs
@@ -917,7 +917,30 @@ namespace Serein.Library.Api
#endregion
- #region 流程依赖类库的接口
+ #region 流程运行时
+
+ #region 全局数据/方法信息
+
+
+ ///
+ /// 添加或更新全局数据
+ ///
+ /// 数据名称
+ /// 数据集
+ ///
+ object AddOrUpdateGlobalData(string keyName, object data);
+
+ ///
+ /// 获取全局数据
+ ///
+ /// 数据名称
+ ///
+ object GetGlobalData(string keyName);
+
+ #endregion
+
+
+ #region 加载依赖
///
/// 运行时加载
@@ -933,6 +956,7 @@ namespace Serein.Library.Api
/// 是否递归加载
void LoadAllNativeLibraryOfRuning(string path, bool isRecurrence = true);
+ #endregion
#endregion
#region UI视觉
diff --git a/Library/FlowNode/DelegateDetails.cs b/Library/FlowNode/DelegateDetails.cs
index 55c0f83..6d3231c 100644
--- a/Library/FlowNode/DelegateDetails.cs
+++ b/Library/FlowNode/DelegateDetails.cs
@@ -78,30 +78,34 @@ namespace Serein.Library
args = Array.Empty
private FlowStarter? flowStarter;
-
-
#endregion
#region 环境对外接口
@@ -526,6 +524,8 @@ namespace Serein.NodeFlow.Env
}
+
+
///
/// 加载项目文件
///
@@ -535,13 +535,15 @@ namespace Serein.NodeFlow.Env
{
var projectData = flowEnvInfo.Project;
// 加载项目配置文件
- var dllPaths = projectData.Librarys.Select(it => it.FileName).ToList();
+ var dllPaths = projectData.Librarys.Select(it => it.FilePath).ToList();
List methodDetailss = [];
// 遍历依赖项中的特性注解,生成方法详情
foreach (var dllPath in dllPaths)
{
- var dllFilePath = Path.GetFullPath(Path.Combine(filePath, dllPath));
+ string cleanedRelativePath = dllPath.TrimStart('.', '\\');
+ var tmpPath = Path.Combine(filePath, cleanedRelativePath);
+ var dllFilePath = Path.GetFullPath(tmpPath);
LoadLibrary(dllFilePath); // 加载项目文件时加载对应的程序集
}
@@ -550,39 +552,48 @@ namespace Serein.NodeFlow.Env
// 加载节点
foreach (NodeInfo? nodeInfo in projectData.Nodes)
{
- var controlType = FlowFunc.GetNodeControlType(nodeInfo);
+ NodeControlType controlType = FlowFunc.GetNodeControlType(nodeInfo);
if (controlType == NodeControlType.None)
{
continue;
}
+ MethodDetails? methodDetails = null;
+
+ if (controlType.IsBaseNode())
+ {
+ // 加载基础节点
+ methodDetails = new MethodDetails();
+ }
else
{
+ // 加载方法节点
if (string.IsNullOrEmpty(nodeInfo.AssemblyName) && string.IsNullOrEmpty(nodeInfo.MethodName))
{
continue;
}
- MethodDetails? methodDetails = null;
- FlowLibraryManagement.TryGetMethodDetails(nodeInfo.AssemblyName, nodeInfo.MethodName,out methodDetails); // 加载项目时尝试获取方法信息
- var nodeModel = FlowFunc.CreateNode(this, controlType, methodDetails); // 加载项目时创建节点
- nodeModel.LoadInfo(nodeInfo); // 创建节点model
- if (nodeModel is null)
- {
- nodeInfo.Guid = string.Empty;
- continue;
- }
-
- TryAddNode(nodeModel); // 加载项目时将节点加载到环境中
- if (nodeInfo.ChildNodeGuids?.Length > 0)
- {
- regionChildNodes.Add((nodeModel, nodeInfo.ChildNodeGuids));
-
- UIContextOperation?.Invoke(() => OnNodeCreate?.Invoke(new NodeCreateEventArgs(nodeModel, nodeInfo.Position)));
- }
- else
- {
- ordinaryNodes.Add((nodeModel, nodeInfo.Position));
- }
+ FlowLibraryManagement.TryGetMethodDetails(nodeInfo.AssemblyName, nodeInfo.MethodName, out methodDetails); // 加载项目时尝试获取方法信息
}
+
+ var nodeModel = FlowFunc.CreateNode(this, controlType, methodDetails); // 加载项目时创建节点
+ nodeModel.LoadInfo(nodeInfo); // 创建节点model
+ if (nodeModel is null)
+ {
+ nodeInfo.Guid = string.Empty;
+ continue;
+ }
+
+ TryAddNode(nodeModel); // 加载项目时将节点加载到环境中
+ if (nodeInfo.ChildNodeGuids?.Length > 0)
+ {
+ regionChildNodes.Add((nodeModel, nodeInfo.ChildNodeGuids));
+
+ UIContextOperation?.Invoke(() => OnNodeCreate?.Invoke(new NodeCreateEventArgs(nodeModel, nodeInfo.Position)));
+ }
+ else
+ {
+ ordinaryNodes.Add((nodeModel, nodeInfo.Position));
+ }
+
}
// 加载区域子项
foreach ((NodeModelBase region, string[] childNodeGuids) item in regionChildNodes)
@@ -1323,7 +1334,6 @@ namespace Serein.NodeFlow.Env
return result;
}
-
///
/// 记录节点更改数据,防止重复更改
///
@@ -1466,6 +1476,31 @@ namespace Serein.NodeFlow.Env
#region 流程依赖类库的接口
+
+ ///
+ /// 添加或更新全局数据
+ ///
+ /// 数据名称
+ /// 数据集
+ ///
+ public object AddOrUpdateGlobalData(string keyName, object data)
+ {
+ SereinEnv.EnvGlobalData.AddOrUpdate(keyName, data, (k, o) => data);
+ return data;
+ }
+
+ ///
+ /// 获取全局数据
+ ///
+ /// 数据名称
+ ///
+ public object? GetGlobalData(string keyName)
+ {
+ SereinEnv.EnvGlobalData.TryGetValue(keyName, out var data);
+ return data;
+ }
+
+
///
/// 运行时加载
///
diff --git a/NodeFlow/Env/FlowEnvironmentDecorator.cs b/NodeFlow/Env/FlowEnvironmentDecorator.cs
index 37d11e1..704f607 100644
--- a/NodeFlow/Env/FlowEnvironmentDecorator.cs
+++ b/NodeFlow/Env/FlowEnvironmentDecorator.cs
@@ -455,6 +455,27 @@ namespace Serein.NodeFlow.Env
}
#region 流程依赖类库的接口
+ ///
+ /// 添加或更新全局数据
+ ///
+ /// 数据名称
+ /// 数据集
+ ///
+ public object AddOrUpdateGlobalData(string keyName, object data)
+ {
+ return currentFlowEnvironment.AddOrUpdateGlobalData(keyName, data);
+ }
+
+ ///
+ /// 获取全局数据
+ ///
+ /// 数据名称
+ ///
+ public object GetGlobalData(string keyName)
+ {
+ return currentFlowEnvironment.GetGlobalData(keyName);
+ }
+
///
/// 运行时加载
@@ -574,6 +595,8 @@ namespace Serein.NodeFlow.Env
return IOC.Run(action);
}
+
+
#endregion
diff --git a/NodeFlow/Env/FlowFunc.cs b/NodeFlow/Env/FlowFunc.cs
index e7ec836..3f4f92c 100644
--- a/NodeFlow/Env/FlowFunc.cs
+++ b/NodeFlow/Env/FlowFunc.cs
@@ -10,7 +10,19 @@ namespace Serein.NodeFlow.Env
///
public static class FlowFunc
{
-
+ ///
+ /// 判断是否为基础节点
+ ///
+ ///
+ public static bool IsBaseNode(this NodeControlType nodeControlType)
+ {
+ if(nodeControlType == NodeControlType.ExpCondition
+ || nodeControlType == NodeControlType.ExpOp)
+ {
+ return true;
+ }
+ return false;
+ }
///
/// 创建节点
diff --git a/NodeFlow/Env/RemoteFlowEnvironment.cs b/NodeFlow/Env/RemoteFlowEnvironment.cs
index 522a257..4cf6dd4 100644
--- a/NodeFlow/Env/RemoteFlowEnvironment.cs
+++ b/NodeFlow/Env/RemoteFlowEnvironment.cs
@@ -895,6 +895,31 @@ namespace Serein.NodeFlow.Env
this.WriteLine(InfoType.INFO, "远程环境尚未实现的接口:LoadAllNativeLibraryOfRuning");
}
+
+
+ ///
+ /// 添加或更新全局数据
+ ///
+ /// 数据名称
+ /// 数据集
+ ///
+ public object AddOrUpdateGlobalData(string keyName, object data)
+ {
+ this.WriteLine(InfoType.INFO, "远程环境尚未实现的接口:AddOrUpdateGlobalData");
+ return null;
+ }
+ ///
+ /// 获取全局数据
+ ///
+ /// 数据名称
+ ///
+ public object GetGlobalData(string keyName)
+ {
+ this.WriteLine(InfoType.INFO, "远程环境尚未实现的接口:GetGlobalData");
+ return null;
+ }
+
+
#endregion
}
}
diff --git a/NodeFlow/FlowStarter.cs b/NodeFlow/FlowStarter.cs
index 659df3d..f85fede 100644
--- a/NodeFlow/FlowStarter.cs
+++ b/NodeFlow/FlowStarter.cs
@@ -241,13 +241,9 @@ namespace Serein.NodeFlow
_flipFlopCts?.Dispose();
} // 通知所有流程上下文停止运行
TerminateAllGlobalFlipflop(); // 确保所有触发器不再运行
-
-
+ SereinEnv.ClearGlobalData(); // 清空全局数据缓存
NativeDllHelper.FreeLibrarys(); // 卸载所有已加载的 Native Dll
- //NativeDllHelper.FreeLibrarys(); // 卸载所有已加载的 Native Dll
-
-
env.FlowState = RunState.Completion;
env.FlipFlopState = RunState.Completion;
@@ -395,7 +391,7 @@ namespace Serein.NodeFlow
}
catch (FlipflopException ex)
{
- await Console.Out.WriteLineAsync($"触发器[{singleFlipFlopNode.MethodDetails.MethodName}]因非预期异常终止。"+ex.Message);
+ env.WriteLine(InfoType.ERROR,$"触发器[{singleFlipFlopNode.MethodDetails.MethodName}]因非预期异常终止。"+ex.Message);
if (ex.Type == FlipflopException.CancelClass.CancelFlow)
{
break;
@@ -403,7 +399,8 @@ namespace Serein.NodeFlow
}
catch (Exception ex)
{
- await Console.Out.WriteLineAsync(ex.Message);
+ env.WriteLine(InfoType.ERROR, $"触发器[{singleFlipFlopNode.Guid}]异常。"+ ex.Message);
+ //await Console.Out.WriteLineAsync(ex.Message);
}
finally
{
diff --git a/NodeFlow/Model/SingleGlobalDataNode.cs b/NodeFlow/Model/SingleGlobalDataNode.cs
new file mode 100644
index 0000000..86ee5da
--- /dev/null
+++ b/NodeFlow/Model/SingleGlobalDataNode.cs
@@ -0,0 +1,30 @@
+using Serein.Library;
+using Serein.Library.Api;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Serein.NodeFlow.Model
+{
+ ///
+ /// 全局数据节点
+ ///
+ public class SingleGlobalDataNode : NodeModelBase
+ {
+ public SingleGlobalDataNode(IFlowEnvironment environment) : base(environment)
+ {
+ }
+
+ public override ParameterData[] GetParameterdatas()
+ {
+ throw new NotImplementedException();
+ }
+
+ public override void OnCreating()
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/NodeFlow/Tool/FlowLibraryManagement.cs b/NodeFlow/Tool/FlowLibraryManagement.cs
index c42e13d..07234ac 100644
--- a/NodeFlow/Tool/FlowLibraryManagement.cs
+++ b/NodeFlow/Tool/FlowLibraryManagement.cs
@@ -206,10 +206,8 @@ namespace Serein.NodeFlow.Tool
private (NodeLibraryInfo, List) LoadDllNodeInfo(string dllFilePath)
{
var fileName = Path.GetFileName(dllFilePath); // 获取文件名
-
if (SereinLibraryDll.Equals(fileName))
{
-
return LoadAssembly(typeof(IFlowEnvironment).Assembly, () => {
//SereinEnv.PrintInfo(InfoType.WRAN, "基础模块不能卸载");
});
diff --git a/WorkBench/App.xaml.cs b/WorkBench/App.xaml.cs
index 5e8e555..a11be47 100644
--- a/WorkBench/App.xaml.cs
+++ b/WorkBench/App.xaml.cs
@@ -15,13 +15,14 @@ namespace Serein.Workbench
{
#if DEBUG
- if (1 == 1)
+ if (1 == 0 )
{
string filePath;
filePath = @"F:\临时\project\linux\project.dnf";
filePath = @"F:\临时\project\linux\http\project.dnf";
filePath = @"F:\临时\project\yolo flow\project.dnf";
filePath = @"F:\临时\project\data\project.dnf";
+ filePath = @"C:\Users\Az\source\repos\CLBanyunqiState\CLBanyunqiState\bin\Release\net8.0\PLCproject.dnf";
string content = System.IO.File.ReadAllText(filePath); // 读取整个文件内容
App.FlowProjectData = JsonConvert.DeserializeObject(content);
App.FileDataPath = System.IO.Path.GetDirectoryName(filePath)!; // filePath;//
diff --git a/WorkBench/MainWindow.xaml.cs b/WorkBench/MainWindow.xaml.cs
index bbf5cdc..f30f431 100644
--- a/WorkBench/MainWindow.xaml.cs
+++ b/WorkBench/MainWindow.xaml.cs
@@ -578,7 +578,7 @@ namespace Serein.Workbench
NodeControlType.Action => CreateNodeControl(nodeModelBase), //typeof(ActionNodeControl),
NodeControlType.Flipflop => CreateNodeControl(nodeModelBase),
NodeControlType.ExpCondition => CreateNodeControl(nodeModelBase),
- NodeControlType.ExpOp => CreateNodeControl(nodeModelBase),
+ NodeControlType.ExpOp => CreateNodeControl(nodeModelBase),
NodeControlType.ConditionRegion => CreateNodeControl(nodeModelBase),
_ => null,
};
@@ -2504,7 +2504,7 @@ namespace Serein.Workbench
NodeLibraryInfo? library = projectData.Librarys[index];
try
{
- string targetPath = System.IO.Path.Combine(librarySavePath, library.FileName); // 目标文件夹
+ string targetPath = System.IO.Path.Combine(librarySavePath, library.FilePath); // 目标文件夹
#if WINDOWS
string sourceFile = library.FilePath; // 源文件夹
#else
diff --git a/WorkBench/Node/View/ActionNodeControl.xaml b/WorkBench/Node/View/ActionNodeControl.xaml
index 7baaddf..7d3064d 100644
--- a/WorkBench/Node/View/ActionNodeControl.xaml
+++ b/WorkBench/Node/View/ActionNodeControl.xaml
@@ -15,8 +15,10 @@
+
+
@@ -24,7 +26,10 @@
-
+
+
+
+
-
+
+
+
+
+
diff --git a/WorkBench/Node/View/ActionNodeControl.xaml.cs b/WorkBench/Node/View/ActionNodeControl.xaml.cs
index bcd3500..8619d87 100644
--- a/WorkBench/Node/View/ActionNodeControl.xaml.cs
+++ b/WorkBench/Node/View/ActionNodeControl.xaml.cs
@@ -16,7 +16,11 @@ namespace Serein.Workbench.Node.View
{
DataContext = viewModel;
InitializeComponent();
+ if(ExecuteJunctionControl.MyNode != null)
+ {
+
ExecuteJunctionControl.MyNode.Guid = viewModel.NodeModel.Guid;
+ }
}
///
diff --git a/WorkBench/Node/View/ConditionNodeControl.xaml.cs b/WorkBench/Node/View/ConditionNodeControl.xaml.cs
index ed72782..a228615 100644
--- a/WorkBench/Node/View/ConditionNodeControl.xaml.cs
+++ b/WorkBench/Node/View/ConditionNodeControl.xaml.cs
@@ -21,6 +21,7 @@ namespace Serein.Workbench.Node.View
DataContext = viewModel;
InitializeComponent();
}
+
///
/// 入参控制点(可能有,可能没)
///
diff --git a/WorkBench/Node/View/ConditionRegionControl.xaml.cs b/WorkBench/Node/View/ConditionRegionControl.xaml.cs
index d31c69b..637b3b4 100644
--- a/WorkBench/Node/View/ConditionRegionControl.xaml.cs
+++ b/WorkBench/Node/View/ConditionRegionControl.xaml.cs
@@ -26,8 +26,6 @@ namespace Serein.Workbench.Node.View
-
-
///
/// 添加条件控件
///
diff --git a/WorkBench/Node/View/ExpOpNodeControl.xaml.cs b/WorkBench/Node/View/ExpOpNodeControl.xaml.cs
index 7525618..6b0f814 100644
--- a/WorkBench/Node/View/ExpOpNodeControl.xaml.cs
+++ b/WorkBench/Node/View/ExpOpNodeControl.xaml.cs
@@ -11,11 +11,11 @@ namespace Serein.Workbench.Node.View
public ExpOpNodeControl() : base()
{
// 窗体初始化需要
- ViewModel = new ExpOpNodeViewModel(new SingleExpOpNode(null));
+ ViewModel = new ExpOpNodeControlViewModel(new SingleExpOpNode(null));
DataContext = ViewModel;
InitializeComponent();
}
- public ExpOpNodeControl(ExpOpNodeViewModel viewModel) :base(viewModel)
+ public ExpOpNodeControl(ExpOpNodeControlViewModel viewModel) :base(viewModel)
{
DataContext = viewModel;
InitializeComponent();
diff --git a/WorkBench/Serein.WorkBench.csproj b/WorkBench/Serein.WorkBench.csproj
index 6bef458..5b4501c 100644
--- a/WorkBench/Serein.WorkBench.csproj
+++ b/WorkBench/Serein.WorkBench.csproj
@@ -55,6 +55,11 @@
+
+
+
diff --git a/WorkBench/Themes/MethodDetailsControl.xaml b/WorkBench/Themes/MethodDetailsControl.xaml
index de53695..a2c9bb5 100644
--- a/WorkBench/Themes/MethodDetailsControl.xaml
+++ b/WorkBench/Themes/MethodDetailsControl.xaml
@@ -46,6 +46,7 @@
Visibility="{Binding IsParams, Mode=OneWay,
Converter={StaticResource InvertedBoolConverter},ConverterParameter=Normal}"
/>
+