using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Serein.Library; using Serein.Library.Api; using Serein.Workbench.Api; using Serein.Workbench.Node; using Serein.Workbench.Node.View; using Serein.Workbench.Node.ViewModel; using Serein.Workbench.ViewModels; using Serein.Workbench.Views; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Media; namespace Serein.Workbench.Services { /// /// 流程节点管理 /// public class FlowNodeService { #region 流程节点操作的相关事件 /// /// 添加了画布 /// public Action OnCreateFlowCanvasView { get; set; } /// /// 移除了画布 /// public Action OnRemoveFlowCanvasView { get; set; } /// /// 添加了节点 /// public Action OnCreateNode { get; set; } #endregion #region 创建节点相关的属性 /// /// 当前查看的画布 /// public FlowCanvasView CurrentSelectCanvas { get; set; } /// /// 当前拖动的方法信息 /// public MethodDetailsInfo? CurrentDragMdInfo { get; set; } /// /// 当前需要创建的节点类型 /// public NodeControlType CurrentNodeControlType { get; set; } = NodeControlType.None; /// /// 当前鼠标位置 /// public PositionOfUI? CurrentMouseLocation { get; set; } /// /// 当前选中的节点 /// public NodeControlBase? CurrentSelectNodeControl { get; set; } /// /// 连接数据 /// public ConnectingData ConnectingData { get; } = new ConnectingData(); #endregion /// /// 连接开始节点 /// public NodeControlBase? ConnectionStartNode { get; set; } /// /// 连接最终落点节点 /// public NodeControlBase? ConnectionEndNode { get; set; } /// /// 当前所有画布 /// public FlowCanvasView[] FlowCanvass => Canvass.Select(c => c.Value).ToArray(); /// /// 记录流程画布 /// private readonly Dictionary Canvass = []; /// /// 记录加载的节点 /// private readonly Dictionary NodeControls = []; /// /// 运行环境接口 /// private readonly IFlowEnvironment flowEnvironment; /// /// 运行环境事件转发器 /// private readonly IFlowEEForwardingService flowEEForwardingService; #region 初始化 public FlowNodeService(IFlowEnvironment flowEnvironment, IFlowEEForwardingService flowEEForwardingService) { this.flowEnvironment = flowEnvironment; this.flowEEForwardingService = flowEEForwardingService; InitFlowEvent(); InitNodeType(); } /// /// 注册节点类型 /// private void InitNodeType() { flowEnvironment.NodeMVVMManagement.RegisterUI(NodeControlType.UI, typeof(UINodeControl), typeof(UINodeControlViewModel)); flowEnvironment.NodeMVVMManagement.RegisterUI(NodeControlType.Action, typeof(ActionNodeControl), typeof(ActionNodeControlViewModel)); flowEnvironment.NodeMVVMManagement.RegisterUI(NodeControlType.Flipflop, typeof(FlipflopNodeControl), typeof(FlipflopNodeControlViewModel)); flowEnvironment.NodeMVVMManagement.RegisterUI(NodeControlType.ExpOp, typeof(ExpOpNodeControl), typeof(ExpOpNodeControlViewModel)); flowEnvironment.NodeMVVMManagement.RegisterUI(NodeControlType.ExpCondition, typeof(ConditionNodeControl), typeof(ConditionNodeControlViewModel)); flowEnvironment.NodeMVVMManagement.RegisterUI(NodeControlType.ConditionRegion, typeof(ConditionRegionControl), typeof(ConditionRegionNodeControlViewModel)); flowEnvironment.NodeMVVMManagement.RegisterUI(NodeControlType.GlobalData, typeof(GlobalDataControl), typeof(GlobalDataNodeControlViewModel)); flowEnvironment.NodeMVVMManagement.RegisterUI(NodeControlType.Script, typeof(ScriptNodeControl), typeof(ScriptNodeControlViewModel)); flowEnvironment.NodeMVVMManagement.RegisterUI(NodeControlType.NetScript, typeof(NetScriptNodeControl), typeof(NetScriptNodeControlViewModel)); } /// /// 注册节点事件 /// private void InitFlowEvent() { flowEEForwardingService.OnCanvasCreate += FlowEEForwardingService_OnCanvasCreate; // 创建了画布 flowEEForwardingService.OnCanvasRemove += FlowEEForwardingService_OnCanvasRemove; // 移除了画布 flowEEForwardingService.OnNodeCreate += FlowEEForwardingService_OnNodeCreate; // 创建了节点 flowEEForwardingService.OnNodeRemove += FlowEEForwardingService_OnNodeRemove; // 移除了节点 flowEEForwardingService.OnNodePlace += FlowEEForwardingService_OnNodePlace; // 节点放置在容器中 flowEEForwardingService.OnNodeTakeOut += FlowEEForwardingService_OnNodeTakeOut; ; // 节点从容器中取出 flowEEForwardingService.OnNodeConnectChange += FlowEEForwardingService_OnNodeConnectChange; // 节点连接状态改变事件 flowEEForwardingService.OnStartNodeChange += FlowEEForwardingService_OnStartNodeChange; // 画布起始节点改变 } private void FlowEEForwardingService_OnStartNodeChange(StartNodeChangeEventArgs eventArgs) { string oldNodeGuid = eventArgs.OldNodeGuid; string newNodeGuid = eventArgs.NewNodeGuid; if (!TryGetControl(newNodeGuid, out var newStartNodeControl)) return; if (!string.IsNullOrEmpty(oldNodeGuid)) { if (!TryGetControl(oldNodeGuid, out var oldStartNodeControl)) return; oldStartNodeControl.BorderBrush = Brushes.Black; oldStartNodeControl.BorderThickness = new Thickness(0); } newStartNodeControl.BorderBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#04FC10")); newStartNodeControl.BorderThickness = new Thickness(2); var node = newStartNodeControl?.ViewModel?.NodeModel; } private void FlowEEForwardingService_OnNodeConnectChange(NodeConnectChangeEventArgs e) { var canvasGuid = e.CanvasGuid; string fromNodeGuid = e.FromNodeGuid; string toNodeGuid = e.ToNodeGuid; if (!TryGetCanvas(canvasGuid, out var flowCanvas) || flowCanvas is not IFlowCanvas flow || !TryGetControl(fromNodeGuid, out var fromNode) || !TryGetControl(toNodeGuid, out var toNode)) { return; } Action? action = (e.JunctionOfConnectionType, e.ChangeType) switch { (JunctionOfConnectionType.Invoke, NodeConnectChangeEventArgs.ConnectChangeType.Create) => () => flow.CreateInvokeConnection(fromNode, toNode, e.ConnectionInvokeType), // 创建节点之间的调用关系 (JunctionOfConnectionType.Invoke, NodeConnectChangeEventArgs.ConnectChangeType.Remove) => () => flow.RemoveInvokeConnection(fromNode, toNode), // 移除节点之间的调用关系 (JunctionOfConnectionType.Arg, NodeConnectChangeEventArgs.ConnectChangeType.Create) => () => flow.CreateArgConnection(fromNode, toNode, e.ConnectionArgSourceType, e.ArgIndex), // 创建节点之间的参数传递关系 (JunctionOfConnectionType.Arg, NodeConnectChangeEventArgs.ConnectChangeType.Remove) => () => flow.RemoveArgConnection(fromNode, toNode, e.ArgIndex), // 移除节点之间的参数传递关系 _ => null }; action?.Invoke(); return; } private void FlowEEForwardingService_OnNodeTakeOut(NodeTakeOutEventArgs eventArgs) { string nodeGuid = eventArgs.NodeGuid; if (!TryGetControl(nodeGuid, out var nodeControl)) { return; } nodeControl.TakeOutContainer(); // 从容器节点中取出 } private void FlowEEForwardingService_OnNodePlace(NodePlaceEventArgs eventArgs) { string nodeGuid = eventArgs.NodeGuid; string containerNodeGuid = eventArgs.ContainerNodeGuid; if (!TryGetControl(nodeGuid, out var nodeControl) || !TryGetControl(containerNodeGuid, out var containerNodeControl)) { return; } if (containerNodeControl is not INodeContainerControl containerControl) { SereinEnv.WriteLine(InfoType.WARN, $"节点[{nodeGuid}]无法放置于节点[{containerNodeGuid}]," + $"因为后者并不实现 INodeContainerControl 接口"); return; } nodeControl.PlaceToContainer(containerControl); // 放置在容器节点中 } #endregion #region 节点、画布相关的事件 /// /// 节点移除 /// /// private void FlowEEForwardingService_OnNodeRemove(NodeRemoveEventArgs eventArgs) { if (!TryGetCanvas(eventArgs.CanvasGuid, out var nodeCanvas) || nodeCanvas is not IFlowCanvas api) { SereinEnv.WriteLine(InfoType.INFO, $"无法移除节点,画布不存在。"); return; } if (!TryGetControl(eventArgs.NodeGuid, out var nodeControl)) { SereinEnv.WriteLine(InfoType.INFO, $"无法移除节点,节点不存在。"); return; } api.Remove(nodeControl); } /// /// 节点创建 /// /// private void FlowEEForwardingService_OnNodeCreate(NodeCreateEventArgs eventArgs) { #region 校验事件传入值 var position = eventArgs.Position; var cavnasGuid = eventArgs.CanvasGuid; var nodeModel = eventArgs.NodeModel; if (NodeControls.ContainsKey(nodeModel.Guid)) { SereinEnv.WriteLine(InfoType.WARN, $"创建节点时发生意外:节点Guid重复 - {nodeModel.Guid}"); return; } if (!flowEnvironment.NodeMVVMManagement.TryGetType(nodeModel.ControlType, out var nodeMVVM)) { SereinEnv.WriteLine(InfoType.INFO, $"无法创建{nodeModel.ControlType}节点,节点类型尚未注册。"); return; } if (nodeMVVM.ControlType == null|| nodeMVVM.ViewModelType == null) { SereinEnv.WriteLine(InfoType.INFO, $"无法创建{nodeModel.ControlType}节点,UI类型尚未注册(请通过 NodeMVVMManagement.RegisterUI() 方法进行注册)。"); return; } if (!TryGetCanvas(cavnasGuid, out var nodeCanvas)) { SereinEnv.WriteLine(InfoType.INFO, $"无法创建{nodeModel.ControlType}节点,不存在画布【{cavnasGuid}】。"); return; } #endregion #region 创建控件 NodeControlBase nodeControl; try { nodeControl = CreateNodeControl(nodeMVVM.ControlType, // 控件UI类型 nodeMVVM.ViewModelType, // 控件VIewModel类型 nodeModel, // 控件数据实体 nodeCanvas); // 所在画布 OnCreateNode.Invoke(nodeControl); // 创建节点 } catch (Exception ex) { SereinEnv.WriteLine(ex); return; } NodeControls.TryAdd(nodeControl.ViewModel.NodeModel.Guid, nodeControl); // 记录创建了的节点控件 #endregion } /// /// 画布移除 /// /// private void FlowEEForwardingService_OnCanvasRemove(CanvasRemoveEventArgs eventArgs) { if (!TryGetCanvas(eventArgs.CanvasGuid, out var nodeCanvas)) { SereinEnv.WriteLine(InfoType.INFO, $"无法移除画布,画布不存在。"); return; } OnRemoveFlowCanvasView.Invoke(nodeCanvas); } /// /// 画布创建 /// /// private void FlowEEForwardingService_OnCanvasCreate(CanvasCreateEventArgs eventArgs) { var model = eventArgs.Model; var guid = model.Guid; if (Canvass.ContainsKey(guid)) { SereinEnv.WriteLine(InfoType.WARN, $"创建画布时发生意外:节点Guid重复 - {guid}"); return; } FlowCanvasView canvasView = new FlowCanvasView(model); //canvasView.ViewModel.Model = model; //canvasView.ViewModel.CanvasGuid = model.Guid; //canvasView.ViewModel.Name = model.Name; //canvasView.SetBinding(model); Canvass.Add(model.Guid, canvasView); OnCreateFlowCanvasView.Invoke(canvasView); // 传递给订阅者 } #endregion /// /// 创建节点控件 /// /// 节点控件视图控件类型 /// 节点控件ViewModel类型 /// 节点Model实例 /// 节点所在画布 /// /// 无法创建节点控件 private static NodeControlBase CreateNodeControl(Type controlType, Type viewModelType, NodeModelBase model, IFlowCanvas nodeCanvas) { if ((controlType is null) || viewModelType is null || model is null) { throw new Exception("无法创建节点控件"); } if (typeof(NodeControlBase).IsSubclassOf(controlType) || typeof(NodeControlViewModelBase).IsSubclassOf(viewModelType)) { throw new Exception("无法创建节点控件"); } if (string.IsNullOrEmpty(model.Guid)) { model.Guid = Guid.NewGuid().ToString(); } var viewModel = Activator.CreateInstance(viewModelType, [model]); var controlObj = Activator.CreateInstance(controlType, [viewModel]); if (controlObj is NodeControlBase nodeControl) { nodeControl.FlowCanvas = nodeCanvas; return nodeControl; } else { throw new Exception("无法创建节点控件"); } } /// /// 从Guid获取节点控件 /// /// /// /// private bool TryGetControl(string nodeGuid, out NodeControlBase nodeControl) { nodeControl = null; if (string.IsNullOrEmpty(nodeGuid)) { return false; } return NodeControls.TryGetValue(nodeGuid, out nodeControl); } /// /// 从Guid获取画布视图 /// /// /// /// private bool TryGetCanvas(string nodeGuid, out FlowCanvasView flowCanvas) { flowCanvas = null; if (string.IsNullOrEmpty(nodeGuid)) { return false; } return Canvass.TryGetValue(nodeGuid, out flowCanvas); } #region 节点的复制与粘贴 /// /// 从节点信息转换为Json文本数据 /// public string CpoyNodeInfo(List dictSelection) { // 遍历当前已选节点 foreach (var node in dictSelection.ToArray()) { if (node.ChildrenNode.Count == 0) { continue; } // 遍历这些节点的子节点,添加过来 foreach (var childNode in node.ChildrenNode) { dictSelection.Add(childNode); } } var nodeInfos = dictSelection.Select(item => item.ToInfo()); JObject json = new JObject() { ["nodes"] = JArray.FromObject(nodeInfos) }; var jsonText = json.ToString(); try { SereinEnv.WriteLine(InfoType.INFO, $"复制已选节点({dictSelection.Count}个)"); return jsonText; } catch (Exception ex) { SereinEnv.WriteLine(InfoType.ERROR, $"复制失败:{ex.Message}"); return string.Empty; } } /// /// 从Json中加载节点 /// /// 需要加载在哪个画布上 /// 文本内容 /// 需要加载的位置 public void PasteNodeInfo(string canvasGuid, string jsonText, PositionOfUI positionOfUI) { try { List? nodes = JsonConvert.DeserializeObject>(jsonText); if (nodes is not null && nodes.Count != 0) { } if (nodes is null || nodes.Count < 0) { return; } #region 节点去重 Dictionary guids = new Dictionary(); // 记录 Guid // 遍历当前节点 foreach (var node in nodes.ToArray()) { if (NodeControls.ContainsKey(node.Guid) && !guids.ContainsKey(node.Guid)) { // 如果是没出现过、且在当前记录中重复的Guid,则记录并新增对应的映射。 guids.TryAdd(node.Guid, Guid.NewGuid().ToString()); } else { // 出现过的Guid,说明重复添加了。应该不会走到这。 continue; } if (node.ChildNodeGuids is null) { continue; // 跳过没有子节点的节点 } // 遍历这些节点的子节点,获得完整的已选节点信息 foreach (var childNodeGuid in node.ChildNodeGuids) { if (NodeControls.ContainsKey(node.Guid) && !NodeControls.ContainsKey(node.Guid)) { // 当前Guid并不重复,跳过替换 continue; } if (!guids.ContainsKey(childNodeGuid)) { // 如果是没出现过的Guid,则记录并新增对应的映射。 guids.TryAdd(node.Guid, Guid.NewGuid().ToString()); } if (!string.IsNullOrEmpty(childNodeGuid) && NodeControls.TryGetValue(childNodeGuid, out var nodeControl)) { var newNodeInfo = nodeControl.ViewModel.NodeModel.ToInfo(); nodes.Add(newNodeInfo); } } } // Guid去重 StringBuilder sb = new StringBuilder(jsonText); foreach (var kv in guids) { sb.Replace(kv.Key, kv.Value); } string result = sb.ToString(); /*var replacer = new GuidReplacer(); foreach (var kv in guids) { replacer.AddReplacement(kv.Key, kv.Value); } string result = replacer.Replace(jsonText);*/ //SereinEnv.WriteLine(InfoType.ERROR, result); nodes = JsonConvert.DeserializeObject>(result); if (nodes is null || nodes.Count < 0) { return; } #endregion // 获取第一个节点的原始位置 var index0NodeX = nodes[0].Position.X; var index0NodeY = nodes[0].Position.Y; // 计算所有节点相对于第一个节点的偏移量 foreach (var node in nodes) { node.CanvasGuid = canvasGuid; // 替换画布Guid var offsetX = node.Position.X - index0NodeX; var offsetY = node.Position.Y - index0NodeY; // 根据鼠标位置平移节点 node.Position = new PositionOfUI(positionOfUI.X + offsetX, positionOfUI.Y + offsetY); } _ = flowEnvironment.LoadNodeInfosAsync(nodes); } catch (Exception ex) { //SereinEnv.WriteLine(InfoType.ERROR, $"粘贴节点时发生异常:{ex}"); } // SereinEnv.WriteLine(InfoType.INFO, $"剪贴板文本内容: {clipboardText}"); } #endregion #region 向运行环境发出请求 /// /// 向运行环境发出请求:添加画布 /// /// public void CreateFlowCanvas() { int width = 1200; int height = 780; _ = Task.Run(async () => { var result = await flowEnvironment.CreateCanvasAsync("", width, height); Console.WriteLine(result.Guid); }); } /// /// 向运行环境发出请求:移除画布 /// public void RemoveFlowCanvas() { if (CurrentSelectCanvas is null) { return; } var model = ((FlowCanvasViewModel)CurrentSelectCanvas.DataContext).Model; _ = flowEnvironment.RemoveCanvasAsync(model.Guid); } /// /// 向运行环境发出请求:创建节点 /// public void CreateNode() { var model = ((FlowCanvasViewModel)CurrentSelectCanvas.DataContext).Model; string canvasGuid = model.Guid; NodeControlType nodeType = CurrentNodeControlType; PositionOfUI? position = CurrentMouseLocation; MethodDetailsInfo? methodDetailsInfo = CurrentDragMdInfo; if (position is null) { return; } _ = flowEnvironment.CreateNodeAsync(canvasGuid, nodeType, position, methodDetailsInfo); } /// /// 向运行环境发出请求:移除节点 /// public void RemoteNode(NodeControlBase nodeControl) { //NodeControlBase? node = CurrentSelectNodeControl; if (nodeControl is null) { return; } var model = nodeControl.ViewModel.NodeModel; if (model is null) { return; } _ = flowEnvironment.RemoveNodeAsync(model.CanvasGuid, model.Guid); } #endregion } }