diff --git a/Extend.FlowRemoteManagement/Model/ConnectionInfoData.cs b/Extend.FlowRemoteManagement/Model/ConnectionInfoData.cs deleted file mode 100644 index c8f4fb7..0000000 --- a/Extend.FlowRemoteManagement/Model/ConnectionInfoData.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Serein.FlowRemoteManagement.Model -{ - public class ConnectionInfoData - { - public bool Op { get; set; } - public string? FromNodeGuid { get; set; } - public string? ToNodeGuid { get; set; } - // None Upstream IsSucceed IsFail IsError - public string? Type { get; set; } - } -} diff --git a/Extend.FlowRemoteManagement/Serein.Extend.RemoteControl.csproj b/Extend.FlowRemoteManagement/Serein.Extend.RemoteControl.csproj deleted file mode 100644 index 5abb2a8..0000000 --- a/Extend.FlowRemoteManagement/Serein.Extend.RemoteControl.csproj +++ /dev/null @@ -1,18 +0,0 @@ - - - - 1.0.0 - net8.0 - enable - enable - D:\Project\C#\DynamicControl\SereinFlow\.Output - - - - - - - - - - diff --git a/Extend.FlowRemoteManagement/SereinFlowRemoteControl.cs b/Extend.FlowRemoteManagement/SereinFlowRemoteControl.cs deleted file mode 100644 index 7a7722a..0000000 --- a/Extend.FlowRemoteManagement/SereinFlowRemoteControl.cs +++ /dev/null @@ -1,167 +0,0 @@ - -using Serein.Library; -using Serein.Library.Api; -using Serein.Library.Network.WebSocketCommunication; -using System.Security.Cryptography.X509Certificates; -using Serein.NodeFlow; -using Serein.Library.Core.NodeFlow; -using Serein.Library.Utils; -using Serein.FlowRemoteManagement.Model; -using System.Reflection; -using Serein.Library.FlowNode; - -namespace SereinFlowRemoteManagement -{ - - - /// - /// SereinFlow 远程控制模块 - /// - [DynamicFlow] - [AutoRegister] - [AutoSocketModule(ThemeKey ="theme",DataKey ="data")] - public class SereinFlowRemoteControl : ISocketHandleModule - { - public int ServerPort { get; set; } = 7525; - - #region 初始化服务端 - public Guid HandleGuid { get; } = new Guid(); - - private readonly IFlowEnvironment environment; - public SereinFlowRemoteControl(IFlowEnvironment environment) - { - this.environment = environment; - } - - [NodeAction(NodeType.Init)] - public void Init(IDynamicContext context) - { - environment.IOC.Register(); - } - - [NodeAction(NodeType.Loading)] - public async Task Loading(IDynamicContext context) - { - environment.IOC.Run(async (socketServer) => - { - socketServer.MsgHandleHelper.AddModule(this, - (ex, send) => - { - send(new - { - code = 400, - ex = ex.Message - }); - }); - await Console.Out.WriteLineAsync("启动远程管理模块"); - await socketServer.StartAsync($"http://*:{ServerPort}/"); - }); - SereinProjectData projectData = await environment.GetProjectInfoAsync(); - } - #endregion - - #region 流程运行接口 - - /// - /// 连接到运行环境,获取当前的节点信息 - /// - /// - /// - [AutoSocketHandle] - public async Task ConnectWorkBench(Func Send) - { - await Send("尝试获取"); - - try - { - var envInfo = this.environment.GetEnvInfoAsync(); - return envInfo; - } - catch (Exception ex) - { - await Send(ex.Message); - return null; - } - } - - public void AddNode(string nodeType,string methodName,int x, int y) - { - if(x <= 0 || y <= 0) - { - throw new InvalidOperationException("坐标错误"); - } - if (!EnumHelper.TryConvertEnum(nodeType, out var connectionType)) - { - throw new InvalidOperationException("类型错误"); - } - - if (this.environment.TryGetMethodDetailsInfo(methodName,out var mdInfo)) - { - this.environment.CreateNode(connectionType, new PositionOfUI(x, y), mdInfo); // - } - - - } - - /// - /// 远程更改两个节点的连接关系 - /// - /// - /// - /// - [AutoSocketHandle(ThemeValue = "ConnectionChange")] - public void ChangeNodeConnection(ConnectionInfoData nodeInfo, Func Send) - { - if (string.IsNullOrEmpty(nodeInfo.FromNodeGuid) || string.IsNullOrEmpty(nodeInfo.ToNodeGuid)) - { - throw new InvalidOperationException("Guid错误"); - } - if (!EnumHelper.TryConvertEnum(nodeInfo.Type, out var connectionType)) - { - throw new InvalidOperationException("类型错误"); - } - - if (nodeInfo.Op) - { - environment.ConnectNodeAsync(nodeInfo.FromNodeGuid, nodeInfo.ToNodeGuid, connectionType); - } - else - { - environment.RemoveConnect(nodeInfo.FromNodeGuid, nodeInfo.ToNodeGuid, connectionType); - } - } - - /// - /// 远程调用某个节点 - /// - [AutoSocketHandle(ThemeValue = "InvokeNode")] - public async Task InvokeNode(string nodeGuid, Func Send) - { - if (string.IsNullOrEmpty(nodeGuid)) - { - throw new InvalidOperationException("Guid错误"); - } - - await environment.StartAsyncInSelectNode(nodeGuid); - - await Send(new - { - state = 200, - tips = "执行完成", - }); - } - - /// - /// 获取项目配置文件信息 - /// - [AutoSocketHandle(ThemeValue = "GetProjectInfo")] - public async Task GetProjectInfo() - { - await Task.Delay(0); - return await environment.GetProjectInfoAsync(); - } - - - #endregion - } -} diff --git a/FlowEdit/SereinFLowEdit(SqlSugar).7z b/FlowEdit/FlowEdit (sqlsugar).7z similarity index 69% rename from FlowEdit/SereinFLowEdit(SqlSugar).7z rename to FlowEdit/FlowEdit (sqlsugar).7z index 826ddea..06184e8 100644 Binary files a/FlowEdit/SereinFLowEdit(SqlSugar).7z and b/FlowEdit/FlowEdit (sqlsugar).7z differ diff --git a/Library/Api/IFlowEnvironment.cs b/Library/Api/IFlowEnvironment.cs index f185196..3da5c7b 100644 --- a/Library/Api/IFlowEnvironment.cs +++ b/Library/Api/IFlowEnvironment.cs @@ -54,10 +54,16 @@ namespace Serein.Library.Api public delegate void NodeCreateHandler(NodeCreateEventArgs eventArgs); /// - /// 容器节点与子项节点的关系发生改变 + /// 节点放置事件 /// /// - public delegate void NodeContainerChildChangeHandler(NodeContainerChildChangeEventArgs eventArgs); + public delegate void NodePlaceHandler(NodePlaceEventArgs eventArgs); + + /// + /// 节点取出事件 + /// + /// + public delegate void NodeTakeOutHandler(NodeTakeOutEventArgs eventArgs); /// /// 环境中流程起始节点发生了改变 @@ -314,51 +320,41 @@ namespace Serein.Library.Api } /// - /// 节点父子关系改变 + /// 节点放置事件参数 /// - public class NodeContainerChildChangeEventArgs : FlowEventArgs + public class NodePlaceEventArgs : FlowEventArgs { - /// - /// 变更类型 - /// - public enum Type + public NodePlaceEventArgs(string nodeGuid, string containerNodeGuid) { - /// - /// 放置 - /// - Place, - /// - /// 取出 - /// - TakeOut - } - /// - /// - /// - /// 子项节点 - /// 容器节点 - /// 类别 - public NodeContainerChildChangeEventArgs(string childNodeGuid, string containerNodeGuid, Type state) - { - ChildNodeGuid = childNodeGuid; + NodeGuid = nodeGuid; ContainerNodeGuid = containerNodeGuid; - State = state; } /// /// 子节点,该数据为此次时间的主节点 /// - public string ChildNodeGuid { get; private set; } + public string NodeGuid { get; private set; } /// /// 父节点 /// public string ContainerNodeGuid { get; private set; } - - /// - /// 改变类型 - /// - public Type State { get; private set; } } + /// + /// 节点取出事件参数 + /// + public class NodeTakeOutEventArgs : FlowEventArgs + { + public NodeTakeOutEventArgs(string nodeGuid) + { + NodeGuid = nodeGuid; + } + /// + /// 需要取出的节点Guid + /// + public string NodeGuid { get; private set; } + } + + /// /// 环境中移除了一个节点 /// @@ -664,9 +660,14 @@ namespace Serein.Library.Api event NodeRemoveHandler OnNodeRemove; /// - /// 节点父子关系发生改变事件 + /// 节点放置事件 /// - event NodeContainerChildChangeHandler OnNodeParentChildChange; + event NodePlaceHandler OnNodePlace; + + /// + /// 节点取出事件 + /// + event NodeTakeOutHandler OnNodeTakeOut; /// /// 起始节点变化事件 @@ -740,6 +741,7 @@ namespace Serein.Library.Api /// 启动远程服务 /// Task StartRemoteServerAsync(int port = 7525); + /// /// 停止远程服务 /// @@ -781,40 +783,29 @@ namespace Serein.Library.Api /// /// void LoadLibrary(string dllPath); + /// /// 移除DLL /// /// 程序集的名称 - bool UnloadLibrary(string assemblyFullName); + bool TryUnloadLibrary(string assemblyFullName); - /// - /// 清理加载的DLL(待更改) - /// - void ClearAll(); - /// /// 开始运行 /// - Task StartAsync(); + Task StartFlowAsync(); + /// /// 从选定的节点开始运行 /// /// /// - Task StartAsyncInSelectNode(string startNodeGuid); - - /// - /// 立刻调用某个节点,并获取其返回值 - /// - /// 调用时的上下文 - /// 节点Guid - /// - Task InvokeNodeAsync(IDynamicContext context, string nodeGuid); + Task StartAsyncInSelectNode(string startNodeGuid); /// /// 结束运行 /// - void ExitFlow(); + Task ExitFlowAsync(); /// /// 移动了某个节点(远程插件使用) @@ -827,8 +818,9 @@ namespace Serein.Library.Api /// /// 设置流程起点节点 /// - /// - void SetStartNode(string nodeGuid); + /// 尝试设置为起始节点的节点Guid + /// 被设置为起始节点的Guid + Task SetStartNodeAsync(string nodeGuid); /// /// 在两个节点之间创建连接关系 @@ -875,14 +867,27 @@ namespace Serein.Library.Api /// 节点绑定的方法说明 Task CreateNodeAsync(NodeControlType nodeType, PositionOfUI position, MethodDetailsInfo methodDetailsInfo = null); + ///// + ///// 将节点放置在容器中/从容器中取出 + ///// + ///// 子节点(主要节点) + ///// 父节点 + ///// 是否组合(反之为分解节点组合关系) + ///// + //Task ChangeNodeContainerChildAsync(string childNodeGuid,string parentNodeGuid,bool isAssembly); + /// - /// 将节点放置在容器中/从容器中取出 + /// 将节点放置在容器中 /// - /// 子节点(主要节点) - /// 父节点 - /// 是否组合(反之为分解节点组合关系) /// - Task ChangeNodeContainerChild(string childNodeGuid,string parentNodeGuid,bool isAssembly); + Task PlaceNodeToContainerAsync(string nodeGuid, string containerNodeGuid); + + /// + /// 将节点从容器中脱离 + /// + /// + Task TakeOutNodeToContainerAsync(string nodeGuid); + /// /// 设置两个节点某个类型的方法调用关系为优先调用 @@ -910,7 +915,6 @@ namespace Serein.Library.Api /// 参数来源类型 Task RemoveConnectArgSourceAsync(string fromNodeGuid, string toNodeGuid, int argIndex); - /// /// 移除节点/区域/基础控件 /// @@ -1035,6 +1039,13 @@ namespace Serein.Library.Api /// 中断类型。0主动监视,1表达式 void TriggerInterrupt(string nodeGuid, string expression, InterruptTriggerEventArgs.InterruptTriggerType type); + /// + /// 立刻调用某个节点,并获取其返回值 + /// + /// 调用时的上下文 + /// 节点Guid + /// + Task InvokeNodeAsync(IDynamicContext context, string nodeGuid); #endregion diff --git a/Library/FlowNode/NodeModelBaseData.cs b/Library/FlowNode/NodeModelBaseData.cs index f7bb63a..aa95c7e 100644 --- a/Library/FlowNode/NodeModelBaseData.cs +++ b/Library/FlowNode/NodeModelBaseData.cs @@ -105,12 +105,12 @@ namespace Serein.Library public Dictionary> SuccessorNodes { get; } /// - /// 该节点的父级节点(容器) + /// 该节点的容器节点 /// - public NodeModelBase ParentNode { get; set; } = null; + public NodeModelBase ContainerNode { get; set; } = null; /// - /// 该节点的子项节点(容器) + /// 该节点的子项节点(如果该节点是容器节点,那就会有这个参数) /// public List ChildrenNode { get; } diff --git a/Library/FlowNode/NodeModelBaseFunc.cs b/Library/FlowNode/NodeModelBaseFunc.cs index 2b75bf3..11407b6 100644 --- a/Library/FlowNode/NodeModelBaseFunc.cs +++ b/Library/FlowNode/NodeModelBaseFunc.cs @@ -164,7 +164,7 @@ namespace Serein.Library IsProtectionParameter = this.MethodDetails.IsProtectionParameter, IsInterrupt = this.DebugSetting.IsInterrupt, IsEnable = this.DebugSetting.IsEnable, - ParentNodeGuid = ParentNode?.Guid, + ParentNodeGuid = ContainerNode?.Guid, ChildNodeGuids = ChildrenNode.Select(item => item.Guid).ToArray(), }; nodeInfo.Position.X = Math.Round(nodeInfo.Position.X, 1); diff --git a/Library/Utils/SereinEnv.cs b/Library/Utils/SereinEnv.cs index ff81f11..f551f42 100644 --- a/Library/Utils/SereinEnv.cs +++ b/Library/Utils/SereinEnv.cs @@ -124,6 +124,16 @@ namespace Serein.Library.Utils { SereinEnv.environment.WriteLine(type,message,@class); } + + /// + /// 输出异常信息 + /// + /// + /// + public static void WriteLine(Exception ex, InfoClass @class = InfoClass.General) + { + SereinEnv.environment.WriteLine(InfoType.ERROR, ex.ToString(), @class); + } diff --git a/NodeFlow/Env/EnvMsgTheme.cs b/NodeFlow/Env/EnvMsgTheme.cs index a243aa3..15bf610 100644 --- a/NodeFlow/Env/EnvMsgTheme.cs +++ b/NodeFlow/Env/EnvMsgTheme.cs @@ -38,6 +38,14 @@ /// public const string RemoveNode = nameof(RemoveNode); /// + /// 尝试放置节点 + /// + public const string PlaceNode = nameof(PlaceNode); + /// + /// 尝试取出节点 + /// + public const string TakeOutNode = nameof(TakeOutNode); + /// /// 尝试连接两个节点的方法调用关系 /// public const string ConnectInvokeNode = nameof(ConnectInvokeNode); diff --git a/NodeFlow/Env/FlowEnvironment.cs b/NodeFlow/Env/FlowEnvironment.cs index c7eb290..1b58346 100644 --- a/NodeFlow/Env/FlowEnvironment.cs +++ b/NodeFlow/Env/FlowEnvironment.cs @@ -152,9 +152,14 @@ namespace Serein.NodeFlow.Env public event NodeRemoveHandler? OnNodeRemove; /// - /// 节点父子关系发生改变事件 + /// 节点放置事件 /// - public event NodeContainerChildChangeHandler OnNodeParentChildChange; + public event NodePlaceHandler OnNodePlace; + + /// + /// 节点取出事件 + /// + public event NodeTakeOutHandler OnNodeTakeOut; /// /// 起始节点变化事件 @@ -350,15 +355,6 @@ namespace Serein.NodeFlow.Env #region 环境对外接口 - ///// - ///// 重定向Console输出 - ///// - //public void SetConsoleOut() - //{ - // var logTextWriter = new LogTextWriter(msg => Output(msg)); - // Console.SetOut(logTextWriter); - //} - /// /// 输出信息 /// @@ -375,25 +371,11 @@ namespace Serein.NodeFlow.Env } - ///// - ///// 使用JSON处理库输出对象信息 - ///// - ///// - //public void WriteLineObjToJson(object obj) - //{ - // var msg = JsonConvert.SerializeObject(obj); - // if (OperatingSystem.IsWindows()) - // { - // UIContextOperation?.Invoke(() => OnEnvOut?.Invoke(msg + Environment.NewLine)); - // } - - //} - /// /// 异步运行 /// /// - public async Task StartAsync() + public async Task StartFlowAsync() { ChannelFlowInterrupt?.CancelAllTasks(); flowStarter = new FlowStarter(); @@ -416,13 +398,16 @@ namespace Serein.NodeFlow.Env // 注册封装好的UI线程上下文 IOC.CustomRegisterInstance(typeof(UIContextOperation).FullName, this.UIContextOperation, false); } - - await flowStarter.RunAsync(this, nodes, autoRegisterTypes, initMethods, loadMethods, exitMethods); - - if (FlipFlopState == RunState.Completion) + _ = Task.Run(async () => { - ExitFlow(); // 未运行触发器时,才会调用结束方法 - } + await flowStarter.RunAsync(this, nodes, autoRegisterTypes, initMethods, loadMethods, exitMethods); + if (FlipFlopState == RunState.Completion) + { + await ExitFlowAsync(); // 未运行触发器时,才会调用结束方法 + } + }); + return true; + } @@ -431,20 +416,20 @@ namespace Serein.NodeFlow.Env /// /// /// - public async Task StartAsyncInSelectNode(string startNodeGuid) + public async Task StartAsyncInSelectNode(string startNodeGuid) { if (flowStarter is null) { SereinEnv.WriteLine(InfoType.ERROR, "没有启动流程,无法运行单个节点"); - return; + return false; } if (true || FlowState == RunState.Running || FlipFlopState == RunState.Running) { NodeModelBase? nodeModel = GuidToModel(startNodeGuid); if (nodeModel is null || nodeModel is SingleFlipflopNode) { - return; + return false; } //var getExp = "@get .DebugSetting.IsEnable"; //var getExpResult1 = SerinExpressionEvaluator.Evaluate(getExp, nodeModel,out _); @@ -453,10 +438,11 @@ namespace Serein.NodeFlow.Env //var getExpResult2 = SerinExpressionEvaluator.Evaluate(getExp, nodeModel, out _); await flowStarter.StartFlowInSelectNodeAsync(this, nodeModel); + return true; } else { - return; + return false; } } @@ -478,21 +464,20 @@ namespace Serein.NodeFlow.Env /// /// 结束流程 /// - public void ExitFlow() + public Task ExitFlowAsync() { ChannelFlowInterrupt?.CancelAllTasks(); flowStarter?.Exit(); UIContextOperation?.Invoke(() => OnFlowRunComplete?.Invoke(new FlowEventArgs())); flowStarter = null; GC.Collect(); - + return Task.FromResult(true); } /// /// 激活全局触发器 /// /// - // [AutoSocketHandle] public void ActivateFlipflopNode(string nodeGuid) { var nodeModel = GuidToModel(nodeGuid); @@ -512,7 +497,6 @@ namespace Serein.NodeFlow.Env /// 关闭全局触发器 /// /// - // [AutoSocketHandle] public void TerminateFlipflopNode(string nodeGuid) { var nodeModel = GuidToModel(nodeGuid); @@ -541,16 +525,6 @@ namespace Serein.NodeFlow.Env }; } - /// - /// 清除所有 - /// - public void ClearAll() - { - //LoadedAssemblyPaths.Clear(); - //NodeLibrarys.Clear(); - //MethodDetailss.Clear(); - - } /// /// 保存项目 @@ -582,7 +556,7 @@ namespace Serein.NodeFlow.Env } _ = LoadNodeInfosAsync(projectData.Nodes.ToList()); - SetStartNode(projectData.StartNode); + SetStartNodeAsync(projectData.StartNode); } @@ -686,7 +660,7 @@ namespace Serein.NodeFlow.Env /// /// /// - public bool UnloadLibrary(string assemblyName) + public bool TryUnloadLibrary(string assemblyName) { // 获取与此程序集相关的节点 var groupedNodes = NodeModels.Values.Where(node => node.MethodDetails.AssemblyName.Equals(assemblyName)).ToArray(); @@ -773,7 +747,6 @@ namespace Serein.NodeFlow.Env /// public Task LoadNodeInfosAsync(List nodeInfos) { - List needPlaceNodeInfos = []; #region 从NodeInfo创建NodeModel foreach (NodeInfo? nodeInfo in nodeInfos) { @@ -805,27 +778,36 @@ namespace Serein.NodeFlow.Env } nodeModel.LoadInfo(nodeInfo); // 创建节点model TryAddNode(nodeModel); // 加载项目时将节点加载到环境中 - if (!string.IsNullOrEmpty(nodeInfo.ParentNodeGuid) && - NodeModels.TryGetValue(nodeInfo.ParentNodeGuid, out var parentNode)) - { - needPlaceNodeInfos.Add(nodeInfo); // 需要重新放置的节点 - } + UIContextOperation?.Invoke(() => OnNodeCreate?.Invoke(new NodeCreateEventArgs(nodeModel, nodeInfo.Position))); // 添加到UI上 } #endregion #region 重新放置节点 - foreach (NodeInfo nodeInfo in needPlaceNodeInfos) + + List needPlaceNodeInfos = []; + foreach (NodeInfo? nodeInfo in nodeInfos) { - if (NodeModels.TryGetValue(nodeInfo.Guid, out var childNode) && + if (!string.IsNullOrEmpty(nodeInfo.ParentNodeGuid) && NodeModels.TryGetValue(nodeInfo.ParentNodeGuid, out var parentNode)) { - childNode.ParentNode = parentNode; - parentNode.ChildrenNode.Add(childNode); - UIContextOperation?.Invoke(() => OnNodeParentChildChange?.Invoke( - new NodeContainerChildChangeEventArgs(childNode.Guid, parentNode.Guid, - NodeContainerChildChangeEventArgs.Type.Place))); + needPlaceNodeInfos.Add(nodeInfo); // 需要重新放置的节点 + } + } + + foreach (NodeInfo nodeInfo in needPlaceNodeInfos) + { + if (NodeModels.TryGetValue(nodeInfo.Guid, out var nodeMoel) && + NodeModels.TryGetValue(nodeInfo.ParentNodeGuid, out var containerNode) + && containerNode is INodeContainer nodeContainer) + { + nodeMoel.ContainerNode = containerNode; // 放置节点 + containerNode.ChildrenNode.Add(nodeMoel); + nodeContainer.PlaceNode(nodeMoel); + + UIContextOperation?.Invoke(() => OnNodePlace?.Invoke( + new NodePlaceEventArgs(nodeMoel.Guid, containerNode.Guid))); } } @@ -935,40 +917,57 @@ namespace Serein.NodeFlow.Env return Task.FromResult(nodeInfo); } + /// - /// 将节点放置在容器中/从容器中取出 + /// 将节点放置在容器中 /// - /// 子节点(主要节点) - /// 父节点 - /// 是否组合(反之为分解节点组合关系) /// - public async Task ChangeNodeContainerChild(string childNodeGuid, string parentNodeGuid, bool isPlace) + public async Task PlaceNodeToContainerAsync(string nodeGuid, string containerNodeGuid) { - // 获取起始节点与目标节点 - var childNode = GuidToModel(childNodeGuid); - var parentNode = GuidToModel(parentNodeGuid); - if (childNode is null || parentNode is null || parentNode is not INodeContainer nodeContainer) return false; + // 获取目标节点与容器节点 + var nodeMoel = GuidToModel(nodeGuid); + if (nodeMoel is null ) return false; - if (isPlace) + if(nodeMoel.ContainerNode is INodeContainer tmpContainer) { - // 放置节点 - parentNode.ChildrenNode.Add(childNode); - childNode.ParentNode = parentNode; - nodeContainer.PlaceNode(childNode); - } - else - { - // 取出节点 - parentNode.ChildrenNode.Remove(childNode); - childNode.ParentNode = null; - nodeContainer.TakeOutNode(childNode); + SereinEnv.WriteLine(InfoType.WARN, $"节点放置失败,节点[{nodeGuid}]已经放置于容器节点[{((NodeModelBase)tmpContainer).Guid}]"); + return false; } - OnNodeParentChildChange?.Invoke(new NodeContainerChildChangeEventArgs(childNodeGuid, parentNodeGuid, - isPlace ? NodeContainerChildChangeEventArgs.Type.Place : NodeContainerChildChangeEventArgs.Type.TakeOut)); + var containerNode = GuidToModel(containerNodeGuid); + if (containerNode is not INodeContainer nodeContainer) return false; + + nodeMoel.ContainerNode = containerNode; // 放置节点 + containerNode.ChildrenNode.Add(nodeMoel); + nodeContainer.PlaceNode(nodeMoel); + OnNodePlace?.Invoke(new NodePlaceEventArgs(nodeGuid, containerNodeGuid)); // 通知UI更改节点放置位置 + return true; + + } + + /// + /// 将节点从容器节点中脱离 + /// + /// + public async Task TakeOutNodeToContainerAsync(string nodeGuid) + { + // 获取目标节点与容器节点 + var nodeMoel = GuidToModel(nodeGuid); + if (nodeMoel is null) return false; + + if(nodeMoel.ContainerNode is not INodeContainer nodeContainer) + { + return false; + } + nodeContainer.TakeOutNode(nodeMoel); // 从容器节点取出 + nodeMoel.ContainerNode = null; // 取消映射关系 + + OnNodeTakeOut?.Invoke(new NodeTakeOutEventArgs(nodeGuid)); // 重新放置在画布上 return true; } + + /// /// 移除节点 /// @@ -1232,11 +1231,13 @@ namespace Serein.NodeFlow.Env /// 设置起点控件 /// /// - public void SetStartNode(string newNodeGuid) + public Task SetStartNodeAsync(string newNodeGuid) { var newStartNodeModel = GuidToModel(newNodeGuid); - if (newStartNodeModel is null) return; + if (newStartNodeModel is null) + return Task.FromResult(StartNode?.Guid ?? string.Empty); SetStartNode(newStartNodeModel); + return Task.FromResult(StartNode?.Guid ?? string.Empty); } /// @@ -1893,11 +1894,11 @@ namespace Serein.NodeFlow.Env { var oldNodeGuid = StartNode?.Guid; StartNode = newStartNode; - if (OperatingSystem.IsWindows()) - { - UIContextOperation?.Invoke(() => OnStartNodeChange?.Invoke(new StartNodeChangeEventArgs(oldNodeGuid, StartNode.Guid))); - } - + UIContextOperation?.Invoke(() => OnStartNodeChange?.Invoke(new StartNodeChangeEventArgs(oldNodeGuid, StartNode.Guid))); + + //if (OperatingSystem.IsWindows()) + //{ + // } } ///// @@ -1910,7 +1911,7 @@ namespace Serein.NodeFlow.Env // { // UIContextOperation?.Invoke(() => OnEnvOut?.Invoke(msg)); // } - + //} #endregion diff --git a/NodeFlow/Env/FlowEnvironmentDecorator.cs b/NodeFlow/Env/FlowEnvironmentDecorator.cs index 5bb9237..405721a 100644 --- a/NodeFlow/Env/FlowEnvironmentDecorator.cs +++ b/NodeFlow/Env/FlowEnvironmentDecorator.cs @@ -3,6 +3,7 @@ using Serein.Library.Api; using Serein.Library.FlowNode; using Serein.Library.Utils; using Serein.NodeFlow.Tool; +using System.Reflection; namespace Serein.NodeFlow.Env { @@ -121,13 +122,16 @@ namespace Serein.NodeFlow.Env remove { currentFlowEnvironment.OnNodeRemove -= value; } } - /// - /// 节点父子关系发生改变事件 - /// - public event NodeContainerChildChangeHandler OnNodeParentChildChange + public event NodePlaceHandler OnNodePlace { - add { currentFlowEnvironment.OnNodeParentChildChange += value; } - remove { currentFlowEnvironment.OnNodeParentChildChange -= value; } + add { currentFlowEnvironment.OnNodePlace += value; } + remove { currentFlowEnvironment.OnNodePlace -= value; } + } + + public event NodeTakeOutHandler OnNodeTakeOut + { + add { currentFlowEnvironment.OnNodeTakeOut += value; } + remove { currentFlowEnvironment.OnNodeTakeOut -= value; } } public event StartNodeChangeHandler OnStartNodeChange @@ -203,10 +207,6 @@ namespace Serein.NodeFlow.Env return await currentFlowEnvironment.CheckObjMonitorStateAsync(key); } - public void ClearAll() - { - currentFlowEnvironment.ClearAll(); - } /// /// 在两个节点之间创建连接关系 @@ -287,27 +287,35 @@ namespace Serein.NodeFlow.Env return result; } + /// - /// 将节点放置在容器中/从容器中取出 + /// 将节点放置在容器中 /// - /// 子节点(主要节点) - /// 父节点 - /// 是否组合(反之为分解节点组合关系) /// - public async Task ChangeNodeContainerChild(string childNodeGuid, string parentNodeGuid, bool isAssembly) + public async Task PlaceNodeToContainerAsync(string nodeGuid, string containerNodeGuid) { SetProjectLoadingFlag(false); - var result = await currentFlowEnvironment.ChangeNodeContainerChild(childNodeGuid, parentNodeGuid, isAssembly); // 装饰器调用 + var result = await currentFlowEnvironment.PlaceNodeToContainerAsync(nodeGuid, containerNodeGuid); // 装饰器调用 SetProjectLoadingFlag(true); return result; + } + /// + /// 将节点从容器中脱离 + /// + /// + public async Task TakeOutNodeToContainerAsync(string nodeGuid) + { + SetProjectLoadingFlag(false); + var result = await currentFlowEnvironment.TakeOutNodeToContainerAsync(nodeGuid); // 装饰器调用 + SetProjectLoadingFlag(true); + return result; } - - public void ExitFlow() + public async Task ExitFlowAsync() { - currentFlowEnvironment.ExitFlow(); + return await currentFlowEnvironment.ExitFlowAsync(); } public void ExitRemoteEnv() @@ -369,9 +377,9 @@ namespace Serein.NodeFlow.Env } - public bool UnloadLibrary(string assemblyName) + public bool TryUnloadLibrary(string assemblyName) { - return currentFlowEnvironment.UnloadLibrary(assemblyName); + return currentFlowEnvironment.TryUnloadLibrary(assemblyName); } /// @@ -441,19 +449,19 @@ namespace Serein.NodeFlow.Env return await currentFlowEnvironment.SetNodeInterruptAsync(nodeGuid, isInterrupt); } - public void SetStartNode(string nodeGuid) + public async Task SetStartNodeAsync(string nodeGuid) { - currentFlowEnvironment.SetStartNode(nodeGuid); + return await currentFlowEnvironment.SetStartNodeAsync(nodeGuid); } - public async Task StartAsync() + public async Task StartFlowAsync() { - await currentFlowEnvironment.StartAsync(); + return await currentFlowEnvironment.StartFlowAsync(); } - public async Task StartAsyncInSelectNode(string startNodeGuid) + public async Task StartAsyncInSelectNode(string startNodeGuid) { - await currentFlowEnvironment.StartAsyncInSelectNode(startNodeGuid); + return await currentFlowEnvironment.StartAsyncInSelectNode(startNodeGuid); } public async Task InvokeNodeAsync(IDynamicContext context, string nodeGuid) diff --git a/NodeFlow/Env/MsgControllerOfClient.cs b/NodeFlow/Env/MsgControllerOfClient.cs index f236bcf..e2aac6f 100644 --- a/NodeFlow/Env/MsgControllerOfClient.cs +++ b/NodeFlow/Env/MsgControllerOfClient.cs @@ -48,7 +48,6 @@ namespace Serein.NodeFlow.Env /// 超时触发 public async Task SendAsync(string theme, object? data = null, int overtimeInMs = 100) { - var msgId = MsgIdHelper.GenerateId().ToString(); SereinEnv.WriteLine(InfoType.INFO, $"[{msgId}] => {theme}"); await SendCommandAsync(msgId, theme, data); // 客户端发送消息 @@ -62,12 +61,17 @@ namespace Serein.NodeFlow.Env public async Task SendAndWaitDataAsync(string theme, object? data = null, int overtimeInMs = 50) { var msgId = MsgIdHelper.GenerateId().ToString(); - //_ = Task.Run(async () => - //{ - // await Task.Delay(500); - //}); - await SendCommandAsync(msgId, theme, data); // 客户端发送消息 - return (await remoteFlowEnvironment.WaitTriggerAsync(msgId)).Value; + _ = SendCommandAsync(msgId, theme, data); // 客户端发送消息 + var result = await remoteFlowEnvironment.WaitTriggerAsync(msgId); + if (result.Type == TriggerDescription.Overtime) + { + throw new Exception($"主题【{theme}】异常,服务端未响应"); + } + else if (result.Type == TriggerDescription.TypeInconsistency) + { + throw new Exception($"主题【{theme}】异常,服务端返回数据类型与预期不一致{result.Value?.GetType()}"); + } + return result.Value; } @@ -96,12 +100,66 @@ namespace Serein.NodeFlow.Env _ = remoteFlowEnvironment.InvokeTriggerAsync(msgId, sereinProjectData); } + /// + /// 开始流程 + /// + /// + /// + [AutoSocketHandle(ThemeValue = EnvMsgTheme.StartFlow, IsReturnValue = false)] + public void StartFlow([UseMsgId] string msgId, bool state) + { + _ = remoteFlowEnvironment.InvokeTriggerAsync(msgId, state); + } + /// + /// 结束流程 + /// + /// + /// + [AutoSocketHandle(ThemeValue = EnvMsgTheme.ExitFlow, IsReturnValue = false)] + public void ExitFlow([UseMsgId] string msgId, bool state) + { + _ = remoteFlowEnvironment.InvokeTriggerAsync(msgId, state); + } + + /// + /// 设置了某个节点为起始节点 + /// + /// + /// 节点Guid + [AutoSocketHandle(ThemeValue = EnvMsgTheme.SetStartNode, IsReturnValue = false)] + public void SetStartNode([UseMsgId] string msgId, string nodeGuid) + { + _ = remoteFlowEnvironment.InvokeTriggerAsync(msgId, nodeGuid); + } + + + + + /// + /// 从某个节点开始运行 + /// + /// + /// + [AutoSocketHandle(ThemeValue = EnvMsgTheme.StartFlowInSelectNode, IsReturnValue = false)] + public void StartFlowInSelectNode([UseMsgId] string msgId, bool state) + { + _ = remoteFlowEnvironment.InvokeTriggerAsync(msgId, state); + } + + /// + /// 设置节点的中断 + /// + /// [AutoSocketHandle(ThemeValue = EnvMsgTheme.SetNodeInterrupt, IsReturnValue = false)] public void SetNodeInterrupt([UseMsgId] string msgId) { _ = remoteFlowEnvironment.InvokeTriggerAsync(msgId, null); } + /// + /// 添加中断监视表达式 + /// + /// [AutoSocketHandle(ThemeValue = EnvMsgTheme.AddInterruptExpression, IsReturnValue = false)] public void AddInterruptExpression([UseMsgId] string msgId) { @@ -109,43 +167,77 @@ namespace Serein.NodeFlow.Env } - + /// + /// 创建节点 + /// + /// + /// [AutoSocketHandle(ThemeValue = EnvMsgTheme.CreateNode, IsReturnValue = false)] public void CreateNode([UseMsgId] string msgId, [UseData] NodeInfo nodeInfo) { _ = remoteFlowEnvironment.InvokeTriggerAsync(msgId, nodeInfo); } + /// + /// 移除节点 + /// + /// + /// [AutoSocketHandle(ThemeValue = EnvMsgTheme.RemoveNode, IsReturnValue = false)] public void RemoveNode([UseMsgId] string msgId, bool state) { _ = remoteFlowEnvironment.InvokeTriggerAsync(msgId, state); } + /// + /// 创建节点之间的调用关系 + /// + /// + /// [AutoSocketHandle(ThemeValue = EnvMsgTheme.ConnectInvokeNode, IsReturnValue = false)] public void ConnectInvokeNode([UseMsgId] string msgId, bool state) { _ = remoteFlowEnvironment.InvokeTriggerAsync(msgId, state); } + /// + /// 移除节点之间的调用关系 + /// + /// + /// [AutoSocketHandle(ThemeValue = EnvMsgTheme.RemoveInvokeConnect, IsReturnValue = false)] public void RemoveInvokeConnect([UseMsgId] string msgId, bool state) { _ = remoteFlowEnvironment.InvokeTriggerAsync(msgId, state); } + /// + /// 创建节点之间参数获取关系 + /// + /// + /// [AutoSocketHandle(ThemeValue = EnvMsgTheme.ConnectArgSourceNode, IsReturnValue = false)] public void ConnectArgSourceNode([UseMsgId] string msgId, bool state) { _ = remoteFlowEnvironment.InvokeTriggerAsync(msgId, state); } + /// + /// 移除节点之间参数获取关系 + /// + /// + /// [AutoSocketHandle(ThemeValue = EnvMsgTheme.RemoveArgSourceConnect, IsReturnValue = false)] public void RemoveArgSourceConnect([UseMsgId] string msgId, bool state) { _ = remoteFlowEnvironment.InvokeTriggerAsync(msgId, state); } + /// + /// 改变参数 + /// + /// + /// [AutoSocketHandle(ThemeValue = EnvMsgTheme.ChangeParameter, IsReturnValue = false)] public void ChangeParameter([UseMsgId] string msgId, bool state) { @@ -153,8 +245,6 @@ namespace Serein.NodeFlow.Env } - - #endregion } diff --git a/NodeFlow/Env/MsgControllerOfServer.cs b/NodeFlow/Env/MsgControllerOfServer.cs index 3e20fb4..4f59b6c 100644 --- a/NodeFlow/Env/MsgControllerOfServer.cs +++ b/NodeFlow/Env/MsgControllerOfServer.cs @@ -172,10 +172,14 @@ namespace Serein.NodeFlow.Env /// /// [AutoSocketHandle(ThemeValue = EnvMsgTheme.StartFlow)] - private async Task StartAsync() + private async Task StartAsync() { var uiContextOperation = environment.IOC.Get(); - await environment.StartAsync(); + var state = await environment.StartFlowAsync(); + return new + { + state = state, + }; } /// @@ -184,19 +188,26 @@ namespace Serein.NodeFlow.Env /// /// [AutoSocketHandle(ThemeValue = EnvMsgTheme.StartFlowInSelectNode)] - private async Task StartAsyncInSelectNode(string nodeGuid) + private async Task StartAsyncInSelectNode(string nodeGuid) { - await environment.StartAsyncInSelectNode(nodeGuid); + var state = await environment.StartAsyncInSelectNode(nodeGuid); + return new + { + state = state, + }; } /// /// 结束流程 /// [AutoSocketHandle(ThemeValue = EnvMsgTheme.ExitFlow)] - private void ExitFlow() + private async Task ExitFlow() { - environment.ExitFlow(); - + var state = await environment.ExitFlowAsync(); + return new + { + state = state, + }; } /// @@ -519,7 +530,7 @@ namespace Serein.NodeFlow.Env [AutoSocketHandle(ThemeValue = EnvMsgTheme.SetStartNode)] public void SetStartNode(string nodeGuid) { - environment.SetStartNode(nodeGuid); + environment.SetStartNodeAsync(nodeGuid); } diff --git a/NodeFlow/Env/RemoteFlowEnvironment.cs b/NodeFlow/Env/RemoteFlowEnvironment.cs index ef8a751..d25c371 100644 --- a/NodeFlow/Env/RemoteFlowEnvironment.cs +++ b/NodeFlow/Env/RemoteFlowEnvironment.cs @@ -55,10 +55,8 @@ namespace Serein.NodeFlow.Env public event NodeConnectChangeHandler OnNodeConnectChange; public event NodeCreateHandler OnNodeCreate; public event NodeRemoveHandler OnNodeRemove; - /// - /// 节点父子关系发生改变事件 - /// - public event NodeContainerChildChangeHandler OnNodeParentChildChange; + public event NodePlaceHandler OnNodePlace; + public event NodeTakeOutHandler OnNodeTakeOut; public event StartNodeChangeHandler OnStartNodeChange; public event FlowRunCompleteHandler OnFlowRunComplete; public event MonitorObjectChangeHandler OnMonitorObjectChange; @@ -117,11 +115,6 @@ namespace Serein.NodeFlow.Env OnEnvOut?.Invoke(type, message); } - public void WriteLineObjToJson(object obj) - { - this.WriteLine(InfoType.INFO, "远程环境尚未实现的接口:WriteLineObjToJson"); - } - public async Task StartRemoteServerAsync(int port = 7525) { this.WriteLine(InfoType.INFO, "远程环境尚未实现的接口:StartRemoteServerAsync"); @@ -133,10 +126,14 @@ namespace Serein.NodeFlow.Env this.WriteLine(InfoType.INFO, "远程环境尚未实现的接口:StopRemoteServer"); } + /// + /// 获取远程环境 + /// + /// public async Task GetProjectInfoAsync() { - var prjectInfo = await msgClient.SendAndWaitDataAsync(EnvMsgTheme.GetProjectInfo); // 等待服务器返回项目信息 - return prjectInfo; + var projectData = await msgClient.SendAndWaitDataAsync(EnvMsgTheme.GetProjectInfo); // 等待服务器返回项目信息 + return projectData; } /// @@ -176,9 +173,9 @@ namespace Serein.NodeFlow.Env } #endregion - - _ = LoadNodeInfosAsync(flowEnvInfo.Project.Nodes.ToList()); - SetStartNode(flowEnvInfo.Project.StartNode); // 设置流程起点 + + LoadNodeInfos(flowEnvInfo.Project.Nodes.ToList()); // 加载节点 + _ = SetStartNodeAsync(flowEnvInfo.Project.StartNode); // 设置流程起点 UIContextOperation?.Invoke(() => { OnProjectLoaded?.Invoke(new ProjectLoadedEventArgs()); // 加载完成 @@ -341,87 +338,95 @@ namespace Serein.NodeFlow.Env } - - - - - - - - - private bool TryAddNode(NodeModelBase nodeModel) - { - //nodeModel.Guid ??= Guid.NewGuid().ToString(); - NodeModels[nodeModel.Guid] = nodeModel; - - // 如果是触发器,则需要添加到专属集合中 - //if (nodeModel is SingleFlipflopNode flipflopNode) - //{ - // var guid = flipflopNode.Guid; - // if (!FlipflopNodes.Exists(it => it.Guid.Equals(guid))) - // { - // FlipflopNodes.Add(flipflopNode); - // } - //} - return true; - } - - + /// + /// 从远程环境获取项目信息 + /// + /// public async Task GetEnvInfoAsync() { var envInfo = await msgClient.SendAndWaitDataAsync(EnvMsgTheme.GetEnvInfo); return envInfo; } - + /// + /// 连接到远程环境 + /// + /// + /// + /// + /// public async Task<(bool, RemoteMsgUtil)> ConnectRemoteEnv(string addres, int port, string token) { await Console.Out.WriteLineAsync("远程环境尚未实现的接口:ConnectRemoteEnv"); return (false, null); } - + + /// + /// 退出远程环境 + /// public void ExitRemoteEnv() { this.WriteLine(InfoType.INFO, "远程环境尚未实现的接口:ExitRemoteEnv"); } - + /// + /// (待更新)加载类库 + /// + /// public void LoadLibrary(string dllPath) { // 将dll文件发送到远程环境,由远程环境进行加载 this.WriteLine(InfoType.INFO, "远程环境尚未实现的接口:LoadDll"); } - - public bool UnloadLibrary(string assemblyName) + /// + /// (待更新)卸载类库 + /// + /// + /// + public bool TryUnloadLibrary(string assemblyName) { // 尝试移除远程环境中的加载了的依赖 this.WriteLine(InfoType.INFO, "远程环境尚未实现的接口:RemoteDll"); return false; } - - public void ClearAll() - { - this.WriteLine(InfoType.INFO, "远程环境尚未实现的接口:ClearAll"); - } - - public async Task StartAsync() + /// + /// 启动远程环境的流程 + /// + /// + public async Task StartFlowAsync() { // 远程环境下不需要UI上下文 - await msgClient.SendAsync(EnvMsgTheme.StartFlow); + var result = await msgClient.SendAndWaitDataAsync(EnvMsgTheme.StartFlow); + return result; } - - public async Task StartAsyncInSelectNode(string startNodeGuid) + /// + /// 从选定的节点开始运行 + /// + /// + /// + public async Task StartAsyncInSelectNode(string startNodeGuid) { - _ = msgClient.SendAsync(EnvMsgTheme.StartFlowInSelectNode, new + var result = await msgClient.SendAndWaitDataAsync(EnvMsgTheme.StartFlowInSelectNode, new { nodeGuid = startNodeGuid }); + return result; } - - public async void ExitFlow() + /// + /// 结束远程环境的流程运行 + /// + /// + public async Task ExitFlowAsync() { - await msgClient.SendAsync(EnvMsgTheme.ExitFlow, null); + var result = await msgClient.SendAndWaitDataAsync(EnvMsgTheme.ExitFlow, null); + return result; } + /// + /// 移动节点,通知远程环境也一起移动,保持相对位置一致 + /// + /// + /// + /// public void MoveNode(string nodeGuid, double x, double y) { //UIContextOperation?.Invoke(() => @@ -443,26 +448,26 @@ namespace Serein.NodeFlow.Env } } - - public void SetStartNode(string nodeGuid) + + /// + /// 设置远程环境的流程起点节点 + /// + /// 尝试设置为起始节点的节点Guid + /// 被设置为起始节点的Guid + public async Task SetStartNodeAsync(string nodeGuid) { - _ = msgClient.SendAsync(EnvMsgTheme.SetStartNode, new + var newNodeGuid = await msgClient.SendAndWaitDataAsync(EnvMsgTheme.SetStartNode, new { nodeGuid }); - UIContextOperation?.Invoke(() => OnStartNodeChange?.Invoke(new StartNodeChangeEventArgs(nodeGuid,nodeGuid))); - } - - public async Task InvokeNodeAsync(IDynamicContext context, string nodeGuid) - { - this.WriteLine(InfoType.INFO, "远程环境尚未实现接口 InvokeNodeAsync"); - //_ = msgClient.SendAsync(EnvMsgTheme.InvokeNodeAsync, new - //{ - // nodeGuid - //}); - return null; + if (NodeModels.TryGetValue(newNodeGuid, out var nodeModel)) // 存在节点 + { + UIContextOperation?.Invoke(() => OnStartNodeChange?.Invoke(new StartNodeChangeEventArgs(nodeGuid, newNodeGuid))); + } + return newNodeGuid; } + /// /// 在两个节点之间创建方法调用关系 /// @@ -599,7 +604,7 @@ namespace Serein.NodeFlow.Env } /// - /// 设置两个节点某个类型的方法调用关系为优先调用 + /// (待更新)设置两个节点某个类型的方法调用关系为优先调用 /// /// 起始节点 /// 目标节点 @@ -610,6 +615,7 @@ namespace Serein.NodeFlow.Env this.WriteLine(InfoType.WARN, "远程环境尚未实现的接口(重要,会尽快实现):SetConnectPriorityInvoke"); return false; } + /// /// 移除两个节点之间的方法调用关系 /// @@ -637,6 +643,7 @@ namespace Serein.NodeFlow.Env } return result; } + /// /// 移除连接节点之间参数传递的关系 /// @@ -670,13 +677,369 @@ namespace Serein.NodeFlow.Env /// /// 从节点信息集合批量加载节点控件 /// - /// 节点信息 - /// 需要加载的位置 + /// 节点信息 /// public async Task LoadNodeInfosAsync(List nodeInfos) { - List needPlaceNodeInfos = []; + if (IsLoadingProject || IsLoadingNode) + { + return; + } + + List loadSuuccessNodes = new List(); // 加载成功的节点信息 + List loadFailureNodes = new List(); // 加载失败的节点信息 + List needPlaceNodeInfos = new List(); // 需要重新放置的节点 + #region 尝试从节点信息加载节点 + foreach (NodeInfo? nodeInfo in nodeInfos) + { + if (!EnumHelper.TryConvertEnum(nodeInfo.Type, out var controlType)) + { + continue; + } + NodeInfo newNodeInfo; + try + { + if (!string.IsNullOrEmpty(nodeInfo.MethodName)) + { + if (!MethodDetailss.TryGetValue(nodeInfo.MethodName, out var methodDetails)) + { + loadFailureNodes.Add(nodeInfo); + continue; // 有方法名称,但本地没有缓存的相关方法信息,跳过 + } + // 加载远程环境时尝试获取方法信息 + newNodeInfo = await CreateNodeAsync(controlType, nodeInfo.Position, methodDetails.ToInfo()); + } + else + { + newNodeInfo = await CreateNodeAsync(controlType, nodeInfo.Position); + } + loadSuuccessNodes.Add(nodeInfo); + } + catch (Exception ex) + { + SereinEnv.WriteLine(ex); + loadFailureNodes.Add(nodeInfo); + continue; // 跳过加载失败的节点 + } + } + #endregion + + // 远程环境无法加载的节点,输出信息 + foreach (var f_node in loadFailureNodes) + { + SereinEnv.WriteLine(InfoType.INFO, "无法加载的节点Guid:" + f_node.Guid); + } + + #region 尝试重新放置节点的位置 + // 判断加载的节点是否需要放置在容器中 + foreach (var nodeInfo in loadSuuccessNodes) + { + if (!string.IsNullOrEmpty(nodeInfo.ParentNodeGuid) && + NodeModels.TryGetValue(nodeInfo.ParentNodeGuid, out var parentNode)) + { + needPlaceNodeInfos.Add(nodeInfo); // 需要重新放置的节点 + } + } + loadSuuccessNodes.Clear(); + loadFailureNodes.Clear(); + foreach (var nodeInfo in needPlaceNodeInfos) + { + // 通知远程调整节点放置位置 + var isSuuccess = await PlaceNodeToContainerAsync(nodeInfo.Guid, nodeInfo.ParentNodeGuid); + if (isSuuccess) + { + loadSuuccessNodes.Add(nodeInfo); + } + else + { + loadFailureNodes.Add(nodeInfo); + } + } + #endregion + + foreach (var f_node in loadFailureNodes) + { + SereinEnv.WriteLine(InfoType.INFO, $"无法移动到指定容器的节点Guid :{f_node.Guid}" + + $"{Environment.NewLine}容器节点Guid{f_node.ParentNodeGuid}{Environment.NewLine}" ); + } + + } + + /// + /// 创建节点/区域/基础控件 + /// + /// 节点/区域/基础控件类型 + /// 节点在画布上的位置( + /// 节点绑定的方法说明 + public async Task CreateNodeAsync(NodeControlType nodeControlType, + PositionOfUI position, + MethodDetailsInfo methodDetailsInfo = null) + { + IsLoadingNode = true; + var nodeInfo = await msgClient.SendAndWaitDataAsync(EnvMsgTheme.CreateNode, new + { + nodeType = nodeControlType.ToString(), + position = position, + mdInfo = methodDetailsInfo, + }); + + 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); // 远程环境下加载节点 + nodeModel.LoadInfo(nodeInfo); + TryAddNode(nodeModel); + IsLoadingNode = false; + + // 通知UI更改 + UIContextOperation.Invoke(() => + { + OnNodeCreate?.Invoke(new NodeCreateEventArgs(nodeModel, position)); + }); + return nodeInfo; + } + + + + /// + /// 将节点放置在容器中 + /// + /// + public async Task PlaceNodeToContainerAsync(string nodeGuid, string containerNodeGuid) + { + var isSuuccess = await msgClient.SendAndWaitDataAsync(EnvMsgTheme.PlaceNode, new + { + nodeGuid = nodeGuid, + containerNodeGuid = containerNodeGuid, + }); + if (isSuuccess) + { + OnNodePlace?.Invoke(new NodePlaceEventArgs(nodeGuid, containerNodeGuid)); // 通知UI更改节点放置位置 + } + return isSuuccess; + } + + /// + /// 将节点从容器中脱离 + /// + /// + public async Task TakeOutNodeToContainerAsync(string nodeGuid) + { + var isSuuccess = await msgClient.SendAndWaitDataAsync(EnvMsgTheme.TakeOutNode, new + { + nodeGuid = nodeGuid, + }); + if (isSuuccess) + { + OnNodeTakeOut?.Invoke(new NodeTakeOutEventArgs(nodeGuid)); // 重新放置在画布上 + } + return isSuuccess; + } + + + + /// + /// 移除远程环境的某个节点 + /// + /// + /// + public async Task RemoveNodeAsync(string nodeGuid) + { + var result = await msgClient.SendAndWaitDataAsync(EnvMsgTheme.RemoveNode, new + { + nodeGuid + }); + if (result) + { + UIContextOperation.Invoke(() => + { + OnNodeRemove?.Invoke(new NodeRemoveEventArgs(nodeGuid)); + }); + } + else + { + this.WriteLine(InfoType.ERROR, "删除失败"); + } + return result; + } + + /// + /// 激活远程某个全局触发器节点 + /// + /// + public void ActivateFlipflopNode(string nodeGuid) + { + // 需要重写 + _ = msgClient.SendAsync(EnvMsgTheme.ActivateFlipflopNode, new + { + nodeGuid + }); + } + + /// + /// 暂停远程某个全局触发器节点 + /// + /// + public void TerminateFlipflopNode(string nodeGuid) + { + // 需要重写 + _ = msgClient.SendAsync(EnvMsgTheme.TerminateFlipflopNode, new + { + nodeGuid + }); + } + + /// + /// 设置远程环境某个节点的中断 + /// + /// + /// + /// + public async Task SetNodeInterruptAsync(string nodeGuid, bool isInterrupt) + { + var state = await msgClient.SendAndWaitDataAsync(EnvMsgTheme.SetNodeInterrupt, // 设置节点中断 + new + { + nodeGuid, + isInterrupt, + }); + return state; + } + + /// + /// 为远程某个节点添加中断的表达式 + /// + /// + /// + /// + public async Task AddInterruptExpressionAsync(string key, string expression) + { + var state = await msgClient.SendAndWaitDataAsync(EnvMsgTheme.AddInterruptExpression, // 设置节点/对象的中断表达式 + new + { + key, + expression, + }); + return state; + } + + /// + /// 检查并获取节点/对象是否正在监视、以及监视的表达式(需要重写) + /// + /// + /// + public async Task<(bool, string[])> CheckObjMonitorStateAsync(string key) + { + if (string.IsNullOrEmpty(key)) + { + var exps = Array.Empty(); + return (false, exps); + } + else + { + var result = await msgClient.SendAndWaitDataAsync<(bool, string[])>(EnvMsgTheme.SetNodeInterrupt, // 检查并获取节点/对象是否正在监视、以及监视的表达式 + new + { + key, + }); + return result; + } + + } + + + + /// + /// 需要定位某个节点 + /// + /// + public void NodeLocated(string nodeGuid) + { + UIContextOperation?.Invoke(() => OnNodeLocated?.Invoke(new NodeLocatedEventArgs(nodeGuid))); + } + + /// + /// 通知远程环境修改节点数据 + /// + /// + /// + /// + /// + public async Task NotificationNodeValueChangeAsync(string nodeGuid, string path, object value) + { + if(IsLoadingProject || IsLoadingNode) + { + return; + } + //this.WriteLine(InfoType.INFO, $"通知远程环境修改节点数据:{nodeGuid},name:{path},value:{value}"); + await msgClient.SendAsync(EnvMsgTheme.ValueNotification, new + { + nodeGuid = nodeGuid, + path = path, + value = value.ToString(), + }); + + } + + /// + /// 改变可选参数的数目 + /// + /// 对应的节点Guid + /// true,增加参数;false,减少参数 + /// 以哪个参数为模板进行拷贝,或删去某个参数(该参数必须为可选参数) + /// + public async Task ChangeParameter(string nodeGuid, bool isAdd, int paramIndex) + { + if (IsLoadingProject || IsLoadingNode) + { + return false; + } + if (!NodeModels.TryGetValue(nodeGuid,out var nodeModel)) + { + return false; + } + //this.WriteLine(InfoType.INFO, $"通知远程环境修改节点可选数据:{nodeGuid},isAdd:{isAdd},paramIndex:{paramIndex}"); + var result = await msgClient.SendAndWaitDataAsync(EnvMsgTheme.ChangeParameter, new + { + nodeGuid = nodeGuid, + isAdd = isAdd, + paramIndex = paramIndex, + }); + if (result) { + if (isAdd) + { + nodeModel.MethodDetails.AddParamsArg(paramIndex); + } + else + { + nodeModel.MethodDetails.RemoveParamsArg(paramIndex); + } + } + return result; + } + + + + #region 私有方法 + + + private bool TryAddNode(NodeModelBase nodeModel) + { + NodeModels[nodeModel.Guid] = nodeModel; + return true; + } + + /// + /// 私有方法,通过节点信息集合加载节点 + /// + /// + private void LoadNodeInfos(List nodeInfos) + { #region 从NodeInfo创建NodeModel foreach (NodeInfo? nodeInfo in nodeInfos) { @@ -709,27 +1072,32 @@ namespace Serein.NodeFlow.Env } nodeModel.LoadInfo(nodeInfo); // 创建节点model TryAddNode(nodeModel); // 加载项目时将节点加载到环境中 - if (!string.IsNullOrEmpty(nodeInfo.ParentNodeGuid) && - NodeModels.TryGetValue(nodeInfo.ParentNodeGuid, out var parentNode)) - { - needPlaceNodeInfos.Add(nodeInfo); // 需要重新放置的节点 - } + UIContextOperation?.Invoke(() => OnNodeCreate?.Invoke(new NodeCreateEventArgs(nodeModel, nodeInfo.Position))); // 添加到UI上 } #endregion #region 重新放置节点 + List needPlaceNodeInfos = []; + foreach (NodeInfo? nodeInfo in nodeInfos) + { + if (!string.IsNullOrEmpty(nodeInfo.ParentNodeGuid) && + NodeModels.TryGetValue(nodeInfo.ParentNodeGuid, out var parentNode)) + { + needPlaceNodeInfos.Add(nodeInfo); // 需要重新放置的节点 + } + } foreach (NodeInfo nodeInfo in needPlaceNodeInfos) { if (NodeModels.TryGetValue(nodeInfo.Guid, out var childNode) && NodeModels.TryGetValue(nodeInfo.ParentNodeGuid, out var parentNode)) { - childNode.ParentNode = parentNode; + childNode.ContainerNode = parentNode; parentNode.ChildrenNode.Add(childNode); - UIContextOperation?.Invoke(() => OnNodeParentChildChange?.Invoke( - new NodeContainerChildChangeEventArgs(childNode.Guid, parentNode.Guid, - NodeContainerChildChangeEventArgs.Type.Place))); + UIContextOperation?.Invoke(() => + OnNodePlace?.Invoke(new NodePlaceEventArgs(nodeInfo.Guid, nodeInfo.ParentNodeGuid)) // 通知UI更改节点放置位置 + ); } } @@ -805,141 +1173,23 @@ namespace Serein.NodeFlow.Env } + #endregion - /// - /// 创建节点/区域/基础控件 - /// - /// 节点/区域/基础控件类型 - /// 节点在画布上的位置( - /// 节点绑定的方法说明 - public async Task CreateNodeAsync(NodeControlType nodeControlType, PositionOfUI position, MethodDetailsInfo methodDetailsInfo = null) - { - IsLoadingNode = true; - var nodeInfo = await msgClient.SendAndWaitDataAsync(EnvMsgTheme.CreateNode, new - { - nodeType = nodeControlType.ToString(), - position = position, - mdInfo = methodDetailsInfo, - }); - - MethodDetails? methodDetails = null; - if (!string.IsNullOrEmpty(nodeInfo.MethodName)) - { - MethodDetailss.TryGetValue(nodeInfo.MethodName, out methodDetails);// 加载远程环境时尝试获取方法信息 - } + #region 远程环境下暂未实现的接口 - //MethodDetailss.TryGetValue(methodDetailsInfo.MethodName, out var methodDetails);// 加载项目时尝试获取方法信息 - var nodeModel = FlowFunc.CreateNode(this, nodeControlType, methodDetails); // 远程环境下加载节点 - nodeModel.LoadInfo(nodeInfo); - TryAddNode(nodeModel); - IsLoadingNode = false; - - // 通知UI更改 - UIContextOperation.Invoke(() => - { - OnNodeCreate?.Invoke(new NodeCreateEventArgs(nodeModel, position)); - }); - return nodeInfo; - } - - /// - /// 将节点放置在容器中/从容器中取出 - /// - /// 子节点(主要节点) - /// 父节点 - /// 是否组合(反之为分解节点组合关系) - /// - public async Task ChangeNodeContainerChild(string childNodeGuid, string parentNodeGuid, bool isAssembly) - { - this.WriteLine(InfoType.WARN, "远程环境尚未实现的接口(重要,会尽快实现):ChangeNodeParentChild"); - return false; - } - - - public async Task RemoveNodeAsync(string nodeGuid) - { - var result = await msgClient.SendAndWaitDataAsync(EnvMsgTheme.RemoveNode, new - { - nodeGuid - }); - if (result) - { - UIContextOperation.Invoke(() => - { - OnNodeRemove?.Invoke(new NodeRemoveEventArgs(nodeGuid)); - }); - } - else - { - this.WriteLine(InfoType.ERROR, "删除失败"); - } - return result; - } - - public void ActivateFlipflopNode(string nodeGuid) - { - _ = msgClient.SendAsync(EnvMsgTheme.ActivateFlipflopNode, new - { - nodeGuid - }); - } - - public void TerminateFlipflopNode(string nodeGuid) - { - _ = msgClient.SendAsync(EnvMsgTheme.TerminateFlipflopNode, new - { - nodeGuid - }); - } - - public async Task SetNodeInterruptAsync(string nodeGuid, bool isInterrupt) - { - var state = await msgClient.SendAndWaitDataAsync(EnvMsgTheme.SetNodeInterrupt, // 设置节点中断 - new - { - nodeGuid, - isInterrupt, - }); - return state; - } - - - public async Task AddInterruptExpressionAsync(string key, string expression) - { - var state = await msgClient.SendAndWaitDataAsync(EnvMsgTheme.AddInterruptExpression, // 设置节点/对象的中断表达式 - new - { - key, - expression, - }); - return state; - } public void SetMonitorObjState(string key, bool isMonitor) { this.WriteLine(InfoType.INFO, "远程环境尚未实现的接口:SetMonitorObjState"); } - public async Task<(bool, string[])> CheckObjMonitorStateAsync(string key) + public async Task InvokeNodeAsync(IDynamicContext context, string nodeGuid) { - if (string.IsNullOrEmpty(key)) - { - var exps = Array.Empty(); - return (false, exps); - } - else - { - var result = await msgClient.SendAndWaitDataAsync<(bool, string[])>(EnvMsgTheme.SetNodeInterrupt, // 检查并获取节点/对象是否正在监视、以及监视的表达式 - new - { - key, - }); - return result; - } - + // 登录到远程环境后,启动器相关方法无效 + this.WriteLine(InfoType.INFO, "远程环境尚未实现接口 InvokeNodeAsync"); + return null; } - public async Task GetOrCreateGlobalInterruptAsync() { this.WriteLine(InfoType.INFO, "远程环境尚未实现的接口:GetOrCreateGlobalInterruptAsync"); @@ -961,76 +1211,31 @@ namespace Serein.NodeFlow.Env } - + /// + /// 对象监视表达式 + /// + /// + /// + /// public void MonitorObjectNotification(string nodeGuid, object monitorData, MonitorObjectEventArgs.ObjSourceType sourceType) { this.WriteLine(InfoType.INFO, "远程环境尚未实现的接口:MonitorObjectNotification"); } - + /// + /// 触发节点的中断 + /// + /// + /// + /// public void TriggerInterrupt(string nodeGuid, string expression, InterruptTriggerEventArgs.InterruptTriggerType type) { this.WriteLine(InfoType.INFO, "远程环境尚未实现的接口:TriggerInterrupt"); } - public void NodeLocated(string nodeGuid) - { - UIContextOperation?.Invoke(() => OnNodeLocated?.Invoke(new NodeLocatedEventArgs(nodeGuid))); - } + #endregion - public async Task NotificationNodeValueChangeAsync(string nodeGuid, string path, object value) - { - if(IsLoadingProject || IsLoadingNode) - { - return; - } - //this.WriteLine(InfoType.INFO, $"通知远程环境修改节点数据:{nodeGuid},name:{path},value:{value}"); - _ = msgClient.SendAsync(EnvMsgTheme.ValueNotification, new - { - nodeGuid = nodeGuid, - path = path, - value = value.ToString(), - }); - - } - - /// - /// 改变可选参数的数目 - /// - /// 对应的节点Guid - /// true,增加参数;false,减少参数 - /// 以哪个参数为模板进行拷贝,或删去某个参数(该参数必须为可选参数) - /// - public async Task ChangeParameter(string nodeGuid, bool isAdd, int paramIndex) - { - if (IsLoadingProject || IsLoadingNode) - { - return false; - } - if (!NodeModels.TryGetValue(nodeGuid,out var nodeModel)) - { - return false; - } - //this.WriteLine(InfoType.INFO, $"通知远程环境修改节点可选数据:{nodeGuid},isAdd:{isAdd},paramIndex:{paramIndex}"); - var result = await msgClient.SendAndWaitDataAsync(EnvMsgTheme.ChangeParameter, new - { - nodeGuid = nodeGuid, - isAdd = isAdd, - paramIndex = paramIndex, - }); - if (result) { - if (isAdd) - { - nodeModel.MethodDetails.AddParamsArg(paramIndex); - } - else - { - nodeModel.MethodDetails.RemoveParamsArg(paramIndex); - } - } - return result; - } #region 流程依赖类库的接口 @@ -1081,5 +1286,9 @@ namespace Serein.NodeFlow.Env #endregion + + + + } } diff --git a/NodeFlow/FlowStarter.cs b/NodeFlow/FlowStarter.cs index 6bcdc4c..aa8b01f 100644 --- a/NodeFlow/FlowStarter.cs +++ b/NodeFlow/FlowStarter.cs @@ -433,7 +433,7 @@ namespace Serein.NodeFlow } catch (FlipflopException ex) { - SereinEnv.WriteLine(InfoType.ERROR,$"触发器[{singleFlipFlopNode.MethodDetails.MethodName}]因非预期异常终止。"+ex.Message); + SereinEnv.WriteLine(InfoType.ERROR, $"触发器[{singleFlipFlopNode.MethodDetails.MethodName}]因非预期异常终止。"+ex.Message); if (ex.Type == FlipflopException.CancelClass.CancelFlow) { break; @@ -442,7 +442,7 @@ namespace Serein.NodeFlow catch (Exception ex) { SereinEnv.WriteLine(InfoType.ERROR, $"触发器[{singleFlipFlopNode.Guid}]异常。"+ ex.Message); - //await Console.Out.WriteLineAsync(ex.Message); + await Task.Delay(100); } } diff --git a/NodeFlow/Model/SingleGlobalDataNode.cs b/NodeFlow/Model/SingleGlobalDataNode.cs index 5b47ba3..94031ed 100644 --- a/NodeFlow/Model/SingleGlobalDataNode.cs +++ b/NodeFlow/Model/SingleGlobalDataNode.cs @@ -54,8 +54,19 @@ namespace Serein.NodeFlow.Model public void PlaceNode(NodeModelBase nodeModel) { - _ = this.Env.RemoveNodeAsync(DataNode?.Guid); - DataNode = nodeModel; + // 全局数据节点只有一个子控件 + if (DataNode is not null) + { + _ = Task.Run(async () => + { + await this.Env.RemoveNodeAsync(DataNode?.Guid); + DataNode = nodeModel; + }); + } + else + { + DataNode = nodeModel; + } } public void TakeOutAll() diff --git a/NodeFlow/Tool/FlowLibraryManagement.cs b/NodeFlow/Tool/FlowLibraryManagement.cs index 07234ac..c78e21e 100644 --- a/NodeFlow/Tool/FlowLibraryManagement.cs +++ b/NodeFlow/Tool/FlowLibraryManagement.cs @@ -201,12 +201,15 @@ namespace Serein.NodeFlow.Tool #region 功能性方法 - private readonly string SereinLibraryDll = $"{nameof(Serein)}.{nameof(Serein.Library)}.dll"; + /// + /// 基础依赖 + /// + public readonly static string SereinBaseLibrary = $"{nameof(Serein)}.{nameof(Serein.Library)}.dll"; private (NodeLibraryInfo, List) LoadDllNodeInfo(string dllFilePath) { var fileName = Path.GetFileName(dllFilePath); // 获取文件名 - if (SereinLibraryDll.Equals(fileName)) + if (SereinBaseLibrary.Equals(fileName)) { return LoadAssembly(typeof(IFlowEnvironment).Assembly, () => { //SereinEnv.PrintInfo(InfoType.WRAN, "基础模块不能卸载"); @@ -215,9 +218,9 @@ namespace Serein.NodeFlow.Tool else { var dir = Path.GetDirectoryName(dllFilePath); // 获取目录路径 - var sereinFlowLibraryPath = Path.Combine(dir, SereinLibraryDll); + var sereinFlowBaseLibraryPath = Path.Combine(dir, SereinBaseLibrary); // 每个类库下面至少需要有“Serein.Library.dll”类库依赖 - var flowAlc = new FlowLibraryAssemblyContext(sereinFlowLibraryPath, fileName); + var flowAlc = new FlowLibraryAssemblyContext(sereinFlowBaseLibraryPath, fileName); Action actionUnload = () => { flowAlc?.Unload(); // 卸载程序集 diff --git a/Serein.BaseNode/Serein.BaseNode.csproj b/Serein.BaseNode/Serein.BaseNode.csproj deleted file mode 100644 index a1a36c4..0000000 --- a/Serein.BaseNode/Serein.BaseNode.csproj +++ /dev/null @@ -1,30 +0,0 @@ - - - - netstandard2.0 - 1.0.0 - - D:\Project\C#\DynamicControl\SereinFlow\.Output - True - SereinFow - 基础节点 - README.md - https://github.com/fhhyyp/serein-flow - MIT - True - - - - - - - - True - \ - - - True - \ - - - diff --git a/Serein.BaseNode/SereinBaseNodes.cs b/Serein.BaseNode/SereinBaseNodes.cs deleted file mode 100644 index 2e0db2a..0000000 --- a/Serein.BaseNode/SereinBaseNodes.cs +++ /dev/null @@ -1,91 +0,0 @@ -using Serein.Library; -using Serein.Library.Api; -using Serein.Library.Utils; -using Serein.Library.Utils.SereinExpression; -using System; -using System.Collections.Generic; -using System.Dynamic; -using System.Linq; - -namespace Serein.BaseNode -{ - - public enum ExpType - { - Get, - Set - } - [DynamicFlow(Name ="[基础节点]")] - internal class SereinBaseNodes - { - [NodeAction(NodeType.Action,"条件节点")] - private bool SereinConditionNode(IDynamicContext context, - object targetObject, - string exp = "ISPASS") - { - var isPass = SereinConditionParser.To(targetObject, exp); - context.NextOrientation = isPass ? ConnectionInvokeType.IsSucceed : ConnectionInvokeType.IsFail; - return isPass; - } - - - - - [NodeAction(NodeType.Action, "表达式节点")] - private object SereinExpNode(IDynamicContext context, - object targetObject, - string exp) - { - - exp = "@" + exp; - var newData = SerinExpressionEvaluator.Evaluate(exp, targetObject, out bool isChange); - object result; - if (isChange || exp.StartsWith("@GET",System.StringComparison.OrdinalIgnoreCase)) - { - result = newData; - } - else - { - result = targetObject; - } - context.NextOrientation = ConnectionInvokeType.IsSucceed; - return result; - } - - - - [NodeAction(NodeType.Action, "KV数据收集节点")] - private Dictionary SereinKvDataCollectionNode(string argName, params object[] value) - { - var names = argName.Split(';'); - var count = Math.Min(value.Length, names.Length); - var dict = new Dictionary(); - for (int i = 0; i < count; i++) - { - dict[names[i]] = value[i]; - } - return dict; - } - [NodeAction(NodeType.Action, "List数据收集节点")] - private object[] SereinListDataCollectionNode(params object[] value) - { - return value; - } - - /* if (!DynamicObjectHelper.TryResolve(dict, className, out var result)) - { - Console.WriteLine("赋值过程中有错误,请检查属性名和类型!"); - } - else - { - DynamicObjectHelper.PrintObjectProperties(result); - } - //if (!ObjDynamicCreateHelper.TryResolve(externalData, "RootType", out var result)) - //{ - // Console.WriteLine("赋值过程中有错误,请检查属性名和类型!"); - - //} - //ObjDynamicCreateHelper.PrintObjectProperties(result!); - return result;*/ - } -} diff --git a/WorkBench.ControlLibrary.Core/AssemblyInfo.cs b/WorkBench.ControlLibrary.Core/AssemblyInfo.cs deleted file mode 100644 index b0ec827..0000000 --- a/WorkBench.ControlLibrary.Core/AssemblyInfo.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Windows; - -[assembly: ThemeInfo( - ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located - //(used if a resource is not found in the page, - // or application resource dictionaries) - ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located - //(used if a resource is not found in the page, - // app, or any theme specific resource dictionaries) -)] diff --git a/WorkBench.ControlLibrary.Core/CustomControl1.cs b/WorkBench.ControlLibrary.Core/CustomControl1.cs deleted file mode 100644 index be2ef34..0000000 --- a/WorkBench.ControlLibrary.Core/CustomControl1.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System.Text; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; - -namespace Serein.WorkBench.ControlLibrary.Core -{ - /// - /// Follow steps 1a or 1b and then 2 to use this custom control in a XAML file. - /// - /// Step 1a) Using this custom control in a XAML file that exists in the current project. - /// Add this XmlNamespace attribute to the root element of the markup file where it is - /// to be used: - /// - /// xmlns:MyNamespace="clr-namespace:Serein.WorkBench.ControlLibrary.Core" - /// - /// - /// Step 1b) Using this custom control in a XAML file that exists in a different project. - /// Add this XmlNamespace attribute to the root element of the markup file where it is - /// to be used: - /// - /// xmlns:MyNamespace="clr-namespace:Serein.WorkBench.ControlLibrary.Core;assembly=Serein.WorkBench.ControlLibrary.Core" - /// - /// You will also need to add a project reference from the project where the XAML file lives - /// to this project and Rebuild to avoid compilation errors: - /// - /// Right click on the target project in the Solution Explorer and - /// "Add Reference"->"Projects"->[Select this project] - /// - /// - /// Step 2) - /// Go ahead and use your control in the XAML file. - /// - /// - /// - /// - public class CustomControl1 : Control - { - static CustomControl1() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl1), new FrameworkPropertyMetadata(typeof(CustomControl1))); - } - } -} \ No newline at end of file diff --git a/WorkBench.ControlLibrary.Core/Serein.WorkBench.ControlLibrary.Core.csproj b/WorkBench.ControlLibrary.Core/Serein.WorkBench.ControlLibrary.Core.csproj deleted file mode 100644 index 6c78894..0000000 --- a/WorkBench.ControlLibrary.Core/Serein.WorkBench.ControlLibrary.Core.csproj +++ /dev/null @@ -1,10 +0,0 @@ - - - - net8.0-windows - enable - true - enable - - - diff --git a/WorkBench.Remote/App.xaml b/WorkBench.Remote/App.xaml deleted file mode 100644 index 8a1c6e9..0000000 --- a/WorkBench.Remote/App.xaml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - diff --git a/WorkBench.Remote/App.xaml.cs b/WorkBench.Remote/App.xaml.cs deleted file mode 100644 index 0f6171d..0000000 --- a/WorkBench.Remote/App.xaml.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Configuration; -using System.Data; -using System.Windows; - -namespace Serein.RemoteWorkBench -{ - /// - /// Interaction logic for App.xaml - /// - public partial class App : Application - { - } - -} diff --git a/WorkBench.Remote/AssemblyInfo.cs b/WorkBench.Remote/AssemblyInfo.cs deleted file mode 100644 index b0ec827..0000000 --- a/WorkBench.Remote/AssemblyInfo.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Windows; - -[assembly: ThemeInfo( - ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located - //(used if a resource is not found in the page, - // or application resource dictionaries) - ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located - //(used if a resource is not found in the page, - // app, or any theme specific resource dictionaries) -)] diff --git a/WorkBench.Remote/MainWindow.xaml b/WorkBench.Remote/MainWindow.xaml deleted file mode 100644 index d3961c5..0000000 --- a/WorkBench.Remote/MainWindow.xaml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - diff --git a/WorkBench.Remote/MainWindow.xaml.cs b/WorkBench.Remote/MainWindow.xaml.cs deleted file mode 100644 index 1df662e..0000000 --- a/WorkBench.Remote/MainWindow.xaml.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Text; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; - -namespace Serein.RemoteWorkBench -{ - /// - /// Interaction logic for MainWindow.xaml - /// - public partial class MainWindow : Window - { - public MainWindow() - { - InitializeComponent(); - } - } -} \ No newline at end of file diff --git a/WorkBench.Remote/Node/NodeControlViewModelBase.cs b/WorkBench.Remote/Node/NodeControlViewModelBase.cs deleted file mode 100644 index 91273af..0000000 --- a/WorkBench.Remote/Node/NodeControlViewModelBase.cs +++ /dev/null @@ -1,127 +0,0 @@ -using Serein.Library.Entity; -using Serein.NodeFlow.Base; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Text; -using System.Threading.Tasks; - -namespace Serein.WorkBench.Node.ViewModel -{ - public abstract class NodeControlViewModelBase : INotifyPropertyChanged - { - public NodeControlViewModelBase(NodeModelBase node) - { - Node = node; - MethodDetails = Node.MethodDetails; - } - - /// - /// 对应的节点实体类 - /// - internal NodeModelBase Node { get; } - - - private bool isSelect; - /// - /// 表示节点控件是否被选中 - /// - internal bool IsSelect - { - get => isSelect; - set - { - isSelect = value; - OnPropertyChanged(); - } - } - - - public NodeDebugSetting DebugSetting - { - get => Node.DebugSetting; - set - { - if (value != null) - { - Node.DebugSetting = value; - OnPropertyChanged(/*nameof(DebugSetting)*/); - } - } - } - - public MethodDetails MethodDetails - { - get => Node.MethodDetails; - set - { - if(value != null) - { - Node.MethodDetails = value; - OnPropertyChanged(/*nameof(MethodDetails)*/); - } - } - } - - private bool isInterrupt; - public bool IsInterrupt - { - get => isInterrupt; - set - { - isInterrupt = value; - OnPropertyChanged(/*nameof(IsInterrupt)*/); - } - } - - - //public bool IsInterrupt - //{ - // get => Node.DebugSetting.IsInterrupt; - // set - // { - // if (value) - // { - // Node.Interrupt(); - // } - // else - // { - // Node.CancelInterrupt(); - // } - // OnPropertyChanged(nameof(IsInterrupt)); - // } - //} - - //public bool IsProtectionParameter - //{ - // get => MethodDetails.IsProtectionParameter; - // set - // { - // MethodDetails.IsProtectionParameter = value; - // OnPropertyChanged(nameof(IsInterrupt)); - // } - //} - - public event PropertyChangedEventHandler? PropertyChanged; - protected void OnPropertyChanged([CallerMemberName] string propertyName = null) - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - } - - - - public void Selected() - { - IsSelect = true; - } - - public void CancelSelect() - { - IsSelect = false; - } - - - } -} diff --git a/WorkBench.Remote/Node/View/ActionNodeControl.xaml b/WorkBench.Remote/Node/View/ActionNodeControl.xaml deleted file mode 100644 index 4faf4b3..0000000 --- a/WorkBench.Remote/Node/View/ActionNodeControl.xaml +++ /dev/null @@ -1,79 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/WorkBench.Remote/Node/View/ActionNodeControl.xaml.cs b/WorkBench.Remote/Node/View/ActionNodeControl.xaml.cs deleted file mode 100644 index f8852ec..0000000 --- a/WorkBench.Remote/Node/View/ActionNodeControl.xaml.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Serein.NodeFlow.Model; -using Serein.WorkBench.Node.ViewModel; -using System.Runtime.CompilerServices; -using System.Windows.Controls; - -namespace Serein.WorkBench.Node.View -{ - /// - /// ActionNode.xaml 的交互逻辑 - /// - public partial class ActionNodeControl : NodeControlBase - { - public ActionNodeControl(ActionNodeControlViewModel viewModel):base(viewModel) - { - DataContext = viewModel; - InitializeComponent(); - } - } -} diff --git a/WorkBench.Remote/Node/View/ActionRegionControl.xaml b/WorkBench.Remote/Node/View/ActionRegionControl.xaml deleted file mode 100644 index 236d16d..0000000 --- a/WorkBench.Remote/Node/View/ActionRegionControl.xaml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - diff --git a/WorkBench.Remote/Node/View/ActionRegionControl.xaml.cs b/WorkBench.Remote/Node/View/ActionRegionControl.xaml.cs deleted file mode 100644 index 60889d0..0000000 --- a/WorkBench.Remote/Node/View/ActionRegionControl.xaml.cs +++ /dev/null @@ -1,130 +0,0 @@ -using Serein.NodeFlow; -using Serein.NodeFlow.Model; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Controls.Primitives; -using System.Windows.Input; - -namespace Serein.WorkBench.Node.View -{ - /// - /// ActionRegion.xaml 的交互逻辑 - /// - public partial class ActionRegionControl : NodeControlBase - { - private Point _dragStartPoint; - - //private new readonly CompositeActionNode Node; - - //public override NodeControlViewModel ViewModel { get ; set ; } - - public ActionRegionControl() : base(null) - { - InitializeComponent(); - } - //public ActionRegionControl(CompositeActionNode node) - //{ - // InitializeComponent(); - // //ViewModel = new NodeControlViewModel(node); - // DataContext = ViewModel; - // base.Name = "动作组合节点"; - //} - - public void AddAction(NodeControlBase node, bool isTask = false) - { - /*TextBlock actionText = new TextBlock - { - Text = node.MethodDetails.MethodName + (isTask ? " (Task)" : ""), - Margin = new Thickness(10, 2, 0, 0), - Tag = node.MethodDetails, - };*/ - /// Node?.AddNode((SingleActionNode)node.ViewModel.Node); - // ActionsListBox.Items.Add(node); - } - - /* public async Task ExecuteActions(DynamicContext context) - { - foreach (TextBlock item in ActionsListBox.Items) - { - dynamic tag = item.Tag; - IAction action = tag.Action; - bool isTask = tag.IsTask; - - if (isTask) - { - await Task.Run(() => action.Execute(Node.MethodDetails, context)); - } - else - { - action.Execute(Node.MethodDetails, context); - } - } - }*/ - - - - private void ActionsListBox_Drop(object sender, DragEventArgs e) - { - /*if (e.Data.GetDataPresent("Type")) - { - Type droppedType = e.Data.GetData("Type") as Type; - - if (droppedType != null && typeof(ICondition).IsAssignableFrom(droppedType) && droppedType.IsClass) - { - // 创建一个新的 TextBlock 并设置其属性 - TextBlock conditionText = new TextBlock - { - Text = droppedType.Name, - Margin = new Thickness(10, 2, 0, 0), - Tag = droppedType - }; - - // 为 TextBlock 添加鼠标左键按下事件处理程序 - // conditionText.MouseLeftButtonDown += TypeText_MouseLeftButtonDown; - // 为 TextBlock 添加鼠标移动事件处理程序 - // conditionText.MouseMove += TypeText_MouseMove; - - // 将 TextBlock 添加到 ActionsListBox 中 - ActionsListBox.Items.Add(conditionText); - } - }*/ - e.Handled = true; - } - - // 用于拖动的鼠标事件处理程序 - private void TypeText_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) - { - _dragStartPoint = e.GetPosition(null); - } - - private void TypeText_MouseMove(object sender, MouseEventArgs e) - { - Point mousePos = e.GetPosition(null); - Vector diff = _dragStartPoint - mousePos; - - if (e.LeftButton == MouseButtonState.Pressed && - (Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance || - Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance)) - { - if (sender is TextBlock typeText) - { - MoveNodeData moveNodeData = new MoveNodeData - { - NodeControlType = Library.Enums.NodeControlType.ConditionRegion - }; - - // 创建一个 DataObject 用于拖拽操作,并设置拖拽效果 - DataObject dragData = new DataObject(MouseNodeType.CreateDllNodeInCanvas, moveNodeData); - - DragDrop.DoDragDrop(typeText, dragData, DragDropEffects.Move); - - - //var dragData = new DataObject(MouseNodeType.CreateNodeInCanvas, typeText.Tag); - //DragDrop.DoDragDrop(typeText, dragData, DragDropEffects.Move); - } - } - } - - - } -} diff --git a/WorkBench.Remote/Node/View/ConditionNodeControl.xaml b/WorkBench.Remote/Node/View/ConditionNodeControl.xaml deleted file mode 100644 index 92adc6d..0000000 --- a/WorkBench.Remote/Node/View/ConditionNodeControl.xaml +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/WorkBench.Remote/Node/View/ConditionNodeControl.xaml.cs b/WorkBench.Remote/Node/View/ConditionNodeControl.xaml.cs deleted file mode 100644 index 7b32096..0000000 --- a/WorkBench.Remote/Node/View/ConditionNodeControl.xaml.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Serein.NodeFlow.Model; -using Serein.WorkBench.Node.ViewModel; - -namespace Serein.WorkBench.Node.View -{ - /// - /// ConditionNode.xaml 的交互逻辑 - /// - public partial class ConditionNodeControl : NodeControlBase - { - public ConditionNodeControl() : base() - { - // 窗体初始化需要 - ViewModel = new ConditionNodeControlViewModel (new SingleConditionNode()); - DataContext = ViewModel; - InitializeComponent(); - } - - public ConditionNodeControl(ConditionNodeControlViewModel viewModel):base(viewModel) - { - DataContext = viewModel; - InitializeComponent(); - } - - } -} diff --git a/WorkBench.Remote/Node/View/ConditionRegionControl.xaml b/WorkBench.Remote/Node/View/ConditionRegionControl.xaml deleted file mode 100644 index b303a69..0000000 --- a/WorkBench.Remote/Node/View/ConditionRegionControl.xaml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - -