diff --git a/Library.Core/NodeFlow/DynamicContext.cs b/Library.Core/NodeFlow/DynamicContext.cs index b29e27c..0a62ad4 100644 --- a/Library.Core/NodeFlow/DynamicContext.cs +++ b/Library.Core/NodeFlow/DynamicContext.cs @@ -9,7 +9,7 @@ namespace Serein.Library.Core.NodeFlow /// public class DynamicContext: IDynamicContext { - public DynamicContext(ISereinIoc sereinIoc, IFlowEnvironment flowEnvironment) + public DynamicContext(ISereinIOC sereinIoc, IFlowEnvironment flowEnvironment) { SereinIoc = sereinIoc; FlowEnvironment = flowEnvironment; @@ -17,7 +17,7 @@ namespace Serein.Library.Core.NodeFlow } public NodeRunCts NodeRunCts { get; set; } - public ISereinIoc SereinIoc { get; } + public ISereinIOC SereinIoc { get; } public IFlowEnvironment FlowEnvironment { get; } public Task CreateTimingTask(Action action, int time = 100, int count = -1) diff --git a/Library.Framework/NodeFlow/DynamicContext.cs b/Library.Framework/NodeFlow/DynamicContext.cs index 6107d70..4ae4329 100644 --- a/Library.Framework/NodeFlow/DynamicContext.cs +++ b/Library.Framework/NodeFlow/DynamicContext.cs @@ -12,13 +12,13 @@ namespace Serein.Library.Framework.NodeFlow /// public class DynamicContext : IDynamicContext { - public DynamicContext(ISereinIoc sereinIoc, IFlowEnvironment flowEnvironment) + public DynamicContext(ISereinIOC sereinIoc, IFlowEnvironment flowEnvironment) { SereinIoc = sereinIoc; FlowEnvironment = flowEnvironment; } public NodeRunCts NodeRunCts { get; set; } - public ISereinIoc SereinIoc { get; } + public ISereinIOC SereinIoc { get; } public IFlowEnvironment FlowEnvironment { get; } public Task CreateTimingTask(Action action, int time = 100, int count = -1) { diff --git a/Library/Api/IDynamicContext.cs b/Library/Api/IDynamicContext.cs index 266319e..d6bcc4a 100644 --- a/Library/Api/IDynamicContext.cs +++ b/Library/Api/IDynamicContext.cs @@ -7,7 +7,7 @@ namespace Serein.Library.Api public interface IDynamicContext { IFlowEnvironment FlowEnvironment { get; } - ISereinIoc SereinIoc { get; } + ISereinIOC SereinIoc { get; } NodeRunCts NodeRunCts { get; set; } Task CreateTimingTask(Action action, int time = 100, int count = -1); } diff --git a/Library/Api/IFlowEnvironment.cs b/Library/Api/IFlowEnvironment.cs index 19ceb72..b0b603c 100644 --- a/Library/Api/IFlowEnvironment.cs +++ b/Library/Api/IFlowEnvironment.cs @@ -7,48 +7,22 @@ using System.Threading.Tasks; namespace Serein.Library.Api { - - public class FlowEventArgs : EventArgs - { - public bool IsSucceed { get; protected set; } = true; - public string ErrorTips { get; protected set; } = string.Empty; - } - - + #region 环境委托 + /// + /// 流程运行完成 + /// + /// public delegate void FlowRunCompleteHandler(FlowEventArgs eventArgs); - /// - /// 加载节点 + /// 加载项目文件时成功加载了节点 /// public delegate void LoadNodeHandler(LoadNodeEventArgs eventArgs); - public class LoadNodeEventArgs : FlowEventArgs - { - public LoadNodeEventArgs(NodeInfo NodeInfo, MethodDetails MethodDetailss) - { - this.NodeInfo = NodeInfo; - this.MethodDetailss = MethodDetailss; - } - public NodeInfo NodeInfo { get; protected set; } - public MethodDetails MethodDetailss { get; protected set; } - } - /// - /// 加载DLL + /// 加载项目文件时成功加载了DLL文件 /// - /// public delegate void LoadDLLHandler(LoadDLLEventArgs eventArgs); - public class LoadDLLEventArgs : FlowEventArgs - { - public LoadDLLEventArgs(Assembly Assembly, List MethodDetailss) - { - this.Assembly = Assembly; - this.MethodDetailss = MethodDetailss; - } - public Assembly Assembly { get; protected set; } - public List MethodDetailss { get; protected set; } - } /// /// 运行环境节点连接发生了改变 @@ -57,43 +31,132 @@ namespace Serein.Library.Api /// /// public delegate void NodeConnectChangeHandler(NodeConnectChangeEventArgs eventArgs); + + /// + /// 环境中加载了一个节点 + /// + /// + /// + /// + public delegate void NodeCreateHandler(NodeCreateEventArgs eventArgs); + + /// + /// 环境中流程起始节点发生了改变 + /// + /// + public delegate void StartNodeChangeHandler(StartNodeChangeEventArgs eventArgs); + #endregion + + #region 环境事件签名 + + /// + /// 流程事件签名基类 + /// + public class FlowEventArgs : EventArgs + { + /// + /// 是否完成 + /// + public bool IsSucceed { get; protected set; } = true; + /// + /// 错误提示 + /// + public string ErrorTips { get; protected set; } = string.Empty; + } + public class LoadNodeEventArgs : FlowEventArgs + { + public LoadNodeEventArgs(NodeInfo NodeInfo, MethodDetails MethodDetailss) + { + this.NodeInfo = NodeInfo; + this.MethodDetailss = MethodDetailss; + } + /// + /// 项目文件节点信息参数 + /// + public NodeInfo NodeInfo { get; protected set; } + /// + /// 已加载在环境中的方法描述 + /// + public MethodDetails MethodDetailss { get; protected set; } + } + + + public class LoadDLLEventArgs : FlowEventArgs + { + public LoadDLLEventArgs(Assembly Assembly, List MethodDetailss) + { + this.Assembly = Assembly; + this.MethodDetailss = MethodDetailss; + } + /// + /// 已加载了的程序集 + /// + public Assembly Assembly { get; protected set; } + /// + /// dll文件中有效的流程方法描述 + /// + public List MethodDetailss { get; protected set; } + } + + public class NodeConnectChangeEventArgs : FlowEventArgs { - public enum ChangeTypeEnum + /// + /// 连接关系改变类型 + /// + public enum ConnectChangeType { + /// + /// 创建 + /// Create, + /// + /// 移除 + /// Remote, } - public NodeConnectChangeEventArgs(string fromNodeGuid, string toNodeGuid, ConnectionType connectionType, ChangeTypeEnum changeType) + public NodeConnectChangeEventArgs(string fromNodeGuid, string toNodeGuid, ConnectionType connectionType, ConnectChangeType changeType) { this.FromNodeGuid = fromNodeGuid; this.ToNodeGuid = toNodeGuid; this.ConnectionType = connectionType; this.ChangeType = changeType; } + /// + /// 连接关系中始节点的Guid + /// public string FromNodeGuid { get; protected set; } + /// + /// 连接关系中目标节点的Guid + /// public string ToNodeGuid { get; protected set; } + /// + /// 连接类型 + /// public ConnectionType ConnectionType { get; protected set; } - public ChangeTypeEnum ChangeType { get; protected set; } + /// + /// 表示此次需要在两个节点之间创建连接关系,或是移除连接关系 + /// + public ConnectChangeType ChangeType { get; protected set; } } - /// - /// 添加了节点 - /// - /// - /// - /// - public delegate void NodeCreateHandler(NodeCreateEventArgs eventArgs); + public class NodeCreateEventArgs : FlowEventArgs { public NodeCreateEventArgs(object nodeModel) { this.NodeModel = nodeModel; } + /// + /// 节点Model对象,目前需要手动转换对应的类型 + /// public object NodeModel { get; private set; } } - + /// + /// 环境中移除了一个节点 + /// + /// public delegate void NodeRemoteHandler(NodeRemoteEventArgs eventArgs); public class NodeRemoteEventArgs : FlowEventArgs @@ -102,24 +165,32 @@ namespace Serein.Library.Api { this.NodeGuid = nodeGuid; } + /// + /// 被移除节点的Guid + /// public string NodeGuid { get; private set; } } - public delegate void StartNodeChangeHandler(StartNodeChangeEventArgs eventArgs); - public class StartNodeChangeEventArgs: FlowEventArgs + public class StartNodeChangeEventArgs : FlowEventArgs { public StartNodeChangeEventArgs(string oldNodeGuid, string newNodeGuid) { this.OldNodeGuid = oldNodeGuid; this.NewNodeGuid = newNodeGuid; ; } - public string OldNodeGuid { get; private set; } - public string NewNodeGuid { get; private set; } - } - + /// + /// 原来的起始节点Guid + /// + public string OldNodeGuid { get; private set; } + /// + /// 新的起始节点Guid + /// + public string NewNodeGuid { get; private set; } + } + #endregion public interface IFlowEnvironment { diff --git a/Library/Api/ISereinIoc.cs b/Library/Api/ISereinIoc.cs index d4aee92..06ef569 100644 --- a/Library/Api/ISereinIoc.cs +++ b/Library/Api/ISereinIoc.cs @@ -4,24 +4,19 @@ using System.Text; namespace Serein.Library.Api { - public interface ISereinIoc + public interface ISereinIOC { - /// - /// 获取或创建类型的实例(不注入依赖项) - /// - object GetOrCreateServiceInstance(Type serviceType, params object[] parameters); - T GetOrCreateServiceInstance(params object[] parameters); /// /// 清空 /// /// - ISereinIoc Reset(); + ISereinIOC Reset(); /// /// 注册实例 /// - ISereinIoc Register(Type type, params object[] parameters); - ISereinIoc Register(params object[] parameters); - ISereinIoc Register(params object[] parameters) where TImplementation : TService; + ISereinIOC Register(Type type, params object[] parameters); + ISereinIOC Register(params object[] parameters); + ISereinIOC Register(params object[] parameters) where TImplementation : TService; /// /// 获取或创建并注入目标类型 /// @@ -35,15 +30,15 @@ namespace Serein.Library.Api /// 创建目标类型的对象, 并注入依赖项 /// object Instantiate(Type type, params object[] parameters); - ISereinIoc Build(); - ISereinIoc Run(Action action); - ISereinIoc Run(Action action); - ISereinIoc Run(Action action); - ISereinIoc Run(Action action); - ISereinIoc Run(Action action); - ISereinIoc Run(Action action); - ISereinIoc Run(Action action); - ISereinIoc Run(Action action); + ISereinIOC Build(); + ISereinIOC Run(Action action); + ISereinIOC Run(Action action); + ISereinIOC Run(Action action); + ISereinIOC Run(Action action); + ISereinIOC Run(Action action); + ISereinIOC Run(Action action); + ISereinIOC Run(Action action); + ISereinIOC Run(Action action); } } diff --git a/Library/Utils/SereinIoc.cs b/Library/Utils/SereinIoc.cs index 2093198..87c1163 100644 --- a/Library/Utils/SereinIoc.cs +++ b/Library/Utils/SereinIoc.cs @@ -11,7 +11,7 @@ namespace Serein.Library.Utils /// /// IOC管理容器 /// - public class SereinIoc : ISereinIoc + public class SereinIOC : ISereinIOC { /// /// 实例集合 @@ -33,78 +33,31 @@ namespace Serein.Library.Utils /// private readonly List _waitingForInstantiation; - public SereinIoc() + public SereinIOC() { // 首先注册自己 _dependencies = new ConcurrentDictionary { - [typeof(ISereinIoc).FullName] = this + [typeof(ISereinIOC).FullName] = this }; _typeMappings = new ConcurrentDictionary { - [typeof(ISereinIoc).FullName] = typeof(ISereinIoc) + [typeof(ISereinIOC).FullName] = typeof(ISereinIOC) }; _unfinishedDependencies = new ConcurrentDictionary>(); _waitingForInstantiation = new List(); } - /// - /// 获取或创建实例对象(不注入对象的依赖项) - /// - /// 目标类型 - /// 构造函数的参数 - /// - public object GetOrCreateServiceInstance(Type type, params object[] parameters) - { - if (_dependencies.ContainsKey(type.FullName)) - { - return _dependencies[type.FullName]; - } - else - { - var instance = Activator.CreateInstance(type); // 创建目标类型的实例对象 - InjectDependencies(instance);// 注入目标对象的依赖项 - _dependencies[type.FullName] = instance; // 记录实例 - return instance; - } - } - /// - /// 泛型方法, 获取或创建实例对象(不注入对象的依赖项) - /// - /// 目标类型 - /// 构造函数的参数 - /// - public T GetOrCreateServiceInstance(params object[] parameters) - { - return (T)GetOrCreateServiceInstance(typeof(T), parameters); - } - /// - /// 清空容器对象 - /// - /// - public ISereinIoc Reset() - { - // 检查是否存在非托管资源 - foreach(var instancei in _dependencies.Values) - { - if (typeof(IDisposable).IsAssignableFrom(instancei.GetType()) && instancei is IDisposable disposable) - { - disposable.Dispose(); - } - } - _typeMappings.Clear(); - _dependencies.Clear(); - _waitingForInstantiation.Clear(); - return this; - } + + #region 类型的注册 /// /// 注册类型 /// /// 目标类型 /// 参数 - public ISereinIoc Register(Type type, params object[] parameters) + public ISereinIOC Register(Type type, params object[] parameters) { RegisterType(type.FullName, type); return this; @@ -114,7 +67,7 @@ namespace Serein.Library.Utils /// /// 目标类型 /// 参数 - public ISereinIoc Register(params object[] parameters) + public ISereinIOC Register(params object[] parameters) { var type = typeof(T); RegisterType(type.FullName, type); @@ -122,61 +75,90 @@ namespace Serein.Library.Utils } - public ISereinIoc Register(params object[] parameters) + public ISereinIOC Register(params object[] parameters) where TImplementation : TService { var typeFullName = typeof(TService).FullName; RegisterType(typeFullName, typeof(TImplementation)); return this; - } - + } + #endregion /// - /// 注册 + /// 尝试从容器中获取对象,如果不存在目标类型的对象,则将类型信息登记到容器,并实例化注入依赖项。 /// - /// - /// public object GetOrInstantiate(Type type) { + // 尝试从容器中获取对象 if (!_dependencies.TryGetValue(type.FullName, out object value)) { - Register(type); - - value = Instantiate(type); - - InjectDependencies(type); + Register(type);// 注册类型信息 + value = Instantiate(type); // 创建实例对象,并注入依赖 + _dependencies.TryAdd(type.FullName, value); // 登记到IOC容器中 } - - - - return value; - + return value; } + /// + /// 尝试从容器中获取对象,如果不存在目标类型的对象,则将类型信息登记到容器,并实例化注入依赖项。 + /// public T GetOrInstantiate() { - if(!_dependencies.TryGetValue(typeof(T).FullName, out object value)) - { - Register(typeof(T)); - value = Instantiate(typeof(T)); - } - + var value = Instantiate(typeof(T)); return (T)value; - //throw new InvalidOperationException("目标类型未创建实例"); + } + + /// + /// 根据类型生成对应的实例,并注入其中的依赖项(类型信息不登记到IOC容器中) + /// + /// + /// + /// + public object Instantiate(Type controllerType, params object[] parameters) + { + var instance = CreateInstance(controllerType, parameters); // 创建目标类型的实例 + if(instance != null) + { + InjectDependencies(instance); // 完成创建后注入实例需要的依赖项 + } + return instance; + } + + #region 容器管理(清空,绑定) + + /// + /// 清空容器对象 + /// + /// + public ISereinIOC Reset() + { + // 检查是否存在非托管资源 + foreach (var instancei in _dependencies.Values) + { + if (typeof(IDisposable).IsAssignableFrom(instancei.GetType()) && instancei is IDisposable disposable) + { + disposable?.Dispose(); + } + } + _unfinishedDependencies?.Clear(); + _typeMappings?.Clear(); + _dependencies?.Clear(); + _waitingForInstantiation?.Clear(); + return this; } /// /// 实例化所有已注册的类型,并尝试绑定 /// /// - public ISereinIoc Build() + public ISereinIOC Build() { // 遍历已注册类型 foreach (var type in _typeMappings.Values.ToArray()) { - - if(_dependencies.ContainsKey(type.FullName)) + + if (_dependencies.ContainsKey(type.FullName)) { // 已经存在实例,不用管 } @@ -186,7 +168,7 @@ namespace Serein.Library.Utils _dependencies[type.FullName] = CreateInstance(type); } // 移除类型的注册记录 - _typeMappings.TryRemove(type.FullName,out _); + _typeMappings.TryRemove(type.FullName, out _); } // 注入实例的依赖项 @@ -198,20 +180,12 @@ namespace Serein.Library.Utils //var instance = Instantiate(item.Value); // TryInstantiateWaitingDependencies(); - + return this; - } - - public object Instantiate(Type controllerType, params object[] parameters) - { - var instance = CreateInstance(controllerType, parameters); - if(instance != null) - { - InjectDependencies(instance); - } - return instance; - } + } + #endregion + #region 私有方法 /// @@ -233,14 +207,14 @@ namespace Serein.Library.Utils private object CreateInstance(Type type, params object[] parameters) { var instance = Activator.CreateInstance(type); - if(_unfinishedDependencies.TryGetValue(type.FullName, out var unfinishedPropertyList)) + if (_unfinishedDependencies.TryGetValue(type.FullName, out var unfinishedPropertyList)) { foreach ((object obj, PropertyInfo property) in unfinishedPropertyList) { property.SetValue(obj, instance); //注入依赖项 } - - if(_unfinishedDependencies.TryRemove(type.FullName, out unfinishedPropertyList)) + + if (_unfinishedDependencies.TryRemove(type.FullName, out unfinishedPropertyList)) { unfinishedPropertyList.Clear(); } @@ -272,19 +246,19 @@ namespace Serein.Library.Utils else { // 存在依赖项,但目标类型的实例暂未加载,需要等待需要实例完成注册 - var unfinishedDependenciesList = _unfinishedDependencies.GetOrAdd(propertyType.FullName, _ = new List<(object, PropertyInfo)>()); + var unfinishedDependenciesList = _unfinishedDependencies.GetOrAdd(propertyType.FullName, _ = new List<(object, PropertyInfo)>()); var data = (instance, property); - if (!unfinishedDependenciesList.Contains(data)) - { - unfinishedDependenciesList.Add(data); - } - isPass = false; + if (!unfinishedDependenciesList.Contains(data)) + { + unfinishedDependenciesList.Add(data); + } + isPass = false; } } return isPass; } - + /// /// 再次尝试注入目标实例的依赖项 /// @@ -304,10 +278,11 @@ namespace Serein.Library.Utils } } } - } + } + #endregion #region run() - public ISereinIoc Run(Action action) + public ISereinIOC Run(Action action) { var service = GetOrInstantiate(); if (service != null) @@ -317,7 +292,7 @@ namespace Serein.Library.Utils return this; } - public ISereinIoc Run(Action action) + public ISereinIOC Run(Action action) { var service1 = GetOrInstantiate(); var service2 = GetOrInstantiate(); @@ -326,7 +301,7 @@ namespace Serein.Library.Utils return this; } - public ISereinIoc Run(Action action) + public ISereinIOC Run(Action action) { var service1 = GetOrInstantiate(); var service2 = GetOrInstantiate(); @@ -335,7 +310,7 @@ namespace Serein.Library.Utils return this; } - public ISereinIoc Run(Action action) + public ISereinIOC Run(Action action) { var service1 = GetOrInstantiate(); var service2 = GetOrInstantiate(); @@ -345,7 +320,7 @@ namespace Serein.Library.Utils return this; } - public ISereinIoc Run(Action action) + public ISereinIOC Run(Action action) { var service1 = GetOrInstantiate(); var service2 = GetOrInstantiate(); @@ -356,7 +331,7 @@ namespace Serein.Library.Utils return this; } - public ISereinIoc Run(Action action) + public ISereinIOC Run(Action action) { var service1 = GetOrInstantiate(); var service2 = GetOrInstantiate(); @@ -368,7 +343,7 @@ namespace Serein.Library.Utils return this; } - public ISereinIoc Run(Action action) + public ISereinIOC Run(Action action) { var service1 = GetOrInstantiate(); var service2 = GetOrInstantiate(); @@ -381,7 +356,7 @@ namespace Serein.Library.Utils return this; } - public ISereinIoc Run(Action action) + public ISereinIOC Run(Action action) { var service1 = GetOrInstantiate(); var service2 = GetOrInstantiate(); diff --git a/NodeFlow/FlowEnvironment.cs b/NodeFlow/FlowEnvironment.cs index 0b9a7e4..a865360 100644 --- a/NodeFlow/FlowEnvironment.cs +++ b/NodeFlow/FlowEnvironment.cs @@ -10,7 +10,9 @@ using System.Diagnostics; using System.Net.Mime; using System.Reflection; using System.Reflection.Emit; +using System.Text; using System.Xml.Linq; +using static Serein.NodeFlow.FlowStarter; namespace Serein.NodeFlow { @@ -47,19 +49,28 @@ namespace Serein.NodeFlow /// public event LoadDLLHandler OnDllLoad; /// - /// 加载节点 + /// 加载节点事件 /// public event LoadNodeHandler OnLoadNode; /// - /// 连接节点 + /// 节点连接属性改变事件 /// public event NodeConnectChangeHandler OnNodeConnectChange; /// - /// 创建节点 + /// 节点创建时间 /// public event NodeCreateHandler OnNodeCreate; + /// + /// 移除节点事件 + /// public event NodeRemoteHandler OnNodeRemote; + /// + /// 起始节点变化事件 + /// public event StartNodeChangeHandler OnStartNodeChange; + /// + /// 流程运行完成时间 + /// public event FlowRunCompleteHandler OnFlowRunComplete; private FlowStarter? nodeFlowStarter = null; @@ -72,7 +83,7 @@ namespace Serein.NodeFlow /// /// 一种轻量的IOC容器 /// - public SereinIoc SereinIoc { get; } = new SereinIoc(); + // public SereinIoc SereinIoc { get; } = new SereinIoc(); /// /// 存储加载的程序集路径 @@ -92,15 +103,17 @@ namespace Serein.NodeFlow public Dictionary Nodes { get; } = []; - public List Regions { get; } = []; + // public List Regions { get; } = []; /// /// 存放触发器节点(运行时全部调用) /// public List FlipflopNodes { get; } = []; - private NodeModelBase? _startNode = null; - + /// + /// 私有属性 + /// + private NodeModelBase _startNode; /// /// 起始节点 /// @@ -112,17 +125,12 @@ namespace Serein.NodeFlow } set { - if (_startNode is null) - { - value.IsStart = true; - _startNode = value; - } - else - { + if (_startNode is not null) + { _startNode.IsStart = false; - value.IsStart = true; - _startNode = value; } + value.IsStart = true; + _startNode = value; } } @@ -132,19 +140,32 @@ namespace Serein.NodeFlow /// public async Task StartAsync() { - nodeFlowStarter = new FlowStarter(SereinIoc); - var nodes = Nodes.Values.ToList(); - var flipflopNodes = nodes.Where(it => it.MethodDetails?.MethodDynamicType == NodeType.Flipflop - && it.IsStart == false) - .Select(it => it as SingleFlipflopNode) - .ToList(); + nodeFlowStarter = new FlowStarter(); + List flipflopNodes = Nodes.Values.Where(it => it.MethodDetails?.MethodDynamicType == NodeType.Flipflop && it.IsStart == false) + .Select(it => (SingleFlipflopNode)it) + .Where(node => node is SingleFlipflopNode flipflopNode && flipflopNode.NotExitPreviousNode()) + .ToList();// 获取需要再运行开始之前启动的触发器节点 + var runMethodDetailess = Nodes.Values.Select(item => item.MethodDetails).ToList(); // 获取环境中所有节点的方法信息 + var initMethods = MethodDetailss.Where(it => it.MethodDynamicType == NodeType.Init).ToList(); + var loadingMethods = MethodDetailss.Where(it => it.MethodDynamicType == NodeType.Loading).ToList(); + var exitMethods = MethodDetailss.Where(it => it.MethodDynamicType == NodeType.Exit).ToList(); + await nodeFlowStarter.RunAsync(StartNode, + this, + runMethodDetailess, + initMethods, + loadingMethods, + exitMethods, + flipflopNodes); - await nodeFlowStarter.RunAsync(StartNode, this, MethodDetailss, flipflopNodes); + if(nodeFlowStarter?.FlipFlopState == RunState.NoStart) + { + this.Exit(); // 未运行触发器时,才会调用结束方法 + } + nodeFlowStarter = null; } public void Exit() { nodeFlowStarter?.Exit(); - nodeFlowStarter = null; OnFlowRunComplete?.Invoke(new FlowEventArgs()); } @@ -162,19 +183,6 @@ namespace Serein.NodeFlow #region 对外暴露的接口 - /// - /// 获取方法描述 - /// - public bool TryGetMethodDetails(string name, out MethodDetails? md) - { - md = MethodDetailss.FirstOrDefault(it => it.MethodName == name); - if (md == null) - { - return false; - } - return true; - } - /// /// 加载项目文件 /// @@ -247,27 +255,34 @@ namespace Serein.NodeFlow } /// - /// 连接节点 + /// 保存项目为项目文件 /// - /// 起始节点 - /// 目标节点 - /// 连接关系 - public void ConnectNode(string fromNodeGuid, string toNodeGuid, ConnectionType connectionType) + /// + public SereinOutputFileData SaveProject() { - // 获取起始节点与目标节点 - if (!Nodes.TryGetValue(fromNodeGuid, out NodeModelBase? fromNode) || !Nodes.TryGetValue(toNodeGuid, out NodeModelBase? toNode)) + var projectData = new SereinOutputFileData() { - return; - } - if (fromNode is null || toNode is null) + Librarys = LoadedAssemblies.Select(assemblies => assemblies.ToLibrary()).ToArray(), + Nodes = Nodes.Values.Select(node => node.ToInfo()).Where(info => info is not null).ToArray(), + StartNode = Nodes.Values.FirstOrDefault(it => it.IsStart)?.Guid, + }; + return projectData; + } + /// + /// 从文件路径中加载DLL + /// + /// + /// + public void LoadDll(string dllPath) + { + (var assembly, var list) = LoadAssembly(dllPath); + if (assembly is not null && list.Count > 0) { - return; + MethodDetailss.AddRange(list); + OnDllLoad?.Invoke(new LoadDLLEventArgs(assembly, list)); } - // 开始连接 - ConnectNode(fromNode, toNode, connectionType); // 外部调用连接方法 } - /// /// 创建节点 /// @@ -326,66 +341,6 @@ namespace Serein.NodeFlow SetStartNode(nodeBase); } } - - - /// - /// 从文件路径中加载DLL - /// - /// - /// - public void LoadDll(string dllPath) - { - (var assembly, var list) = LoadAssembly(dllPath); - if (assembly is not null && list.Count > 0) - { - MethodDetailss.AddRange(list); - OnDllLoad?.Invoke(new LoadDLLEventArgs(assembly, list)); - } - - } - - /// - /// 保存项目为项目文件 - /// - /// - public SereinOutputFileData SaveProject() - { - var projectData = new SereinOutputFileData() - { - Librarys = LoadedAssemblies.Select(assemblies => assemblies.ToLibrary()).ToArray(), - Nodes = Nodes.Values.Select(node => node.ToInfo()).Where(info => info is not null).ToArray(), - StartNode = Nodes.Values.FirstOrDefault(it => it.IsStart)?.Guid, - }; - return projectData; - } - - /// - /// 移除连接关系 - /// - /// - /// - /// - /// - public void RemoteConnect(string fromNodeGuid, string toNodeGuid, ConnectionType connectionType) - { - // 获取起始节点与目标节点 - if (!Nodes.TryGetValue(fromNodeGuid, out NodeModelBase? fromNode) || !Nodes.TryGetValue(toNodeGuid, out NodeModelBase? toNode)) - { - return; - } - if (fromNode is null || toNode is null) - { - return; - } - - fromNode.SuccessorNodes[connectionType].Remove(toNode); - toNode.PreviousNodes[connectionType].Remove(fromNode); - OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNodeGuid, - toNodeGuid, - connectionType, - NodeConnectChangeEventArgs.ChangeTypeEnum.Remote)); - } - /// /// 移除节点 /// @@ -418,7 +373,7 @@ namespace Serein.NodeFlow OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(pNode.Guid, remoteNode.Guid, pCType, - NodeConnectChangeEventArgs.ChangeTypeEnum.Remote)); // 通知UI + NodeConnectChangeEventArgs.ConnectChangeType.Remote)); // 通知UI } } @@ -433,7 +388,7 @@ namespace Serein.NodeFlow OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(remoteNode.Guid, sNode.Guid, sCType, - NodeConnectChangeEventArgs.ChangeTypeEnum.Remote)); // 通知UI + NodeConnectChangeEventArgs.ConnectChangeType.Remote)); // 通知UI } } @@ -443,6 +398,68 @@ namespace Serein.NodeFlow OnNodeRemote?.Invoke(new NodeRemoteEventArgs(nodeGuid)); } + /// + /// 连接节点 + /// + /// 起始节点 + /// 目标节点 + /// 连接关系 + public void ConnectNode(string fromNodeGuid, string toNodeGuid, ConnectionType connectionType) + { + // 获取起始节点与目标节点 + if (!Nodes.TryGetValue(fromNodeGuid, out NodeModelBase? fromNode) || !Nodes.TryGetValue(toNodeGuid, out NodeModelBase? toNode)) + { + return; + } + if (fromNode is null || toNode is null) + { + return; + } + // 开始连接 + ConnectNode(fromNode, toNode, connectionType); // 外部调用连接方法 + + } + + /// + /// 移除连接关系 + /// + /// + /// + /// + /// + public void RemoteConnect(string fromNodeGuid, string toNodeGuid, ConnectionType connectionType) + { + // 获取起始节点与目标节点 + if (!Nodes.TryGetValue(fromNodeGuid, out NodeModelBase? fromNode) || !Nodes.TryGetValue(toNodeGuid, out NodeModelBase? toNode)) + { + return; + } + if (fromNode is null || toNode is null) + { + return; + } + + fromNode.SuccessorNodes[connectionType].Remove(toNode); + toNode.PreviousNodes[connectionType].Remove(fromNode); + OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNodeGuid, + toNodeGuid, + connectionType, + NodeConnectChangeEventArgs.ConnectChangeType.Remote)); + } + + /// + /// 获取方法描述 + /// + public bool TryGetMethodDetails(string name, out MethodDetails? md) + { + md = MethodDetailss.FirstOrDefault(it => it.MethodName == name); + if (md == null) + { + return false; + } + return true; + } + /// /// 设置起点控件 /// @@ -494,14 +511,14 @@ namespace Serein.NodeFlow { // 加载DLL,创建 MethodDetails、实例作用对象、委托方法 var itemMethodDetails = MethodDetailsHelperTmp.GetList(item, false); - foreach (var md in itemMethodDetails) - { - // var instanceType = - // Activator.CreateInstance(md.ActingInstanceType); - // SereinIoc.RegisterInstantiate(md.ActingInstance); - SereinIoc.Register(md.ActingInstanceType); - } methodDetails.AddRange(itemMethodDetails); + //foreach (var md in itemMethodDetails) + //{ + // // var instanceType = + // // Activator.CreateInstance(md.ActingInstanceType); + // // SereinIoc.RegisterInstantiate(md.ActingInstance); + // SereinIoc.Register(md.ActingInstanceType); + //} } LoadedAssemblies.Add(assembly); // 将加载的程序集添加到列表中 LoadedAssemblyPaths.Add(dllPath); // 记录加载的DLL路径 @@ -514,7 +531,6 @@ namespace Serein.NodeFlow } } - /// /// 连接节点 /// @@ -573,7 +589,7 @@ namespace Serein.NodeFlow OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNode.Guid, toNode.Guid, connectionType, - NodeConnectChangeEventArgs.ChangeTypeEnum.Create)); // 通知UI + NodeConnectChangeEventArgs.ConnectChangeType.Create)); // 通知UI } /// @@ -589,20 +605,11 @@ namespace Serein.NodeFlow } #endregion - #region 视觉元素交互 - - #region 本地交互(WPF) + #region 网络交互 #endregion - #region 网络交互(通过Socket的方式进行操作) - - #endregion - - - #endregion - -} + } public static class FlowFunc { public static Library.Entity.Library ToLibrary(this Assembly assembly) @@ -625,6 +632,22 @@ namespace Serein.NodeFlow _ => throw new NotImplementedException("未定义的流程状态") }; } + + public static bool NotExitPreviousNode(this SingleFlipflopNode node) + { + ConnectionType[] ct = [ConnectionType.IsSucceed, + ConnectionType.IsFail, + ConnectionType.IsError, + ConnectionType.Upstream]; + foreach (ConnectionType ctType in ct) + { + if(node.PreviousNodes[ctType].Count > 0) + { + return false; + } + } + return true; + } } diff --git a/NodeFlow/FlowStarter.cs b/NodeFlow/FlowStarter.cs index 8943f31..da72a72 100644 --- a/NodeFlow/FlowStarter.cs +++ b/NodeFlow/FlowStarter.cs @@ -16,69 +16,135 @@ namespace Serein.NodeFlow /// public class FlowStarter { - public FlowStarter(ISereinIoc serviceContainer/*, List methodDetails*/) + public FlowStarter() { - SereinIoc = serviceContainer; - + SereinIOC = new SereinIOC(); } + /// + /// 流程运行状态 + /// + public enum RunState + { + /// + /// 等待开始 + /// + NoStart, + /// + /// 正在运行 + /// + Running, + /// + /// 运行完成 + /// + Completion, + } + /// + /// 控制触发器的结束 + /// + private NodeRunCts FlipFlopCts { get; set; } = null; + + /// + /// 运行状态 + /// + public RunState FlowState { get; private set; } = RunState.NoStart; + public RunState FlipFlopState { get; private set; } = RunState.NoStart; + + /// + /// 运行时的IOC容器 + /// + private ISereinIOC SereinIOC { get; } = null; + + /// + /// 结束运行时需要执行的方法 + /// + private Action ExitAction { get; set; } = null; + /// + /// 运行的上下文 + /// + private IDynamicContext Context { get; set; } = null; + - private ISereinIoc SereinIoc { get; } - // private List MethodDetailss { get; } - private Action ExitAction { get; set; } = null; //退出方法 - private IDynamicContext Context { get; set; } = null; //上下文 - public NodeRunCts MainCts { get; set; } /// /// 开始运行 /// - /// + /// 起始节点 + /// 运行环境 + /// 环境中已加载的所有节点方法 + /// 触发器节点 /// - // public async Task RunAsync(List nodes, IFlowEnvironment flowEnvironment) - public async Task RunAsync(NodeModelBase startNode, IFlowEnvironment flowEnvironment, List methodDetailss, List flipflopNodes) + public async Task RunAsync(NodeModelBase startNode, + IFlowEnvironment env, + List runMd, + List initMethods, + List loadingMethods, + List exitMethods, + List flipflopNodes) { - // var startNode = nodes.FirstOrDefault(p => p.IsStart); - if (startNode == null) { return; } + + FlowState = RunState.Running; // 开始运行 + if (startNode == null) { + FlowState = RunState.Completion; // 不存在起点,退出流程 + return; + } + + // 判断使用哪一种流程上下文 var isNetFramework = true; - if (isNetFramework) { - Context = new Serein.Library.Framework.NodeFlow.DynamicContext(SereinIoc, flowEnvironment); + Context = new Serein.Library.Framework.NodeFlow.DynamicContext(SereinIOC, env); } else { - Context = new Serein.Library.Core.NodeFlow.DynamicContext(SereinIoc, flowEnvironment); + Context = new Serein.Library.Core.NodeFlow.DynamicContext(SereinIOC, env); } - MainCts = SereinIoc.GetOrCreateServiceInstance(); - - foreach (var md in methodDetailss) + #region 初始化运行环境的Ioc容器 + // 清除节点使用的对象 + foreach (var nodeMd in runMd) { - SereinIoc.Register(md.ActingInstanceType); + nodeMd.ActingInstance = null; } - SereinIoc.Build(); - foreach (var md in flipflopNodes.Select(it => it.MethodDetails).ToArray()) + SereinIOC.Reset(); // 开始运行时清空ioc中注册的实例 + // 初始化ioc容器中的类型对象 + foreach (var md in runMd) { - md.ActingInstance = SereinIoc.GetOrCreateServiceInstance(md.ActingInstanceType); + SereinIOC.Register(md.ActingInstanceType); } - foreach (var md in methodDetailss) + SereinIOC.Build(); + foreach (var md in runMd) { - md.ActingInstance = SereinIoc.GetOrCreateServiceInstance(md.ActingInstanceType); + md.ActingInstance = SereinIOC.GetOrInstantiate(md.ActingInstanceType); } - var initMethods = methodDetailss.Where(it => it.MethodDynamicType == NodeType.Init).ToList(); - var loadingMethods = methodDetailss.Where(it => it.MethodDynamicType == NodeType.Loading).ToList(); - var exitMethods = methodDetailss.Where(it => it.MethodDynamicType == NodeType.Exit).ToList(); + //foreach (var md in flipflopNodes.Select(it => it.MethodDetails).ToArray()) + //{ + // md.ActingInstance = SereinIoc.GetOrCreateServiceInstance(md.ActingInstanceType); + //} + #endregion + + + #region 创建Node中初始化、加载时、退出时调用的方法 + + foreach (var md in initMethods) // 初始化 + { + md.ActingInstance ??= Context.SereinIoc.GetOrInstantiate(md.ActingInstanceType); + } + foreach (var md in loadingMethods) // 加载 + { + md.ActingInstance ??= Context.SereinIoc.GetOrInstantiate(md.ActingInstanceType); + } + foreach (var md in exitMethods) // 初始化 + { + md.ActingInstance ??= Context.SereinIoc.GetOrInstantiate(md.ActingInstanceType); + } + + object?[]? args = [Context]; ExitAction = () => { - //ServiceContainer.Run((web) => - //{ - // web?.Stop(); - //}); foreach (MethodDetails? md in exitMethods) { - md.ActingInstance = Context.SereinIoc.GetOrInstantiate(md.ActingInstanceType); - object?[]? args = [Context]; object?[]? data = [md.ActingInstance, args]; md.MethodDelegate.DynamicInvoke(data); } @@ -86,53 +152,62 @@ namespace Serein.NodeFlow { Context.NodeRunCts.Cancel(); } - if (MainCts != null && !MainCts.IsCancellationRequested) MainCts.Cancel(); - SereinIoc.Reset(); + if (FlipFlopCts != null && !FlipFlopCts.IsCancellationRequested) + { + FlipFlopCts.Cancel(); + } + FlowState = RunState.Completion; + FlipFlopState = RunState.Completion; }; Context.SereinIoc.Build(); + #endregion + + #region 执行初始化,然后绑定IOC容器,再执行加载时 + foreach (var md in initMethods) // 初始化 - 调用方法 { - md.ActingInstance ??= Context.SereinIoc.GetOrInstantiate(md.ActingInstanceType); - object?[]? args = [Context]; object?[]? data = [md.ActingInstance, args]; md.MethodDelegate.DynamicInvoke(data); } Context.SereinIoc.Build(); foreach (var md in loadingMethods) // 加载 { - md.ActingInstance ??= Context.SereinIoc.GetOrInstantiate(md.ActingInstanceType); - object?[]? args = [Context]; object?[]? data = [md.ActingInstance, args]; md.MethodDelegate.DynamicInvoke(data); - } + } + #endregion - // 运行触发器节点 - var singleFlipflopNodes = flipflopNodes.Select(it => (SingleFlipflopNode)it).ToArray(); - - // 使用 TaskCompletionSource 创建未启动的任务 - var tasks = singleFlipflopNodes.Select(async node => - { - await FlipflopExecute(node, flowEnvironment); - }).ToArray(); - _ = Task.WhenAll(tasks); + + // 节点任务的启动 try { - await Task.Run(async () => + + if (flipflopNodes.Count > 0) { - await startNode.StartExecution(Context); - //await Task.WhenAll([startNode.StartExecution(Context), .. tasks]); - }); + FlipFlopState = RunState.Running; + // 如果存在需要启动的触发器,则开始启动 + FlipFlopCts = SereinIOC.GetOrInstantiate(); + // 使用 TaskCompletionSource 创建未启动的触发器任务 + var tasks = flipflopNodes.Select(async node => + { + await FlipflopExecute(node, env); + }).ToArray(); + _ = Task.WhenAll(tasks); + } + await startNode.StartExecution(Context); // 等待结束 - while (!MainCts.IsCancellationRequested) + if(FlipFlopCts != null) { - await Task.Delay(100); + while (!FlipFlopCts.IsCancellationRequested) + { + await Task.Delay(100); + } } } catch (Exception ex) { await Console.Out.WriteLineAsync(ex.ToString()); } - } /// @@ -140,17 +215,15 @@ namespace Serein.NodeFlow /// private async Task FlipflopExecute(SingleFlipflopNode singleFlipFlopNode, IFlowEnvironment flowEnvironment) { - DynamicContext context = new DynamicContext(SereinIoc, flowEnvironment); + DynamicContext context = new DynamicContext(SereinIOC, flowEnvironment); MethodDetails md = singleFlipFlopNode.MethodDetails; var del = md.MethodDelegate; try { - - //var func = md.ExplicitDatas.Length == 0 ? (Func>>)del : (Func>>)del; var func = md.ExplicitDatas.Length == 0 ? (Func>)del : (Func>)del; - while (!MainCts.IsCancellationRequested) // 循环中直到栈为空才会退出 + while (!FlipFlopCts.IsCancellationRequested) // 循环中直到栈为空才会退出 { object?[]? parameters = singleFlipFlopNode.GetParameters(context, md); // 调用委托并获取结果 @@ -168,7 +241,7 @@ namespace Serein.NodeFlow var tasks = singleFlipFlopNode.SuccessorNodes[connection].Select(nextNode => { - var context = new DynamicContext(SereinIoc,flowEnvironment); + var context = new DynamicContext(SereinIOC,flowEnvironment); nextNode.PreviousNode = singleFlipFlopNode; return nextNode.StartExecution(context); }).ToArray(); diff --git a/NodeFlow/Tool/MethodDetailsHelper.cs b/NodeFlow/Tool/MethodDetailsHelper.cs index 1c33a04..ab695e7 100644 --- a/NodeFlow/Tool/MethodDetailsHelper.cs +++ b/NodeFlow/Tool/MethodDetailsHelper.cs @@ -7,16 +7,6 @@ using System.Reflection; namespace Serein.NodeFlow.Tool; - -//public static class DelegateCache -//{ -// /// -// /// 委托缓存全局字典 -// /// -// //public static ConcurrentDictionary GlobalDicDelegates { get; } = new ConcurrentDictionary(); -//} - - public static class MethodDetailsHelperTmp { /// @@ -211,190 +201,3 @@ public static class MethodDetailsHelperTmp } - -public static class MethodDetailsHelper -{ - // 缓存的实例对象(键:类型名称) - // public static ConcurrentDictionary DynamicInstanceToType { get; } = new ConcurrentDictionary(); - // 缓存的实例对象 (键:生成的方法名称) - // public static ConcurrentDictionary DynamicInstance { get; } = new ConcurrentDictionary(); - - - /// - /// 生成方法信息 - /// - /// - /// - /// - public static ConcurrentDictionary GetDict(ISereinIoc serviceContainer, Type type, bool isNetFramework) - { - var methodDetailsDictionary = new ConcurrentDictionary(); - var assemblyName = type.Assembly.GetName().Name; - var methods = GetMethodsToProcess(type, isNetFramework); - - foreach (var method in methods) - { - - var methodDetails = CreateMethodDetails(serviceContainer, type, method, assemblyName, isNetFramework); - - methodDetailsDictionary.TryAdd(methodDetails.MethodName, methodDetails); - } - - return methodDetailsDictionary; - } - /// - /// 获取处理方法 - /// - private static IEnumerable GetMethodsToProcess(Type type, bool isNetFramework) - { - if (isNetFramework) - { - - return type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) - .Where(m => m.GetCustomAttribute()?.Scan == true); - } - else - { - - return type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) - .Where(m => m.GetCustomAttribute()?.Scan == true); - } - } - /// - /// 创建方法信息 - /// - /// - private static MethodDetails CreateMethodDetails(ISereinIoc serviceContainer, Type type, MethodInfo method, string assemblyName, bool isNetFramework) - { - - var methodName = method.Name; - var attribute = method.GetCustomAttribute(); - var explicitDataOfParameters = GetExplicitDataOfParameters(method.GetParameters()); - // 生成委托 - var methodDelegate = GenerateMethodDelegate(type, // 方法所在的对象类型 - method, // 方法信息 - method.GetParameters(),// 方法参数 - method.ReturnType);// 返回值 - - - var dllTypeName = $"{assemblyName}.{type.Name}"; - serviceContainer.Register(type); - object instance = serviceContainer.GetOrCreateServiceInstance(type); - var dllTypeMethodName = $"{assemblyName}.{type.Name}.{method.Name}"; - - return new MethodDetails - { - ActingInstanceType = type, - ActingInstance = instance, - MethodName = dllTypeMethodName, - MethodDelegate = methodDelegate, - MethodDynamicType = attribute.MethodDynamicType, - MethodLockName = attribute.LockName, - MethodTips = attribute.MethodTips, - ExplicitDatas = explicitDataOfParameters, - ReturnType = method.ReturnType, - }; - - } - - private static ExplicitData[] GetExplicitDataOfParameters(ParameterInfo[] parameters) - { - - return parameters.Select((it, index) => - { - //Console.WriteLine($"{it.Name}-{it.HasDefaultValue}-{it.DefaultValue}"); - string explicitTypeName = GetExplicitTypeName(it.ParameterType); - var items = GetExplicitItems(it.ParameterType, explicitTypeName); - if ("Bool".Equals(explicitTypeName)) explicitTypeName = "Select"; // 布尔值 转为 可选类型 - - - - return new ExplicitData - { - IsExplicitData = it.HasDefaultValue, - Index = index, - ExplicitType = it.ParameterType, - ExplicitTypeName = explicitTypeName, - DataType = it.ParameterType, - ParameterName = it.Name, - DataValue = it.HasDefaultValue ? it.DefaultValue.ToString() : "", - Items = items.ToArray(), - }; - - - - }).ToArray(); - } - - private static string GetExplicitTypeName(Type type) - { - return type switch - { - Type t when t.IsEnum => "Select", - Type t when t == typeof(bool) => "Bool", - Type t when t == typeof(string) => "Value", - Type t when t == typeof(int) => "Value", - Type t when t == typeof(double) => "Value", - _ => "Value" - }; - } - - private static IEnumerable GetExplicitItems(Type type, string explicitTypeName) - { - return explicitTypeName switch - { - "Select" => Enum.GetNames(type), - "Bool" => ["True", "False"], - _ => [] - }; - - } - - private static Delegate GenerateMethodDelegate(Type type, MethodInfo methodInfo, ParameterInfo[] parameters, Type returnType) - { - var parameterTypes = parameters.Select(p => p.ParameterType).ToArray(); - var parameterCount = parameters.Length; - - if (returnType == typeof(void)) - { - if (parameterCount == 0) - { - // 无返回值,无参数 - return ExpressionHelper.MethodCaller(type, methodInfo); - } - else - { - // 无返回值,有参数 - return ExpressionHelper.MethodCaller(type, methodInfo, parameterTypes); - } - } - // else if (returnType == typeof(Task public partial class MainWindow : Window { - /// - /// 一种轻量的IOC容器 - /// - private SereinIoc ServiceContainer { get; } = new SereinIoc(); - /// /// 全局捕获Console输出事件,打印在这个窗体里面 /// private readonly LogWindow logWindow; - /// - /// 存储加载的程序集 - /// - // private readonly List loadedAssemblies = []; - /// - /// 存储加载的程序集路径 - /// - // private readonly List loadedAssemblyPaths = []; - - /// - /// 存储所有方法信息 - /// - // private static ConcurrentDictionary DllMethodDetails { get; } = []; - - /// - /// 存储所有与节点有关的控件 - /// - private readonly Dictionary NodeControls = []; - /// - /// 存储所有的连接 - /// - private readonly List Connections = []; - - /// - /// 存放触发器节点(运行时全部调用) - /// - // private readonly List flipflopNodes = []; - /// /// 节点的命名空间 /// public const string NodeSpaceName = $"{nameof(Serein)}.{nameof(Serein.NodeFlow)}.{nameof(Serein.NodeFlow.Model)}"; + /// /// 流程运行环境 /// - private IFlowEnvironment FlowEnvironment; + private IFlowEnvironment FlowEnvironment { get; } + private MainWindowViewModel ViewModel { get; set; } + /// - /// 流程启动器 + /// 存储所有与节点有关的控件 /// - // private FlowStarter nodeFlowStarter; + private Dictionary NodeControls { get; } = []; + /// + /// 存储所有的连接 + /// + private List Connections { get; } = []; + + #region 与画布相关的字段 - /// /// 当前选取的控件 /// private readonly List selectControls = []; + /// + /// 拖动创建节点控件时的鼠标位置 + /// + private Point canvasDropPosition; + /// /// 记录拖动开始时的鼠标位置 /// @@ -154,20 +134,14 @@ namespace Serein.WorkBench private TranslateTransform translateTransform; #endregion - private Point canvasDropPosition; - - - // private MainWindowViewModel mainWindowViewModel { get; } public MainWindow() { - // mainWindowViewModel = new MainWindowViewModel(this); - InitializeComponent(); + ViewModel = new MainWindowViewModel(this); + FlowEnvironment = ViewModel.FlowEnvironment; - - + InitializeComponent(); logWindow = new LogWindow(); logWindow.Show(); - // 重定向 Console 输出 var logTextWriter = new LogTextWriter(WriteLog); Console.SetOut(logTextWriter); @@ -177,7 +151,6 @@ namespace Serein.WorkBench private void InitFlowEvent() { - FlowEnvironment = new FlowEnvironment(); FlowEnvironment.OnDllLoad += FlowEnvironment_DllLoadEvent; FlowEnvironment.OnLoadNode += FlowEnvironment_NodeLoadEvent; FlowEnvironment.OnStartNodeChange += FlowEnvironment_StartNodeChangeEvent; @@ -188,8 +161,6 @@ namespace Serein.WorkBench } - - private void InitUI() { canvasTransformGroup = new TransformGroup(); @@ -226,7 +197,6 @@ namespace Serein.WorkBench WriteLog("-------运行完成---------\r\n"); } - /// /// 加载了DLL文件,dll内容 /// @@ -287,23 +257,8 @@ namespace Serein.WorkBench NodeControls.TryAdd(nodeInfo.Guid, nodeControl); // 存放对应的控件 PlaceNodeOnCanvas(nodeControl, nodeInfo.Position.X, nodeInfo.Position.Y); // 配置节点,并放置在画布上 - - - // 添加到画布 - //FlowChartCanvas.Dispatcher.Invoke(() => - //{ - // // 添加控件到画布 - // FlowChartCanvas.Children.Add(nodeControl); - // Canvas.SetLeft(nodeControl, nodeInfo.Position.x); - // Canvas.SetTop(nodeControl, nodeInfo.Position.y); - // nodeControls.TryAdd(nodeInfo.Guid, nodeControl); // 存放对应的控件 - // ConfigureContextMenu(nodeControl); // 配置节点右键菜单 - // ConfigureNodeEvents(nodeControl); // 配置节点事件 - //}); - } - /// /// 节点连接关系变更 /// @@ -319,7 +274,7 @@ namespace Serein.WorkBench return; } ConnectionType connectionType = eventArgs.ConnectionType; - if(eventArgs.ChangeType == NodeConnectChangeEventArgs.ChangeTypeEnum.Create) + if(eventArgs.ChangeType == NodeConnectChangeEventArgs.ConnectChangeType.Create) { // 添加连接 var connection = new Connection @@ -334,7 +289,7 @@ namespace Serein.WorkBench Connections.Add(connection); EndConnection(); } - else if (eventArgs.ChangeType == NodeConnectChangeEventArgs.ChangeTypeEnum.Remote) + else if (eventArgs.ChangeType == NodeConnectChangeEventArgs.ConnectChangeType.Remote) { // 需要移除连接 var removeConnections = Connections.Where(c => c.Start.ViewModel.Node.Guid.Equals(fromNodeGuid) @@ -1403,7 +1358,7 @@ namespace Serein.WorkBench /// private void ButtonDebugFlipflopNode_Click(object sender, RoutedEventArgs e) { - FlowEnvironment.Exit(); + FlowEnvironment.Exit(); // 在运行平台上点击了退出 } /// diff --git a/WorkBench/MainWindowViewModel.cs b/WorkBench/MainWindowViewModel.cs index c22f689..0aa9541 100644 --- a/WorkBench/MainWindowViewModel.cs +++ b/WorkBench/MainWindowViewModel.cs @@ -1,4 +1,5 @@ -using Serein.Library.Attributes; +using Serein.Library.Api; +using Serein.Library.Attributes; using Serein.Library.Entity; using Serein.Library.Utils; using Serein.NodeFlow; @@ -18,64 +19,13 @@ namespace Serein.WorkBench public class MainWindowViewModel { private readonly MainWindow window ; + public IFlowEnvironment FlowEnvironment { get; set; } public MainWindowViewModel(MainWindow window) { FlowEnvironment = new FlowEnvironment(); this.window = window; } - public FlowEnvironment FlowEnvironment { get; set; } - - #region 加载项目文件 - public void LoadProjectFile(SereinOutputFileData projectFile) - { - var dllPaths = projectFile.Librarys.Select(it => it.Path).ToList(); - foreach (var dll in dllPaths) - { - var filePath = System.IO.Path.GetFullPath(System.IO.Path.Combine(App.FileDataPath, dll)); - //LoadAssembly(filePath); - } - } - - - - - - private void DisplayControlDll(Assembly assembly, - List conditionTypes, - List actionTypes, - List flipflopMethods) - { - - var dllControl = new DllControl - { - Header = "DLL name : " + assembly.GetName().Name // 设置控件标题为程序集名称 - }; - - - foreach (var item in actionTypes) - { - dllControl.AddAction(item.Clone()); // 添加动作类型到控件 - } - foreach (var item in flipflopMethods) - { - dllControl.AddFlipflop(item.Clone()); // 添加触发器方法到控件 - } - - /*foreach (var item in stateTypes) - { - dllControl.AddState(item); - }*/ - - window.DllStackPanel.Children.Add(dllControl); // 将控件添加到界面上显示 - } - - - - #endregion - - - } } diff --git a/WorkBench/Node/NodeBase.cs b/WorkBench/Node/NodeBase.cs deleted file mode 100644 index 2dd99f2..0000000 --- a/WorkBench/Node/NodeBase.cs +++ /dev/null @@ -1,270 +0,0 @@ -namespace DySerin; - - - - - - -/*public class ConditionNode : NodeBase, ICondition -{ - private Func ConditionFunc { get; set; } - - public ConditionNode(Func conditionFunc) - { - ConditionFunc = conditionFunc; - } - - public override void Execute() - { - if (ConditionFunc()) - { - EnterTrueBranch(); - } - else - { - EnterFalseBranch(); - } - } - - // 实现条件接口的方法 - public bool Evaluate(DynamicContext context) - { - Context = context; // 更新节点的上下文 - return ConditionFunc(); - } -} - - - -public class ActionNode : NodeBase, IAction -{ - private Action ActionMethod { get; set; } - - public ActionNode(Action actionMethod) - { - ActionMethod = actionMethod; - } - - public override void Execute() - { - try - { - ActionMethod(); - EnterTrueBranch(); // 动作成功,进入真分支 - } - catch (Exception ex) - { - // 可添加异常处理逻辑 - Return(); // 动作失败,终止节点 - } - } - - // 实现动作接口的方法 - public void Execute(DynamicContext context) - { - Context = context; // 更新节点的上下文 - Execute(); - } -} - - - - - -*/ - - - - - - - -/* -/// -/// 根节点 -/// -public abstract class NodeControl : UserControl -{ - public string Id { get; set; } - public string Name { get; set; } - - public abstract void Execute(NodeContext context); -} - -/// -/// 条件节点 -/// -public class ConditionNodeControl : NodeControl -{ - public Func Condition { get; set; } - public NodeControl TrueNode { get; set; } - public NodeControl FalseNode { get; set; } - - public ConditionNodeControl() - { - this.Content = new TextBlock { Text = "条件节点" }; - this.Background = Brushes.LightBlue; - } - - public override void Execute(NodeContext context) - { - if (Condition(context)) - { - TrueNode?.Execute(context); - } - else - { - FalseNode?.Execute(context); - } - } -} - -/// -/// 动作节点 -/// -public class ActionNodeControl : NodeControl -{ - public Action Action { get; set; } - - public ActionNodeControl() - { - this.Content = new TextBlock { Text = "动作节点" }; - this.Background = Brushes.LightGreen; - } - - public override void Execute(NodeContext context) - { - Action?.Invoke(context); - } -} - - -/// -/// 状态节点 -/// -public class StateNodeControl : NodeControl -{ - public Func StateFunction { get; set; } - - public StateNodeControl() - { - this.Content = new TextBlock { Text = "状态节点" }; - this.Background = Brushes.LightYellow; - } - - public override void Execute(NodeContext context) - { - var result = StateFunction(context); - context.Set("StateResult", result); - } -} - -/// -/// 节点上下文 -/// -public class NodeContext -{ - private readonly Dictionary _data = new Dictionary(); - - public void Set(string key, T value) - { - _data[key] = value; - } - - public T Get(string key) - { - return _data.ContainsKey(key) ? (T)_data[key] : default; - } -} -*/ - -/* -public class Context -{ - public Dictionary Data { get; set; } = new Dictionary(); - public void Set(string key, T value) - { - Data[key] = value; - } - - public T Get(string key) - { - return Data.ContainsKey(key) ? (T)Data[key] : default; - } -} - -public interface INode -{ - Context Enter(Context context); - Context Exit(Context context); -} - - - -public partial class ConditionNode : INode -{ - public Func Condition { get; set; } - public INode TrueBranch { get; set; } - public INode FalseBranch { get; set; } - - public Context Enter(Context context) - { - if (Condition(context)) - { - return TrueBranch?.Enter(context) ?? context; - } - else - { - return FalseBranch?.Enter(context) ?? context; - } - } - - public Context Exit(Context context) - { - return context; - } - - - -} - -public partial class ActionNode : INode -{ - public Action Action { get; set; } - public bool IsTask { get; set; } - - public Context Enter(Context context) - { - if (IsTask) - { - Task.Run(() => Action(context)); - } - else - { - Action(context); - } - return context; - } - - public Context Exit(Context context) - { - return context; - } -} - -public partial class StateNode : INode -{ - public Context Enter(Context context) - { - return context; - } - - public Context Exit(Context context) - { - return context; - } -} - - - -*/ diff --git a/WorkBench/Themes/TypeViewerWindow.xaml.cs b/WorkBench/Themes/TypeViewerWindow.xaml.cs index 64ac0ba..631d5aa 100644 --- a/WorkBench/Themes/TypeViewerWindow.xaml.cs +++ b/WorkBench/Themes/TypeViewerWindow.xaml.cs @@ -40,6 +40,11 @@ namespace Serein.WorkBench.Themes TypeTreeView.Items.Add(rootNode); } + /// + /// 添加属性节点 + /// + /// + /// private void AddMembersToTreeNode(TreeViewItem node, Type type) { var members = type.GetMembers(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly); @@ -61,6 +66,7 @@ namespace Serein.WorkBench.Themes memberNode.Header = $"{member.Name} : {propertyType.Name}"; if (!propertyType.IsPrimitive && propertyType != typeof(string)) { + // 递归显示类型属性的节点 AddMembersToTreeNode(memberNode, propertyType); } }