From f7cae3493fcfbb10f21a343a887fe387c6e5a10c Mon Sep 17 00:00:00 2001
From: fengjiayi <12821976+ning_xi@user.noreply.gitee.com>
Date: Tue, 27 May 2025 23:46:06 +0800
Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=94=BB=E5=B8=83=E4=BF=A1?=
=?UTF-8?q?=E6=81=AF=E8=A7=86=E5=9B=BE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Library/Enums/NodeType.cs | 25 ++---
Library/Extension/FlowModelExtension.cs | 8 +-
Library/FlowNode/FlowCanvasDetails.cs | 23 +++-
Library/FlowNode/NodeModelBaseData.cs | 40 +++++--
Library/FlowNode/NodeModelBaseFunc.cs | 2 +-
Library/FlowNode/SereinProjectData.cs | 5 +
Library/Serein.Library.csproj | 7 +-
Library/Utils/SereinIoc.cs | 2 +-
Library/Utils/UIContextOperation.cs | 19 +++-
NodeFlow/Env/FlowEnvironment.cs | 102 ++++++++----------
NodeFlow/Env/RemoteFlowEnvironment.cs | 18 +++-
NodeFlow/FlowWorkManagement.cs | 2 +-
NodeFlow/Model/SingleFlowCallNode.cs | 33 ++++++
NodeFlow/Model/SingleGlobalDataNode.cs | 4 +-
Serein.Library.MyGenerator/Attribute.cs | 2 +-
Workbench/App.xaml.cs | 1 +
Workbench/Models/TabModel.cs | 7 +-
Workbench/Node/View/ActionNodeControl.xaml | 10 +-
Workbench/Node/View/ConnectionControl.cs | 2 +-
Workbench/Node/View/FlowCallNodeControl.xaml | 16 +++
.../Node/View/FlowCallNodeControl.xaml.cs | 36 +++++++
.../ViewModel/FlowCallNodeControlViewModel.cs | 18 ++++
Workbench/Serein.WorkBench.csproj | 4 +
Workbench/Services/FlowNodeService.cs | 25 ++++-
Workbench/Services/KeyEventService.cs | 4 +-
.../ViewModels/CanvasNodeTreeViewModel.cs | 41 +++++++
Workbench/ViewModels/FlowEditViewModel.cs | 22 ++--
Workbench/ViewModels/Locator.cs | 17 +--
Workbench/Views/CanvasInfoView.xaml | 96 +++++++++++++++++
Workbench/Views/CanvasInfoView.xaml.cs | 32 ++++++
Workbench/Views/FlowCanvasView.xaml.cs | 46 ++++++--
Workbench/Views/FlowEditView.xaml | 14 ++-
Workbench/Views/FlowWorkbenchView.xaml | 4 +-
33 files changed, 532 insertions(+), 155 deletions(-)
create mode 100644 NodeFlow/Model/SingleFlowCallNode.cs
create mode 100644 Workbench/Node/View/FlowCallNodeControl.xaml
create mode 100644 Workbench/Node/View/FlowCallNodeControl.xaml.cs
create mode 100644 Workbench/Node/ViewModel/FlowCallNodeControlViewModel.cs
create mode 100644 Workbench/ViewModels/CanvasNodeTreeViewModel.cs
create mode 100644 Workbench/Views/CanvasInfoView.xaml
create mode 100644 Workbench/Views/CanvasInfoView.xaml.cs
diff --git a/Library/Enums/NodeType.cs b/Library/Enums/NodeType.cs
index 37f7fbc..24f0346 100644
--- a/Library/Enums/NodeType.cs
+++ b/Library/Enums/NodeType.cs
@@ -65,16 +65,6 @@ namespace Serein.Library
}
-
- class UserInfo
- {
- public string Name;
- public int Id;
- public string[] PhoneNums;
- }
-
-
-
///
/// 生成的节点控件
@@ -109,11 +99,7 @@ namespace Serein.Library
///
[Description("base")]
ExpCondition,
- ///
- /// 条件节点区域
- ///
- [Description("base")]
- ConditionRegion,
+
///
/// 全局数据
///
@@ -129,6 +115,15 @@ namespace Serein.Library
///
[Description("base")]
NetScript,
+
+ ///
+ /// 流程调用节点(流程图公开的节点)
+ ///
+ [Description("base")]
+ FlowCall,
+
+
+
}
}
diff --git a/Library/Extension/FlowModelExtension.cs b/Library/Extension/FlowModelExtension.cs
index 6e051d6..c930380 100644
--- a/Library/Extension/FlowModelExtension.cs
+++ b/Library/Extension/FlowModelExtension.cs
@@ -93,7 +93,6 @@ namespace Serein.Library
public static NodeInfo ToInfo(this NodeModelBase nodeModel)
{
// if (MethodDetails == null) return null;
-
var trueNodes = nodeModel.SuccessorNodes[ConnectionInvokeType.IsSucceed].Select(item => item.Guid); // 真分支
var falseNodes = nodeModel.SuccessorNodes[ConnectionInvokeType.IsFail].Select(item => item.Guid);// 假分支
var errorNodes = nodeModel.SuccessorNodes[ConnectionInvokeType.IsError].Select(item => item.Guid);// 异常分支
@@ -103,8 +102,9 @@ namespace Serein.Library
var nodeInfo = new NodeInfo
{
- CanvasGuid = nodeModel.CanvasGuid,
+ CanvasGuid = nodeModel.CanvasDetails.Guid,
Guid = nodeModel.Guid,
+ IsPublic = nodeModel.IsPublic,
AssemblyName = nodeModel.MethodDetails.AssemblyName,
MethodName = nodeModel.MethodDetails?.MethodName,
Label = nodeModel.MethodDetails?.MethodAnotherName,
@@ -131,18 +131,18 @@ namespace Serein.Library
/// 从节点信息加载节点
///
///
+ ///
///
///
public static void LoadInfo(this NodeModelBase nodeModel, NodeInfo nodeInfo)
{
- nodeModel.CanvasGuid = nodeInfo.CanvasGuid;
nodeModel.Guid = nodeInfo.Guid;
nodeModel.Position = nodeInfo.Position ?? new PositionOfUI(0, 0);// 加载位置信息
var md = nodeModel.MethodDetails; // 当前节点的方法说明
nodeModel.MethodDetails.IsProtectionParameter = nodeInfo.IsProtectionParameter; // 保护参数
nodeModel.DebugSetting.IsInterrupt = nodeInfo.IsInterrupt; // 是否中断
nodeModel.DebugSetting.IsEnable = nodeInfo.IsEnable; // 是否使能
-
+ nodeModel.IsPublic = nodeInfo.IsPublic; // 是否全局公开
if (md != null)
{
if (md.ParameterDetailss == null)
diff --git a/Library/FlowNode/FlowCanvasDetails.cs b/Library/FlowNode/FlowCanvasDetails.cs
index 0fa1ef7..c8d6e49 100644
--- a/Library/FlowNode/FlowCanvasDetails.cs
+++ b/Library/FlowNode/FlowCanvasDetails.cs
@@ -2,6 +2,7 @@
using Serein.Library.FlowNode;
using System;
using System.Collections.Generic;
+using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
@@ -27,9 +28,21 @@ namespace Serein.Library
public IFlowEnvironment Env { get; }
///
- /// 标识画布ID
+ /// 画布拥有的节点
///
[PropertyInfo(IsProtection = true)]
+ private System.Collections.ObjectModel.ObservableCollection _nodes = [];
+
+ ///
+ /// 画布公开的节点
+ ///
+ [PropertyInfo(IsProtection = true)]
+ private System.Collections.ObjectModel.ObservableCollection _publicNodes = [];
+
+ ///
+ /// 标识画布ID
+ ///
+ [PropertyInfo(IsProtection = false)]
private string _guid;
///
@@ -54,19 +67,19 @@ namespace Serein.Library
/// 预览位置X
///
[PropertyInfo(IsNotification = true)]
- private double _viewX ;
+ private double _viewX;
///
/// 预览位置Y
///
[PropertyInfo(IsNotification = true)]
- private double _viewY ;
+ private double _viewY;
///
/// 缩放比例X
///
[PropertyInfo(IsNotification = true)]
- private double _scaleX = 1;
+ private double _scaleX = 1;
///
/// 缩放比例Y
@@ -85,7 +98,7 @@ namespace Serein.Library
public partial class FlowCanvasDetails
{
-
+
}
diff --git a/Library/FlowNode/NodeModelBaseData.cs b/Library/FlowNode/NodeModelBaseData.cs
index 44efedb..6f5d7be 100644
--- a/Library/FlowNode/NodeModelBaseData.cs
+++ b/Library/FlowNode/NodeModelBaseData.cs
@@ -14,7 +14,7 @@ namespace Serein.Library
///
/// 节点基类(数据)
///
- [NodeProperty(ValuePath = NodeValuePath.None)]
+ [NodeProperty(ValuePath = NodeValuePath.Node)]
public abstract partial class NodeModelBase : IDynamicFlowNode
{
///
@@ -35,13 +35,11 @@ namespace Serein.Library
[PropertyInfo(IsProtection = true)]
private NodeControlType _controlType;
-
///
/// 所属画布
///
- [PropertyInfo(IsProtection = true)]
- private string _canvasGuid ;
-
+ [PropertyInfo(IsProtection = true)]
+ private FlowCanvasDetails _canvasDetails ;
///
/// 在画布中的位置
@@ -56,10 +54,10 @@ namespace Serein.Library
private string _displayName;
///
- /// 是否为起点控件
+ /// 是否公开
///
- [PropertyInfo]
- private bool _isStart;
+ [PropertyInfo(IsNotification = true, CustomCodeAtEnd = "NodePublicStateChanged();")]
+ private bool _isPublic;
///
/// 附加的调试功能
@@ -68,7 +66,7 @@ namespace Serein.Library
private NodeDebugSetting _debugSetting ;
///
- /// 方法描述。不包含Method与委托,需要通过MethodName从环境中获取委托进行调用。
+ /// 方法描述。包含参数信息。不包含Method与委托,如若需要调用对应的方法,需要通过MethodName从环境中获取委托进行调用。
///
[PropertyInfo(IsProtection = true)]
private MethodDetails _methodDetails ;
@@ -122,7 +120,29 @@ namespace Serein.Library
///
public List ChildrenNode { get; }
-
+ ///
+ /// 节点公开状态发生改变
+ ///
+ private void NodePublicStateChanged()
+ {
+
+ if (IsPublic)
+ {
+ // 公开节点
+ if (!CanvasDetails.PublicNodes.Contains(this))
+ {
+ CanvasDetails.PublicNodes.Add(this);
+ }
+ }
+ else
+ {
+ // 取消公开
+ if (CanvasDetails.PublicNodes.Contains(this))
+ {
+ CanvasDetails.PublicNodes.Remove(this);
+ }
+ }
+ }
}
}
diff --git a/Library/FlowNode/NodeModelBaseFunc.cs b/Library/FlowNode/NodeModelBaseFunc.cs
index fa3a573..0c734dc 100644
--- a/Library/FlowNode/NodeModelBaseFunc.cs
+++ b/Library/FlowNode/NodeModelBaseFunc.cs
@@ -23,7 +23,7 @@ namespace Serein.Library
///
- /// 节点基类(数据):条件控件,动作控件,条件区域,动作区域
+ /// 节点基类
///
public abstract partial class NodeModelBase : IDynamicFlowNode
{
diff --git a/Library/FlowNode/SereinProjectData.cs b/Library/FlowNode/SereinProjectData.cs
index 3cd8754..8d7944f 100644
--- a/Library/FlowNode/SereinProjectData.cs
+++ b/Library/FlowNode/SereinProjectData.cs
@@ -197,6 +197,11 @@ namespace Serein.Library
///
public string Guid { get; set; }
+ ///
+ /// 是否全局公开
+ ///
+ public bool IsPublic { get; set; }
+
///
/// 节点方法所属的程序集名称
///
diff --git a/Library/Serein.Library.csproj b/Library/Serein.Library.csproj
index 64b0a6e..761a9f1 100644
--- a/Library/Serein.Library.csproj
+++ b/Library/Serein.Library.csproj
@@ -24,12 +24,15 @@
+
+
+
@@ -51,10 +54,6 @@
-
-
-
-
True
diff --git a/Library/Utils/SereinIoc.cs b/Library/Utils/SereinIoc.cs
index 8642eff..f0b2ce8 100644
--- a/Library/Utils/SereinIoc.cs
+++ b/Library/Utils/SereinIoc.cs
@@ -198,7 +198,7 @@ namespace Serein.Library.Utils
public string Name { get; set; }
public Type Type { get; set; }
}
- private const string FlowBaseClassName = "<>$FlowBaseClass!@#";
+ private const string FlowBaseClassName = "@FlowBaseClass";
public Dictionary> BuildDependencyTree()
diff --git a/Library/Utils/UIContextOperation.cs b/Library/Utils/UIContextOperation.cs
index d377792..3771379 100644
--- a/Library/Utils/UIContextOperation.cs
+++ b/Library/Utils/UIContextOperation.cs
@@ -54,10 +54,11 @@ namespace Serein.Library.Utils
}
///
- /// 同步方式进行调用方法
+ /// 同步方式在UI线程上进行调用方法
///
/// 要执行的UI操作
- public void Invoke(Action uiAction)
+ /// 异常发生时的回调
+ public void Invoke(Action uiAction, Action onException = null)
{
if(context is null && getUiContext != null)
{
@@ -65,7 +66,15 @@ namespace Serein.Library.Utils
}
context?.Post(state =>
{
- uiAction?.Invoke();
+ try
+ {
+ uiAction?.Invoke();
+ }
+ catch (Exception ex)
+ {
+ if(onException != null) onException(ex);
+ Debug.WriteLine(ex);
+ }
}, null);
}
@@ -73,8 +82,9 @@ namespace Serein.Library.Utils
/// 异步方式进行调用
///
/// 要执行的UI操作
+ /// 异常发生时的回调
///
- public Task InvokeAsync(Action uiAction)
+ public Task InvokeAsync(Action uiAction, Action onException = null)
{
if (context is null && getUiContext != null)
{
@@ -92,6 +102,7 @@ namespace Serein.Library.Utils
catch (Exception ex)
{
tcs.SetException(ex);
+ if (onException != null) onException(ex);
Debug.WriteLine(ex);
}
}, null);
diff --git a/NodeFlow/Env/FlowEnvironment.cs b/NodeFlow/Env/FlowEnvironment.cs
index 1c84fb0..67c7b7c 100644
--- a/NodeFlow/Env/FlowEnvironment.cs
+++ b/NodeFlow/Env/FlowEnvironment.cs
@@ -6,6 +6,7 @@ using Serein.Library.Utils.SereinExpression;
using Serein.NodeFlow.Model;
using Serein.NodeFlow.Tool;
using System;
+using System.Diagnostics;
using System.Reactive;
using System.Reflection;
using System.Text;
@@ -52,7 +53,7 @@ namespace Serein.NodeFlow.Env
NodeMVVMManagement.RegisterModel(NodeControlType.Flipflop, typeof(SingleFlipflopNode)); // 触发器节点
NodeMVVMManagement.RegisterModel(NodeControlType.ExpOp, typeof(SingleExpOpNode)); // 表达式节点
NodeMVVMManagement.RegisterModel(NodeControlType.ExpCondition, typeof(SingleConditionNode)); // 条件表达式节点
- NodeMVVMManagement.RegisterModel(NodeControlType.ConditionRegion, typeof(CompositeConditionNode)); // 条件区域
+ //NodeMVVMManagement.RegisterModel(NodeControlType.ConditionRegion, typeof(CompositeConditionNode)); // 条件区域
NodeMVVMManagement.RegisterModel(NodeControlType.GlobalData, typeof(SingleGlobalDataNode)); // 全局数据节点
NodeMVVMManagement.RegisterModel(NodeControlType.Script, typeof(SingleScriptNode)); // 脚本节点
NodeMVVMManagement.RegisterModel(NodeControlType.NetScript, typeof(SingleNetScriptNode)); // 脚本节点
@@ -309,36 +310,6 @@ namespace Serein.NodeFlow.Env
private List FlipflopNodes { get; } = [];
- /*
- ///
- /// 起始节点私有属性
- ///
- private NodeModelBase? _startNode = null;
-
- ///
- /// 起始节点
- ///
- private NodeModelBase? StartNode
- {
- get
- {
- return _startNode;
- }
- set
- {
- if (value is null)
- {
- return;
- }
- if (_startNode is not null)
- {
- _startNode.IsStart = false;
- }
- value.IsStart = true;
- _startNode = value;
- }
- }*/
-
///
/// 流程任务管理
///
@@ -385,7 +356,7 @@ namespace Serein.NodeFlow.Env
SereinEnv.WriteLine(InfoType.WARN, $"画布不存在,停止运行。{canvasGuid}");
isBreak = true;
}
- var count = NodeModels.Values.Count(n => n.CanvasGuid.Equals(canvasGuid));
+ var count = NodeModels.Values.Count(n => n.CanvasDetails.Guid.Equals(canvasGuid));
if(count == 0)
{
SereinEnv.WriteLine(InfoType.WARN, $"画布没有节点,停止运行。{canvasGuid}");
@@ -414,7 +385,7 @@ namespace Serein.NodeFlow.Env
return false;
}
var ft = new FlowTask();
- ft.GetNodes = () => NodeModels.Values.Where(node => node.CanvasGuid.Equals(guid)).ToList();
+ ft.GetNodes = () => NodeModels.Values.Where(node => node.CanvasDetails.Guid.Equals(guid)).ToList();
var startNodeModel = NodeModels.GetValueOrDefault(canvasModel.StartNode);
if(startNodeModel is null)
{
@@ -867,7 +838,7 @@ namespace Serein.NodeFlow.Env
var model = new FlowCanvasDetails(this);
model.LoadInfo(info);
FlowCanvass.Add(model.Guid, model);
- UIContextOperation.InvokeAsync(() =>
+ UIContextOperation.Invoke(() =>
{
OnCanvasCreate.Invoke(new CanvasCreateEventArgs(model));
});
@@ -886,7 +857,7 @@ namespace Serein.NodeFlow.Env
{
return false;
}
- var count = NodeModels.Values.Count(node => node.CanvasGuid.Equals(canvasGuid));
+ var count = NodeModels.Values.Count(node => node.CanvasDetails.Guid.Equals(canvasGuid));
if(count > 0)
{
SereinEnv.WriteLine(InfoType.WARN, "无法删除具有节点的画布");
@@ -894,7 +865,7 @@ namespace Serein.NodeFlow.Env
}
if (FlowCanvass.Remove(canvasGuid))
{
- await UIContextOperation.InvokeAsync(() =>
+ UIContextOperation.Invoke(() =>
{
OnCanvasRemove.Invoke(new CanvasRemoveEventArgs(canvasGuid));
});
@@ -942,10 +913,24 @@ namespace Serein.NodeFlow.Env
nodeInfo.Guid = string.Empty;
continue;
}
- nodeModel.LoadInfo(nodeInfo); // 创建节点model
- TryAddNode(nodeModel); // 加载项目时将节点加载到环境中
-
- await UIContextOperation.InvokeAsync(() =>
+ if(FlowCanvass.TryGetValue(nodeInfo.CanvasGuid, out var canvasModel))
+ {
+
+ // 节点与画布互相绑定
+ // 需要在UI线程上进行添加,否则会报 “不支持从调度程序线程以外的线程对其 SourceCollection 进行的更改”异常
+ nodeModel.CanvasDetails = canvasModel;
+ UIContextOperation.Invoke(() => canvasModel.Nodes.Add(nodeModel));
+
+ nodeModel.LoadInfo(nodeInfo); // 创建节点model
+ TryAddNode(nodeModel); // 加载项目时将节点加载到环境中
+ }
+ else
+ {
+ SereinEnv.WriteLine(InfoType.ERROR, $"加载节点[{nodeInfo.Guid}]时发生异常,画布[{nodeInfo.CanvasGuid}]不存在");
+ return;
+ }
+
+ UIContextOperation.Invoke(() =>
OnNodeCreate?.Invoke(new NodeCreateEventArgs(nodeInfo.CanvasGuid, nodeModel, nodeInfo.Position))); // 添加到UI上
}
#endregion
@@ -971,7 +956,7 @@ namespace Serein.NodeFlow.Env
var result = nodeContainer.PlaceNode(nodeModel);
if (result)
{
- await UIContextOperation.InvokeAsync(() => OnNodePlace?.Invoke(
+ UIContextOperation.Invoke(() => OnNodePlace?.Invoke(
new NodePlaceEventArgs(nodeInfo.CanvasGuid, nodeModel.Guid, containerNode.Guid)));
}
@@ -1036,7 +1021,7 @@ namespace Serein.NodeFlow.Env
#region 确定节点之间的参数调用关系
foreach (var toNode in NodeModels.Values)
{
- var canvasGuid = toNode.CanvasGuid;
+ var canvasGuid = toNode.CanvasDetails.Guid;
if (toNode.MethodDetails.ParameterDetailss == null)
{
continue;
@@ -1055,9 +1040,9 @@ namespace Serein.NodeFlow.Env
#endregion
- await UIContextOperation.InvokeAsync(() =>
+ UIContextOperation.Invoke(() =>
{
- UIContextOperation?.Invoke(() => OnProjectLoaded?.Invoke(new ProjectLoadedEventArgs()));
+ OnProjectLoaded?.Invoke(new ProjectLoadedEventArgs());
});
return;
@@ -1075,7 +1060,7 @@ namespace Serein.NodeFlow.Env
PositionOfUI position,
MethodDetailsInfo? methodDetailsInfo = null)
{
- if (!TryGetCanvasModel(canvasGuid,out var cavnasModel))
+ if (!TryGetCanvasModel(canvasGuid,out var canvasModel))
{
return Task.FromResult(null);
}
@@ -1097,9 +1082,9 @@ namespace Serein.NodeFlow.Env
return Task.FromResult(null);
}
}
-
+ nodeModel.CanvasDetails = canvasModel;
+ canvasModel.Nodes.Add(nodeModel); // 节点与画布互相绑定
TryAddNode(nodeModel);
- nodeModel.CanvasGuid = canvasGuid; // 设置所属于的画布
nodeModel.Position = position; // 设置位置
// 通知UI更改
@@ -1107,9 +1092,9 @@ namespace Serein.NodeFlow.Env
// 因为需要UI先布置了元素,才能通知UI变更特效
// 如果不存在流程起始控件,默认设置为流程起始控件
- if (cavnasModel.StartNode is null)
+ if (canvasModel.StartNode is null)
{
- SetStartNode(cavnasModel, nodeModel);
+ SetStartNode(canvasModel, nodeModel);
}
var nodeInfo = nodeModel.ToInfo();
return Task.FromResult(nodeInfo);
@@ -1147,7 +1132,7 @@ namespace Serein.NodeFlow.Env
var result = nodeContainer.PlaceNode(nodeModel); // 放置在容器节点
if (result)
{
- _ = UIContextOperation?.InvokeAsync(() =>
+ UIContextOperation.Invoke(() =>
{
OnNodePlace?.Invoke(new NodePlaceEventArgs(canvasGuid, nodeGuid, containerNodeGuid)); // 通知UI更改节点放置位置
});
@@ -1179,7 +1164,7 @@ namespace Serein.NodeFlow.Env
var result = nodeContainer.TakeOutNode(nodeModel); // 从容器节点取出
if (result)
{
- _ = UIContextOperation?.InvokeAsync(() =>
+ UIContextOperation.Invoke(() =>
{
OnNodeTakeOut?.Invoke(new NodeTakeOutEventArgs(canvasGuid, nodeGuid)); // 重新放置在画布上
});
@@ -1198,7 +1183,7 @@ namespace Serein.NodeFlow.Env
///
public async Task RemoveNodeAsync(string canvasGuid, string nodeGuid)
{
- if (!FlowCanvass.ContainsKey(canvasGuid))
+ if (!TryGetCanvasModel(canvasGuid,out var canvasModel))
{
return false;
}
@@ -1247,10 +1232,12 @@ namespace Serein.NodeFlow.Env
}
}
-
- // 从集合中移除节点
+
+ // 从集合中移除节点,解除与画布的绑定关系
NodeModels.Remove(nodeGuid);
+ UIContextOperation?.Invoke(() => canvasModel.Nodes.Remove(remoteNode));
+
UIContextOperation?.Invoke(() => OnNodeRemove?.Invoke(new NodeRemoveEventArgs(canvasGuid, nodeGuid)));
return true;
}
@@ -1752,7 +1739,7 @@ namespace Serein.NodeFlow.Env
if (OperatingSystem.IsWindows())
{
- await UIContextOperation.InvokeAsync(() => OnNodeConnectChange?.Invoke(
+ UIContextOperation.Invoke(() => OnNodeConnectChange?.Invoke(
new NodeConnectChangeEventArgs(
canvasGuid,
fromNode.Guid,
@@ -1785,7 +1772,7 @@ namespace Serein.NodeFlow.Env
if (OperatingSystem.IsWindows())
{
- await UIContextOperation.InvokeAsync(() => OnNodeConnectChange?.Invoke(
+ UIContextOperation.Invoke(() => OnNodeConnectChange?.Invoke(
new NodeConnectChangeEventArgs(
canvasGuid,
fromNode.Guid,
@@ -1807,6 +1794,7 @@ namespace Serein.NodeFlow.Env
{
nodeModel.Guid ??= Guid.NewGuid().ToString();
NodeModels.TryAdd(nodeModel.Guid, nodeModel);
+
// 如果是触发器,则需要添加到专属集合中
if (nodeModel is SingleFlipflopNode flipflopNode)
@@ -2005,7 +1993,7 @@ namespace Serein.NodeFlow.Env
}
toNode.MethodDetails.ParameterDetailss[argIndex].ArgDataSourceNodeGuid = fromNode.Guid;
toNode.MethodDetails.ParameterDetailss[argIndex].ArgDataSourceType = connectionArgSourceType;
- await UIContextOperation.InvokeAsync(() =>
+ UIContextOperation.Invoke(() =>
OnNodeConnectChange?.Invoke(
new NodeConnectChangeEventArgs(
canvasGuid,
diff --git a/NodeFlow/Env/RemoteFlowEnvironment.cs b/NodeFlow/Env/RemoteFlowEnvironment.cs
index 1e3abee..88ada4d 100644
--- a/NodeFlow/Env/RemoteFlowEnvironment.cs
+++ b/NodeFlow/Env/RemoteFlowEnvironment.cs
@@ -87,6 +87,12 @@ namespace Serein.NodeFlow.Env
public UIContextOperation UIContextOperation { get; }
public NodeMVVMManagement NodeMVVMManagement { get; }
+
+ ///
+ /// 运行环境加载的画布集合
+ ///
+ private Dictionary FlowCanvass { get; } = [];
+
///
/// 标示是否正在加载项目
///
@@ -893,7 +899,11 @@ namespace Serein.NodeFlow.Env
//MethodDetailss.TryGetValue(methodDetailsInfo.MethodName, out var methodDetails);// 加载项目时尝试获取方法信息
var nodeModel = FlowNodeExtension.CreateNode(this, nodeControlType, methodDetails); // 远程环境下加载节点
- nodeModel.LoadInfo(nodeInfo);
+
+ if (FlowCanvass.TryGetValue(nodeInfo.CanvasGuid, out var canvasModel))
+ {
+ }
+ nodeModel.LoadInfo(nodeInfo); // 创建节点model
TryAddNode(nodeModel);
IsLoadingNode = false;
@@ -1214,6 +1224,10 @@ namespace Serein.NodeFlow.Env
nodeInfo.Guid = string.Empty;
continue;
}
+
+ if (FlowCanvass.TryGetValue(nodeInfo.CanvasGuid, out var canvasModel))
+ {
+ }
nodeModel.LoadInfo(nodeInfo); // 创建节点model
TryAddNode(nodeModel); // 加载项目时将节点加载到环境中
@@ -1300,7 +1314,7 @@ namespace Serein.NodeFlow.Env
if (!string.IsNullOrEmpty(pd.ArgDataSourceNodeGuid)
&& NodeModels.TryGetValue(pd.ArgDataSourceNodeGuid, out var fromNode))
{
- var canvasGuid = toNode.CanvasGuid;
+ var canvasGuid = toNode.CanvasDetails.Guid;
UIContextOperation?.Invoke(() =>
OnNodeConnectChange?.Invoke(
new NodeConnectChangeEventArgs(
diff --git a/NodeFlow/FlowWorkManagement.cs b/NodeFlow/FlowWorkManagement.cs
index 53d2f11..fe19718 100644
--- a/NodeFlow/FlowWorkManagement.cs
+++ b/NodeFlow/FlowWorkManagement.cs
@@ -227,7 +227,7 @@ namespace Serein.NodeFlow
{
var env = WorkOptions.Environment;
var flipflopNodes = flow.GetNodes().Where(item => item is SingleFlipflopNode node
- && !node.IsStart
+
&& node.DebugSetting.IsEnable
&& node.NotExitPreviousNode())
.Select(item => (SingleFlipflopNode)item);
diff --git a/NodeFlow/Model/SingleFlowCallNode.cs b/NodeFlow/Model/SingleFlowCallNode.cs
new file mode 100644
index 0000000..36f0cf6
--- /dev/null
+++ b/NodeFlow/Model/SingleFlowCallNode.cs
@@ -0,0 +1,33 @@
+using Serein.Library;
+using Serein.Library.Api;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Serein.NodeFlow.Model
+{
+ ///
+ /// 流程调用节点
+ ///
+ public class SingleFlowCallNode : NodeModelBase
+ {
+ public SingleFlowCallNode(IFlowEnvironment environment) : base(environment)
+ {
+
+ }
+
+ ///
+ /// 需要调用其它流程图中的某个节点
+ ///
+ ///
+ ///
+ ///
+ public override async Task ExecutingAsync(IDynamicContext context, CancellationToken token)
+ {
+ await base.ExecutingAsync(context, token);
+ return new FlowResult(this, context, null);
+ }
+ }
+}
\ No newline at end of file
diff --git a/NodeFlow/Model/SingleGlobalDataNode.cs b/NodeFlow/Model/SingleGlobalDataNode.cs
index be3a5ba..4ba93de 100644
--- a/NodeFlow/Model/SingleGlobalDataNode.cs
+++ b/NodeFlow/Model/SingleGlobalDataNode.cs
@@ -96,7 +96,7 @@ namespace Serein.NodeFlow.Model
{
foreach (var nodeModel in ChildrenNode)
{
- await nodeModel.Env.TakeOutNodeToContainerAsync(nodeModel.CanvasGuid, nodeModel.Guid);
+ await nodeModel.Env.TakeOutNodeToContainerAsync(nodeModel.CanvasDetails.Guid, nodeModel.Guid);
}
DataNode = null;
}
@@ -178,7 +178,7 @@ namespace Serein.NodeFlow.Model
return;
}
// 移除数据节点
- _ = this.Env.RemoveNodeAsync(DataNode.CanvasGuid, DataNode.Guid);
+ _ = this.Env.RemoveNodeAsync(DataNode.CanvasDetails.Guid, DataNode.Guid);
}
}
diff --git a/Serein.Library.MyGenerator/Attribute.cs b/Serein.Library.MyGenerator/Attribute.cs
index ba8c22a..13c260e 100644
--- a/Serein.Library.MyGenerator/Attribute.cs
+++ b/Serein.Library.MyGenerator/Attribute.cs
@@ -56,7 +56,7 @@ namespace Serein.Library
public sealed class PropertyInfoAttribute : Attribute
{
///
- /// 是否通知UI
+ /// 是否通知远程环境(如果在远程环境下)
///
public bool IsNotification = false;
diff --git a/Workbench/App.xaml.cs b/Workbench/App.xaml.cs
index b6b9831..4bbcf63 100644
--- a/Workbench/App.xaml.cs
+++ b/Workbench/App.xaml.cs
@@ -34,6 +34,7 @@ namespace Serein.Workbench
collection.AddSingleton();
collection.AddTransient(); // 画布
+ collection.AddTransient(); // 画布节点树视图
}
public static void AddWorkbenchServices(this IServiceCollection collection)
diff --git a/Workbench/Models/TabModel.cs b/Workbench/Models/TabModel.cs
index c1fad2b..6197c24 100644
--- a/Workbench/Models/TabModel.cs
+++ b/Workbench/Models/TabModel.cs
@@ -1,5 +1,6 @@
using CommunityToolkit.Mvvm.ComponentModel;
using Newtonsoft.Json.Linq;
+using Serein.Library;
using Serein.Workbench.ViewModels;
using Serein.Workbench.Views;
using System;
@@ -19,7 +20,7 @@ namespace Serein.Workbench.Models
///
/// tab 名称
///
- public string Name
+ /* public string Name
{
get
{
@@ -34,6 +35,10 @@ namespace Serein.Workbench.Models
OnPropertyChanged(nameof(Name));
}
}
+*/
+
+ [ObservableProperty]
+ private FlowCanvasDetails _model;
///
diff --git a/Workbench/Node/View/ActionNodeControl.xaml b/Workbench/Node/View/ActionNodeControl.xaml
index 9b4d134..12b4954 100644
--- a/Workbench/Node/View/ActionNodeControl.xaml
+++ b/Workbench/Node/View/ActionNodeControl.xaml
@@ -91,7 +91,13 @@
-
+
+
+
+
+
+
+
@@ -107,6 +113,8 @@
+
+
diff --git a/Workbench/Node/View/ConnectionControl.cs b/Workbench/Node/View/ConnectionControl.cs
index 07080b9..5eacfb9 100644
--- a/Workbench/Node/View/ConnectionControl.cs
+++ b/Workbench/Node/View/ConnectionControl.cs
@@ -238,7 +238,7 @@ namespace Serein.Workbench.Node.View
{
Canvas.Children.Remove(BezierLine);
var env = Start.MyNode.Env;
- var canvasGuid = Start.MyNode.CanvasGuid;
+ var canvasGuid = Start.MyNode.CanvasDetails.Guid;
if (Start.JunctionType.ToConnectyionType() == JunctionOfConnectionType.Invoke)
{
env.RemoveConnectInvokeAsync(canvasGuid, Start.MyNode.Guid, End.MyNode.Guid, InvokeType);
diff --git a/Workbench/Node/View/FlowCallNodeControl.xaml b/Workbench/Node/View/FlowCallNodeControl.xaml
new file mode 100644
index 0000000..b5eccaf
--- /dev/null
+++ b/Workbench/Node/View/FlowCallNodeControl.xaml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
diff --git a/Workbench/Node/View/FlowCallNodeControl.xaml.cs b/Workbench/Node/View/FlowCallNodeControl.xaml.cs
new file mode 100644
index 0000000..3eb41de
--- /dev/null
+++ b/Workbench/Node/View/FlowCallNodeControl.xaml.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+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.Node.View
+{
+ ///
+ /// FlowCallNodeControl.xaml 的交互逻辑
+ ///
+ public partial class FlowCallNodeControl : NodeControlBase, INodeJunction
+ {
+ public FlowCallNodeControl()
+ {
+ InitializeComponent();
+ }
+
+ public JunctionControlBase ExecuteJunction => throw new NotImplementedException();
+
+ public JunctionControlBase NextStepJunction => throw new NotImplementedException();
+
+ public JunctionControlBase[] ArgDataJunction => throw new NotImplementedException();
+
+ public JunctionControlBase ReturnDataJunction => throw new NotImplementedException();
+ }
+}
diff --git a/Workbench/Node/ViewModel/FlowCallNodeControlViewModel.cs b/Workbench/Node/ViewModel/FlowCallNodeControlViewModel.cs
new file mode 100644
index 0000000..4171b87
--- /dev/null
+++ b/Workbench/Node/ViewModel/FlowCallNodeControlViewModel.cs
@@ -0,0 +1,18 @@
+using Serein.NodeFlow.Model;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Serein.Workbench.Node.ViewModel
+{
+ public partial class FlowCallNodeControlViewModel : NodeControlViewModelBase
+ {
+ public new SingleFlowCallNode NodelModel { get; }
+ public FlowCallNodeControlViewModel(SingleFlowCallNode node) : base(node)
+ {
+ this.NodelModel = node;
+ }
+ }
+}
diff --git a/Workbench/Serein.WorkBench.csproj b/Workbench/Serein.WorkBench.csproj
index 1ce1737..0561aaf 100644
--- a/Workbench/Serein.WorkBench.csproj
+++ b/Workbench/Serein.WorkBench.csproj
@@ -31,6 +31,8 @@
+
+
@@ -43,6 +45,8 @@
+
+
diff --git a/Workbench/Services/FlowNodeService.cs b/Workbench/Services/FlowNodeService.cs
index 5d837e3..0476c55 100644
--- a/Workbench/Services/FlowNodeService.cs
+++ b/Workbench/Services/FlowNodeService.cs
@@ -36,14 +36,31 @@ namespace Serein.Workbench.Services
/// 添加了节点
///
public Action OnCreateNode { get; set; }
-
+
+ ///
+ /// 查看的画布发生改变
+ ///
+ public Action OnViewCanvasChanged{ get; set; }
+
#endregion
#region 创建节点相关的属性
+
+
+ private FlowCanvasView currentSelectCanvas;
///
/// 当前查看的画布
///
- public FlowCanvasView CurrentSelectCanvas { get; set; }
+ public FlowCanvasView CurrentSelectCanvas { get => currentSelectCanvas; set
+ {
+ if (value == null || value.Equals(currentSelectCanvas))
+ {
+ return;
+ }
+ currentSelectCanvas = value;
+ OnViewCanvasChanged?.Invoke(value);
+ }
+ }
///
/// 当前拖动的方法信息
@@ -128,7 +145,7 @@ namespace Serein.Workbench.Services
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.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));
@@ -648,7 +665,7 @@ namespace Serein.Workbench.Services
return;
}
- _ = flowEnvironment.RemoveNodeAsync(model.CanvasGuid, model.Guid);
+ _ = flowEnvironment.RemoveNodeAsync(model.CanvasDetails.Guid, model.Guid);
}
#endregion
diff --git a/Workbench/Services/KeyEventService.cs b/Workbench/Services/KeyEventService.cs
index 88c6ec2..865f6f6 100644
--- a/Workbench/Services/KeyEventService.cs
+++ b/Workbench/Services/KeyEventService.cs
@@ -78,14 +78,14 @@ namespace Serein.Workbench.Services
{
KeysState[(int)key] = true;
OnKeyDown?.Invoke(key);
- Debug.WriteLine($"按键按下事件:{key}");
+ //Debug.WriteLine($"按键按下事件:{key}");
}
public void KeyUp(Key key)
{
KeysState[(int)key] = false;
OnKeyUp?.Invoke(key);
- Debug.WriteLine($"按键抬起事件:{key}");
+ //Debug.WriteLine($"按键抬起事件:{key}");
}
}
diff --git a/Workbench/ViewModels/CanvasNodeTreeViewModel.cs b/Workbench/ViewModels/CanvasNodeTreeViewModel.cs
new file mode 100644
index 0000000..26186a1
--- /dev/null
+++ b/Workbench/ViewModels/CanvasNodeTreeViewModel.cs
@@ -0,0 +1,41 @@
+using CommunityToolkit.Mvvm.ComponentModel;
+using Serein.Library;
+using Serein.Workbench.Services;
+using Serein.Workbench.Views;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Serein.Workbench.ViewModels
+{
+ internal partial class CanvasInfoViewModel : ObservableObject
+ {
+ private readonly FlowNodeService flowNodeService;
+
+ ///
+ /// 画布数据实体
+ ///
+ [ObservableProperty]
+ private FlowCanvasDetails _model;
+
+ public CanvasInfoViewModel(FlowNodeService flowNodeService)
+ {
+ this.flowNodeService = flowNodeService;
+ this.flowNodeService.OnViewCanvasChanged += OnViewCanvasChanged;
+ }
+
+ ///
+ /// 查看的画布发生改变
+ ///
+ ///
+ private void OnViewCanvasChanged(FlowCanvasView flowCanvas)
+ {
+ if (flowCanvas.DataContext is FlowCanvasViewModel vm)
+ {
+ Model = vm.Model;
+ }
+ }
+ }
+}
diff --git a/Workbench/ViewModels/FlowEditViewModel.cs b/Workbench/ViewModels/FlowEditViewModel.cs
index 45a4d33..f993307 100644
--- a/Workbench/ViewModels/FlowEditViewModel.cs
+++ b/Workbench/ViewModels/FlowEditViewModel.cs
@@ -22,8 +22,11 @@ namespace Serein.Workbench.ViewModels
///
public partial class FlowEditViewModel : ObservableObject
{
- public ObservableCollection CanvasTabs { get; set; } = [];
-
+ ///
+ /// 画布集合
+ ///
+ [ObservableProperty]
+ private ObservableCollection _canvasTabs = [];
///
/// 当前选择的画布
@@ -42,11 +45,8 @@ namespace Serein.Workbench.ViewModels
flowNodeService.OnRemoveFlowCanvasView += OnRemoveFlowCanvasView; // 移除了画布
this.PropertyChanged += OnPropertyChanged;
-
}
-
-
private void OnPropertyChanged(object? value, PropertyChangedEventArgs e)
{
if (this.SelectedTab is null) return;
@@ -56,9 +56,13 @@ namespace Serein.Workbench.ViewModels
#region 响应环境事件
private void OnCreateFlowCanvasView(FlowCanvasView canvas)
{
- var model = new FlowEditorTabModel(canvas);
- CanvasTabs.Add(model);
- SelectedTab = model;
+ var tab = new FlowEditorTabModel(canvas);
+ if(canvas is IFlowCanvas flowCanvas)
+ {
+ tab.Model = flowCanvas.Model;
+ }
+ CanvasTabs.Add(tab);
+ SelectedTab = tab;
}
private void OnRemoveFlowCanvasView(FlowCanvasView canvas)
{
@@ -102,7 +106,7 @@ namespace Serein.Workbench.ViewModels
if (tab != null)
{
tab.IsEditing = false;
- if(tab.Name != newName && !string.IsNullOrWhiteSpace(newName)) tab.Name = newName; // 名称合法时设置新名称
+ if(tab.Model.Name != newName && !string.IsNullOrWhiteSpace(newName)) tab.Model.Name = newName; // 名称合法时设置新名称
OnPropertyChanged(nameof(CanvasTabs)); // 刷新Tabs集合
}
}
diff --git a/Workbench/ViewModels/Locator.cs b/Workbench/ViewModels/Locator.cs
index eae5f75..322d6f1 100644
--- a/Workbench/ViewModels/Locator.cs
+++ b/Workbench/ViewModels/Locator.cs
@@ -15,25 +15,18 @@ namespace Serein.Workbench.ViewModels
ServiceProvider = serviceProvider;
}
- //private IServiceProvider GetService()
- //{
- // var service = new ServiceCollection();
- // service.AddSingleton();
- // service.AddSingleton();
- // service.AddSingleton();
- // service.AddSingleton();
- // service.AddSingleton();
- // service.AddTransient();
- // return service.BuildServiceProvider();
- //}
-
+
public MainViewModel MainViewModel => App.GetService() ?? throw new NotImplementedException();
public MainMenuBarViewModel MainMenuBarViewModel => App.GetService() ?? throw new NotImplementedException();
public FlowWorkbenchViewModel FlowWorkbenchViewModel => App.GetService() ?? throw new NotImplementedException();
public BaseNodesViewModel BaseNodesViewModel => App.GetService() ?? throw new NotImplementedException();
public FlowLibrarysViewModel FlowLibrarysViewModel => App.GetService() ?? throw new NotImplementedException();
public FlowEditViewModel FlowEditViewModel => App.GetService() ?? throw new NotImplementedException();
+
+
+
public FlowCanvasViewModel FlowCanvasViewModel => App.GetService() ?? throw new NotImplementedException();
+ public CanvasInfoViewModel CanvasNodeTreeViewModel => App.GetService() ?? throw new NotImplementedException();
public IServiceProvider ServiceProvider { get; }
}
diff --git a/Workbench/Views/CanvasInfoView.xaml b/Workbench/Views/CanvasInfoView.xaml
new file mode 100644
index 0000000..7b515e4
--- /dev/null
+++ b/Workbench/Views/CanvasInfoView.xaml
@@ -0,0 +1,96 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Workbench/Views/CanvasInfoView.xaml.cs b/Workbench/Views/CanvasInfoView.xaml.cs
new file mode 100644
index 0000000..3bf02f0
--- /dev/null
+++ b/Workbench/Views/CanvasInfoView.xaml.cs
@@ -0,0 +1,32 @@
+using Serein.Workbench.ViewModels;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+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.Views
+{
+ ///
+ /// CanvasNodeTreeView.xaml 的交互逻辑
+ ///
+ public partial class CanvasInfoView : UserControl
+ {
+ private readonly CanvasInfoViewModel ViewModel;
+ public CanvasInfoView()
+ {
+ this.ViewModel = App.GetService();
+ this.DataContext = this.ViewModel;
+ InitializeComponent();
+ }
+ }
+}
diff --git a/Workbench/Views/FlowCanvasView.xaml.cs b/Workbench/Views/FlowCanvasView.xaml.cs
index 06b6871..2d24c00 100644
--- a/Workbench/Views/FlowCanvasView.xaml.cs
+++ b/Workbench/Views/FlowCanvasView.xaml.cs
@@ -374,14 +374,14 @@ namespace Serein.Workbench.Views
// 准备放置条件表达式控件
if (nodeControl.ViewModel.NodeModel.ControlType == NodeControlType.ExpCondition)
{
- ConditionRegionControl? conditionRegion = WpfFuncTool.GetParentOfType(hitElement);
+ /* ConditionRegionControl? conditionRegion = WpfFuncTool.GetParentOfType(hitElement);
if (conditionRegion is not null)
{
targetNodeControl = conditionRegion;
//// 如果存在条件区域容器
//conditionRegion.AddCondition(nodeControl);
return true;
- }
+ }*/
}
else
@@ -408,13 +408,24 @@ namespace Serein.Workbench.Views
///
private void KeyEventService_OnKeyDown(Key key)
{
- if (!flowNodeService.CurrentSelectCanvas.Guid.Equals(Guid))
+
+ if (flowNodeService.CurrentSelectCanvas is null || !flowNodeService.CurrentSelectCanvas.Guid.Equals(Guid))
{
return;
}
+
+
+ if (key == Key.F5)
+ {
+ // F5 调试当前流程
+ _ = flowEnvironment.StartFlowAsync([Guid]);
+ }
+
+
if (key == Key.Escape)
{
+ // 退出连线、选取状态
IsControlDragging = false;
IsCanvasDragging = false;
SelectionRectangle.Visibility = Visibility.Collapsed;
@@ -427,16 +438,33 @@ namespace Serein.Workbench.Views
if (selectNodeControls.Count > 0 && key == Key.C && (keyEventService.GetKeyState(Key.LeftCtrl) || keyEventService.GetKeyState(Key.RightCtrl)))
{
var text = flowNodeService.CpoyNodeInfo([.. selectNodeControls.Select(c => c.ViewModel.NodeModel)]);
- Clipboard.SetDataObject(text, true); // 复制,持久性设置
- return;
+ //Clipboard.SetText(text); // 复制,持久性设置
+ try
+ {
+ Clipboard.SetDataObject(text, true); // 复制,持久性设置
+ }
+ catch
+ {
+ Clipboard.SetText(text);
+ return;
+ }
}
-
+
// 粘贴节点
if (key == Key.V && (keyEventService.GetKeyState(Key.LeftCtrl) || keyEventService.GetKeyState(Key.RightCtrl)))
{
string clipboardText = Clipboard.GetText(TextDataFormat.Text); // 获取复制的文本
- var jobject = JObject.Parse(clipboardText);
- var nodesText = jobject["nodes"]?.ToString();
+ string nodesText = "";
+ try
+ {
+ var jobject = JObject.Parse(clipboardText);
+ nodesText = jobject["nodes"]?.ToString();
+ }
+ catch (Exception ex)
+ {
+ return;
+ }
+
if (!string.IsNullOrWhiteSpace(nodesText))
{
@@ -596,7 +624,7 @@ namespace Serein.Workbench.Views
{
NodeControlType nodeControlType = droppedType switch
{
- Type when typeof(ConditionRegionControl).IsAssignableFrom(droppedType) => NodeControlType.ConditionRegion, // 条件区域
+ //Type when typeof(ConditionRegionControl).IsAssignableFrom(droppedType) => NodeControlType.ConditionRegion, // 条件区域
Type when typeof(ConditionNodeControl).IsAssignableFrom(droppedType) => NodeControlType.ExpCondition,
Type when typeof(ExpOpNodeControl).IsAssignableFrom(droppedType) => NodeControlType.ExpOp,
Type when typeof(GlobalDataControl).IsAssignableFrom(droppedType) => NodeControlType.GlobalData,
diff --git a/Workbench/Views/FlowEditView.xaml b/Workbench/Views/FlowEditView.xaml
index ea1d1d0..f208415 100644
--- a/Workbench/Views/FlowEditView.xaml
+++ b/Workbench/Views/FlowEditView.xaml
@@ -4,11 +4,11 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Serein.Workbench.Views"
+ xmlns:converters="clr-namespace:Serein.Workbench.Tool.Converters"
xmlns:vm="clr-namespace:Serein.Workbench.ViewModels"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:DesignInstance vm:FlowEditViewModel}"
- xmlns:converters="clr-namespace:Serein.Workbench.Tool.Converters"
Background="#E7F0F6">
@@ -17,19 +17,20 @@
-
-
@@ -37,10 +38,7 @@
-
-
-
-
+
diff --git a/Workbench/Views/FlowWorkbenchView.xaml b/Workbench/Views/FlowWorkbenchView.xaml
index 75fde79..24ed111 100644
--- a/Workbench/Views/FlowWorkbenchView.xaml
+++ b/Workbench/Views/FlowWorkbenchView.xaml
@@ -39,6 +39,8 @@
-
+
+
+