重写脚本解释器的实现,提高其可读性。

This commit is contained in:
fengjiayi
2025-07-13 17:34:03 +08:00
parent 6141d2c1c1
commit 01ab905155
42 changed files with 1747 additions and 715 deletions

View File

@@ -292,7 +292,7 @@ namespace Serein.Library
/// 从DLL拖动出来时从元数据拷贝新的实例作为属于节点独享的方法描述 /// 从DLL拖动出来时从元数据拷贝新的实例作为属于节点独享的方法描述
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public MethodDetails CloneOfNode( IFlowNode nodeModel) public MethodDetails CloneOfNode(IFlowNode nodeModel)
{ {
// this => 是元数据 // this => 是元数据
var md = new MethodDetails(nodeModel) // 创建新节点时拷贝实例 var md = new MethodDetails(nodeModel) // 创建新节点时拷贝实例

View File

@@ -48,11 +48,7 @@ namespace Serein.NodeFlow.Env
/// </summary> /// </summary>
private RunState FlipFlopState = RunState.NoStart; private RunState FlipFlopState = RunState.NoStart;
/// <inheritdoc/>
/// <summary>
/// 异步运行
/// </summary>
/// <returns></returns>
public async Task<bool> StartFlowAsync(string[] canvasGuids) public async Task<bool> StartFlowAsync(string[] canvasGuids)
{ {
#region #region
@@ -144,12 +140,7 @@ namespace Serein.NodeFlow.Env
return true; return true;
} }
/// <inheritdoc/>
/// <summary>
/// 从选定节点开始运行
/// </summary>
/// <param name="startNodeGuid"></param>
/// <returns></returns>
public async Task<TResult> StartFlowAsync<TResult>(string startNodeGuid) public async Task<TResult> StartFlowAsync<TResult>(string startNodeGuid)
{ {
@@ -207,10 +198,7 @@ namespace Serein.NodeFlow.Env
} }
return result; return result;
}*/ }*/
/// <inheritdoc/>
/// <summary>
/// 结束流程
/// </summary>
public Task<bool> ExitFlowAsync() public Task<bool> ExitFlowAsync()
{ {
flowWorkManagement?.Exit(); flowWorkManagement?.Exit();
@@ -220,11 +208,7 @@ namespace Serein.NodeFlow.Env
GC.Collect(); GC.Collect();
return Task.FromResult(true); return Task.FromResult(true);
} }
/// <inheritdoc/>
/// <summary>
/// 激活全局触发器
/// </summary>
/// <param name="nodeGuid"></param>
public void ActivateFlipflopNode(string nodeGuid) public void ActivateFlipflopNode(string nodeGuid)
{ {
/*if (!TryGetNodeModel(nodeGuid, out var nodeModel)) /*if (!TryGetNodeModel(nodeGuid, out var nodeModel))
@@ -242,11 +226,7 @@ namespace Serein.NodeFlow.Env
} }
}*/ }*/
} }
/// <inheritdoc/>
/// <summary>
/// 关闭全局触发器
/// </summary>
/// <param name="nodeGuid"></param>
public void TerminateFlipflopNode(string nodeGuid) public void TerminateFlipflopNode(string nodeGuid)
{ {
/* if (!TryGetNodeModel(nodeGuid, out var nodeModel)) /* if (!TryGetNodeModel(nodeGuid, out var nodeModel))
@@ -264,24 +244,12 @@ namespace Serein.NodeFlow.Env
{ {
this.sereinIOC = ioc; // 设置IOC容器 this.sereinIOC = ioc; // 设置IOC容器
} }
/// <inheritdoc/>
/// <summary>
/// 启动器调用,运行到某个节点时触发了监视对象的更新(对象预览视图将会自动更新)
/// </summary>
/// <param name="nodeGuid"></param>
/// <param name="monitorData"></param>
/// <param name="sourceType"></param>
public void MonitorObjectNotification(string nodeGuid, object monitorData, MonitorObjectEventArgs.ObjSourceType sourceType) public void MonitorObjectNotification(string nodeGuid, object monitorData, MonitorObjectEventArgs.ObjSourceType sourceType)
{ {
flowEnvironmentEvent.OnMonitorObjectChanged(new MonitorObjectEventArgs(nodeGuid, monitorData, sourceType)); flowEnvironmentEvent.OnMonitorObjectChanged(new MonitorObjectEventArgs(nodeGuid, monitorData, sourceType));
} }
/// <inheritdoc/>
/// <summary>
/// 启动器调用,节点触发了中断。
/// </summary>
/// <param name="nodeGuid">节点</param>
/// <param name="expression">表达式</param>
/// <param name="type">类型0用户主动的中断1表达式中断</param>
public void TriggerInterrupt(string nodeGuid, string expression, InterruptTriggerEventArgs.InterruptTriggerType type) public void TriggerInterrupt(string nodeGuid, string expression, InterruptTriggerEventArgs.InterruptTriggerType type)
{ {
flowEnvironmentEvent.OnInterruptTriggered(new InterruptTriggerEventArgs(nodeGuid, expression, type)); flowEnvironmentEvent.OnInterruptTriggered(new InterruptTriggerEventArgs(nodeGuid, expression, type));
@@ -292,28 +260,14 @@ namespace Serein.NodeFlow.Env
#region #region
/// <inheritdoc/>
/// <summary>
/// 调用流程接口,将返回 FlowResult.Value。如果需要 FlowResult 对象,请使用该方法的泛型版本。
/// </summary>
/// <param name="apiGuid">流程接口节点Guid</param>
/// <param name="dict">调用时入参参数</param>
/// <returns></returns>
public async Task<object> InvokeAsync(string apiGuid, Dictionary<string, object> dict) public async Task<object> InvokeAsync(string apiGuid, Dictionary<string, object> dict)
{ {
var result = await InvokeAsync<object>(apiGuid, dict); var result = await InvokeAsync<object>(apiGuid, dict);
return result; return result;
} }
/// <inheritdoc/>
/// <summary>
/// 调用流程接口,泛型类型为 FlowResult 时,将返回 FlowResult 对象。
/// </summary>
/// <typeparam name="TResult"></typeparam>
/// <param name="apiGuid">流程接口节点Guid</param>
/// <param name="dict">调用时入参参数</param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
public async Task<TResult> InvokeAsync<TResult>(string apiGuid, Dictionary<string, object> dict) public async Task<TResult> InvokeAsync<TResult>(string apiGuid, Dictionary<string, object> dict)
{ {
if (sereinIOC is null) if (sereinIOC is null)

View File

@@ -201,7 +201,7 @@ namespace Serein.NodeFlow.Env
private int _add_canvas_count = 1; private int _add_canvas_count = 1;
/// <inheritdoc/>
public void CreateCanvas(string canvasName, int width, int height) public void CreateCanvas(string canvasName, int width, int height)
{ {
IOperation operation = new CreateCanvasOperation IOperation operation = new CreateCanvasOperation
@@ -219,7 +219,7 @@ namespace Serein.NodeFlow.Env
flowOperationService.Execute(operation); flowOperationService.Execute(operation);
} }
/// <inheritdoc/>
public void RemoveCanvas(string canvasGuid) public void RemoveCanvas(string canvasGuid)
{ {
IOperation operation = new RemoveCanvasOperation IOperation operation = new RemoveCanvasOperation
@@ -228,7 +228,7 @@ namespace Serein.NodeFlow.Env
}; };
flowOperationService.Execute(operation); flowOperationService.Execute(operation);
} }
/// <inheritdoc/>
public void ConnectInvokeNode(string canvasGuid, string fromNodeGuid, string toNodeGuid, JunctionType fromNodeJunctionType, JunctionType toNodeJunctionType, ConnectionInvokeType invokeType) public void ConnectInvokeNode(string canvasGuid, string fromNodeGuid, string toNodeGuid, JunctionType fromNodeJunctionType, JunctionType toNodeJunctionType, ConnectionInvokeType invokeType)
{ {
IOperation operation = new ChangeNodeConnectionOperation IOperation operation = new ChangeNodeConnectionOperation
@@ -245,7 +245,7 @@ namespace Serein.NodeFlow.Env
flowOperationService.Execute(operation); flowOperationService.Execute(operation);
} }
/// <inheritdoc/>
public void ConnectArgSourceNode(string canvasGuid, string fromNodeGuid, string toNodeGuid, JunctionType fromNodeJunctionType, JunctionType toNodeJunctionType, ConnectionArgSourceType argSourceType, int argIndex) public void ConnectArgSourceNode(string canvasGuid, string fromNodeGuid, string toNodeGuid, JunctionType fromNodeJunctionType, JunctionType toNodeJunctionType, ConnectionArgSourceType argSourceType, int argIndex)
{ {
IOperation operation = new ChangeNodeConnectionOperation IOperation operation = new ChangeNodeConnectionOperation
@@ -262,7 +262,7 @@ namespace Serein.NodeFlow.Env
}; };
flowOperationService.Execute(operation); flowOperationService.Execute(operation);
} }
/// <inheritdoc/>
public void RemoveInvokeConnect(string canvasGuid, string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType) public void RemoveInvokeConnect(string canvasGuid, string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType)
{ {
IOperation operation = new ChangeNodeConnectionOperation IOperation operation = new ChangeNodeConnectionOperation
@@ -276,7 +276,7 @@ namespace Serein.NodeFlow.Env
}; };
flowOperationService.Execute(operation); flowOperationService.Execute(operation);
} }
/// <inheritdoc/>
public void RemoveArgSourceConnect(string canvasGuid, string fromNodeGuid, string toNodeGuid, int argIndex) public void RemoveArgSourceConnect(string canvasGuid, string fromNodeGuid, string toNodeGuid, int argIndex)
{ {
IOperation operation = new ChangeNodeConnectionOperation IOperation operation = new ChangeNodeConnectionOperation
@@ -290,7 +290,7 @@ namespace Serein.NodeFlow.Env
}; };
flowOperationService.Execute(operation); flowOperationService.Execute(operation);
} }
/// <inheritdoc/>
public void CreateNode(string canvasGuid, NodeControlType nodeType, PositionOfUI position, MethodDetailsInfo methodDetailsInfo = null) public void CreateNode(string canvasGuid, NodeControlType nodeType, PositionOfUI position, MethodDetailsInfo methodDetailsInfo = null)
{ {
IOperation operation = new CreateNodeOperation IOperation operation = new CreateNodeOperation
@@ -302,7 +302,7 @@ namespace Serein.NodeFlow.Env
}; };
flowOperationService.Execute(operation); flowOperationService.Execute(operation);
} }
/// <inheritdoc/>
public void RemoveNode(string canvasGuid, string nodeGuid) public void RemoveNode(string canvasGuid, string nodeGuid)
{ {
IOperation operation = new RemoveNodeOperation IOperation operation = new RemoveNodeOperation
@@ -312,7 +312,7 @@ namespace Serein.NodeFlow.Env
}; };
flowOperationService.Execute(operation); flowOperationService.Execute(operation);
} }
/// <inheritdoc/>
public void PlaceNodeToContainer(string canvasGuid, string nodeGuid, string containerNodeGuid) public void PlaceNodeToContainer(string canvasGuid, string nodeGuid, string containerNodeGuid)
{ {
IOperation operation = new ContainerPlaceNodeOperation IOperation operation = new ContainerPlaceNodeOperation
@@ -323,7 +323,7 @@ namespace Serein.NodeFlow.Env
}; };
flowOperationService.Execute(operation); flowOperationService.Execute(operation);
} }
/// <inheritdoc/>
public void TakeOutNodeToContainer(string canvasGuid, string nodeGuid) public void TakeOutNodeToContainer(string canvasGuid, string nodeGuid)
{ {
IOperation operation = new ContainerTakeOutNodeOperation IOperation operation = new ContainerTakeOutNodeOperation
@@ -333,7 +333,7 @@ namespace Serein.NodeFlow.Env
}; };
flowOperationService.Execute(operation); flowOperationService.Execute(operation);
} }
/// <inheritdoc/>
public void SetStartNode(string canvasGuid, string nodeGuid) public void SetStartNode(string canvasGuid, string nodeGuid)
{ {
@@ -363,7 +363,7 @@ namespace Serein.NodeFlow.Env
)); ));
return; return;
} }
/// <inheritdoc/>
public void SetConnectPriorityInvoke(string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType) public void SetConnectPriorityInvoke(string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType)
{ {
@@ -377,7 +377,7 @@ namespace Serein.NodeFlow.Env
}; };
flowOperationService.Execute(operation); flowOperationService.Execute(operation);
} }
/// <inheritdoc/>
public void ChangeParameter(string nodeGuid, bool isAdd, int paramIndex) public void ChangeParameter(string nodeGuid, bool isAdd, int paramIndex)
{ {
IOperation operation = new ChangeParameterOperation IOperation operation = new ChangeParameterOperation
@@ -389,12 +389,7 @@ namespace Serein.NodeFlow.Env
flowOperationService.Execute(operation); flowOperationService.Execute(operation);
} }
/// <summary> /// <inheritdoc/>
/// 从节点信息集合批量加载节点控件
/// </summary>
/// <param name="List<NodeInfo>">节点信息</param>
/// <returns></returns>
///
public async Task LoadNodeInfosAsync(List<NodeInfo> nodeInfos) public async Task LoadNodeInfosAsync(List<NodeInfo> nodeInfos)
{ {
#region NodeInfo创建NodeModel #region NodeInfo创建NodeModel
@@ -635,11 +630,7 @@ namespace Serein.NodeFlow.Env
#region #region
/// <inheritdoc/>
/// <summary>
/// 定位节点
/// </summary>
/// <param name="nodeGuid"></param>
public void NodeLocate(string nodeGuid) public void NodeLocate(string nodeGuid)
{ {
if (OperatingSystem.IsWindows()) if (OperatingSystem.IsWindows())

View File

@@ -85,43 +85,47 @@ namespace Serein.NodeFlow.Model
TargetNodeGuid = nodeGuid; TargetNodeGuid = nodeGuid;
} }
/// <summary>
/// 目标节点发生改变
/// </summary>
/// <param name="value"></param>
partial void OnTargetNodeGuidChanged(string value) partial void OnTargetNodeGuidChanged(string value)
{ {
if (string.IsNullOrEmpty(value) || !Env.TryGetNodeModel(value, out var targetNode)) if (string.IsNullOrEmpty(value) || !Env.TryGetNodeModel(value, out var targetNode))
{ {
// 取消设置接口节点 // 取消设置接口节点
TargetNode.PropertyChanged -= TargetNode_PropertyChanged; TargetNode.PropertyChanged -= TargetNode_PropertyChanged; // 不再监听目标属通知
TargetNode = null; TargetNode = null;
this.ApiGlobalName = ""; this.ApiGlobalName = "";
this.MethodDetails = new MethodDetails(); this.MethodDetails = new MethodDetails();
} }
else else
{ {
//if (this.MethodDetails.ActingInstanceType.FullName.Equals())
TargetNode = targetNode; TargetNode = targetNode;
if (!this.IsShareParam if (!this.IsShareParam // 不共享参数
&& CacheMethodDetails is not null && TargetNode.MethodDetails is not null // 目标节点有方法描述
&& TargetNode.MethodDetails is not null && CacheMethodDetails is not null // 存在缓存
&& TargetNode.MethodDetails.AssemblyName == CacheMethodDetails.AssemblyName && TargetNode.MethodDetails.AssemblyName == CacheMethodDetails.AssemblyName // 与缓存中一致
&& TargetNode.MethodDetails.MethodName == CacheMethodDetails.MethodName) && TargetNode.MethodDetails.MethodName == CacheMethodDetails.MethodName) // 与缓存中一致
{ {
this.MethodDetails = CacheMethodDetails; this.MethodDetails = CacheMethodDetails; // 直接使用缓存
this.ApiGlobalName = GetApiInvokeName(this); this.ApiGlobalName = GetApiInvokeName(this); // 生成新的接口名称
} }
else else
{ {
if (TargetNode.MethodDetails is not null) if (TargetNode.MethodDetails is not null) // // 目标节点有方法描述
{ {
CacheMethodDetails = TargetNode.MethodDetails.CloneOfNode(this); // 从目标节点复制一份 CacheMethodDetails = TargetNode.MethodDetails.CloneOfNode(this); // 从目标节点复制一份到缓存中
TargetNode.PropertyChanged += TargetNode_PropertyChanged; TargetNode.PropertyChanged += TargetNode_PropertyChanged; // 监听目标属性通知“IsPublic”属性
this.MethodDetails = CacheMethodDetails; this.MethodDetails = CacheMethodDetails; // 设置流程接口节点的方法描述为目标节点的方法描述(共享参数更改)
this.ApiGlobalName = GetApiInvokeName(this); this.ApiGlobalName = GetApiInvokeName(this); // 生成新的接口名称
} }
} }
} }
OnPropertyChanged(nameof(MethodDetails)); OnPropertyChanged(nameof(MethodDetails)); // 通知控件MethodDetails属性发生改变
} }
partial void OnIsShareParamChanged(bool value) partial void OnIsShareParamChanged(bool value)
@@ -132,6 +136,7 @@ namespace Serein.NodeFlow.Model
} }
if (value) if (value)
{ {
// 不再与目标节点共享参数,而是拷贝新的实体,缓存起来,自己单独使用
CacheMethodDetails = TargetNode.MethodDetails.CloneOfNode(this); CacheMethodDetails = TargetNode.MethodDetails.CloneOfNode(this);
this.MethodDetails = CacheMethodDetails; this.MethodDetails = CacheMethodDetails;
} }
@@ -140,12 +145,17 @@ namespace Serein.NodeFlow.Model
if(TargetNode.ControlType == NodeControlType.Script) if(TargetNode.ControlType == NodeControlType.Script)
{ {
// 脚本节点入参需不可编辑入参数量、入参名称 // 限制脚本节点对于入参数量、入参名称的修改
foreach (var item in CacheMethodDetails.ParameterDetailss) foreach (var item in CacheMethodDetails.ParameterDetailss)
{ {
item.IsParams = false; item.IsParams = false;
} }
} }
// 与目标节点共享参数
if(CacheMethodDetails is null)
{
CacheMethodDetails = TargetNode.MethodDetails; // 防御性代码,几乎不可能触发
}
this.MethodDetails = CacheMethodDetails; this.MethodDetails = CacheMethodDetails;
} }

View File

@@ -2,7 +2,7 @@
using Serein.Library.Api; using Serein.Library.Api;
using Serein.Library.Utils; using Serein.Library.Utils;
using Serein.Script; using Serein.Script;
using Serein.Script.Node; using Serein.Script.Node.FlowControl;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Dynamic; using System.Dynamic;
@@ -35,7 +35,7 @@ namespace Serein.NodeFlow.Model
private IScriptFlowApi ScriptFlowApi; private IScriptFlowApi ScriptFlowApi;
private ProgramNode programNode; private ProgramNode programNode;
private SereinScriptInterpreter ScriptInterpreter; private readonly SereinScriptInterpreter scriptInterpreter;
private bool IsScriptChanged = false; private bool IsScriptChanged = false;
/// <summary> /// <summary>
@@ -45,7 +45,7 @@ namespace Serein.NodeFlow.Model
public SingleScriptNode(IFlowEnvironment environment):base(environment) public SingleScriptNode(IFlowEnvironment environment):base(environment)
{ {
ScriptFlowApi = new ScriptFlowApi(environment, this); ScriptFlowApi = new ScriptFlowApi(environment, this);
ScriptInterpreter = new SereinScriptInterpreter(); scriptInterpreter = new SereinScriptInterpreter();
} }
static SingleScriptNode() static SingleScriptNode()
@@ -79,11 +79,11 @@ namespace Serein.NodeFlow.Model
/// </summary> /// </summary>
public override void OnCreating() public override void OnCreating()
{ {
MethodInfo? method = this.GetType().GetMethod(nameof(GetFlowApi)); /* MethodInfo? method = this.GetType().GetMethod(nameof(GetFlowApi));
if (method != null) if (method != null)
{ {
ScriptInterpreter.AddFunction(nameof(GetFlowApi), method, () => this); // 挂载获取流程接口 ScriptInterpreter.AddFunction(nameof(GetFlowApi), method, () => this); // 挂载获取流程接口
} }*/
var md = MethodDetails; var md = MethodDetails;
var pd = md.ParameterDetailss ??= new ParameterDetails[1]; var pd = md.ParameterDetailss ??= new ParameterDetails[1];
@@ -103,8 +103,8 @@ namespace Serein.NodeFlow.Model
Items = null, Items = null,
IsParams = true, IsParams = true,
//Description = "脚本节点入参" //Description = "脚本节点入参"
}; };
md.ReturnType = typeof(object); // 默认返回 object
} }
@@ -157,19 +157,24 @@ namespace Serein.NodeFlow.Model
varNames.Add(pd.Name); varNames.Add(pd.Name);
} }
var sb = new StringBuilder(); /*var sb = new StringBuilder();
foreach (var pd in MethodDetails.ParameterDetailss) foreach (var pd in MethodDetails.ParameterDetailss)
{ {
sb.AppendLine($"let {pd.Name};"); // 提前声明这些变量 sb.AppendLine($"let {pd.Name};"); // 提前声明这些变量
} }
sb.Append(Script); sb.Append(Script);
var script = sb.ToString(); var script = sb.ToString();*/
var p = new SereinScriptParser(script); var parser = new SereinScriptParser(); // 准备解析器
//var p = new SereinScriptParser(Script); var typeAnalysis = new SereinScriptTypeAnalysis(); // 准备分析器
programNode = p.Parse(); // 开始解析 programNode = parser.Parse(Script); // 开始解析获取程序主节点
var typeAnalysis = new SereinScriptTypeAnalysis();
ScriptInterpreter.SetTypeAnalysis(typeAnalysis); var dict = MethodDetails.ParameterDetailss.ToDictionary(pd => pd.Name, pd => pd.DataType);
typeAnalysis.AnalysisProgramNode(programNode); typeAnalysis.NodeSymbolInfos.Clear(); // 清空符号表
typeAnalysis.LoadSymbol(dict); // 提前加载脚本节点定义的符号
typeAnalysis.AnalysisProgramNode(programNode); // 分析节点类型
var returnType = typeAnalysis.NodeSymbolInfos[programNode]; // 获取返回类型
MethodDetails.ReturnType = returnType;
//scriptInterpreter.SetTypeAnalysis(typeAnalysis); // 设置类型分析器
} }
catch (Exception ex) catch (Exception ex)
@@ -240,17 +245,17 @@ namespace Serein.NodeFlow.Model
if (token.IsCancellationRequested) return null; if (token.IsCancellationRequested) return null;
var result = await ScriptInterpreter.InterpretAsync(scriptContext, programNode); // 从入口节点执行 var result = await scriptInterpreter.InterpretAsync(scriptContext, programNode); // 从入口节点执行
envEvent.FlowRunComplete -= onFlowStop; envEvent.FlowRunComplete -= onFlowStop;
return new FlowResult(this.Guid, context, result); return new FlowResult(this.Guid, context, result);
} }
#region #region
public IScriptFlowApi GetFlowApi() /*public IScriptFlowApi GetFlowApi()
{ {
return ScriptFlowApi; return ScriptFlowApi;
} }*/
private static class ScriptBaseFunc private static class ScriptBaseFunc
{ {

View File

@@ -375,13 +375,28 @@ namespace Serein.NodeFlow.Model.Operation
$"{Environment.NewLine}目标节点:{ToNode.Guid}"); $"{Environment.NewLine}目标节点:{ToNode.Guid}");
return false; return false;
}*/ }*/
if (FromNode.MethodDetails.ReturnType == typeof(void))
{
SereinEnv.WriteLine(InfoType.WARN, $"连接失败,节点参数入参不允许接收 void 返回值");
return false;
}
var toNodeArgSourceGuid = ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceNodeGuid; // 目标节点对应参数可能已经有其它连接 var toNodeArgSourceGuid = ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceNodeGuid; // 目标节点对应参数可能已经有其它连接
var toNodeArgSourceType = ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceType; var toNodeArgSourceType = ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceType;
if (FromNode.Guid == toNodeArgSourceGuid if (false && string.IsNullOrWhiteSpace(toNodeArgSourceGuid) && flowModelService.ContainsNodeModel(toNodeArgSourceGuid))
&& toNodeArgSourceType == ConnectionArgSourceType)
{ {
if (FromNode.NeedResultNodes[type].Contains(ToNode)) SereinEnv.WriteLine(InfoType.WARN, $"连接失败,节点参数入参不允许接收多个节点返回值");
return false;
}
// 判断是否建立过连接关系
if (FromNode.Guid == toNodeArgSourceGuid && toNodeArgSourceType == ConnectionArgSourceType)
{
if (FromNode.NeedResultNodes[type].Contains(ToNode)) // 如果来源节点被该节点获取过,则创建链接
{ {
SereinEnv.WriteLine(InfoType.INFO, $"节点之间已建立过连接关系" + SereinEnv.WriteLine(InfoType.INFO, $"节点之间已建立过连接关系" +
$"起始节点:{FromNode.Guid}" + $"起始节点:{FromNode.Guid}" +
@@ -390,14 +405,18 @@ namespace Serein.NodeFlow.Model.Operation
$"参数类型:{ConnectionArgSourceType}"); $"参数类型:{ConnectionArgSourceType}");
return false; return false;
} }
var fromNodeGuid = FromNode.Guid;
var toNodeGuid = ToNode.Guid;
// 目标节点需要参数,但却没有被依赖的记录,则添加依赖记录并出现连接
FromNode.NeedResultNodes[type].Add(ToNode); FromNode.NeedResultNodes[type].Add(ToNode);
await TriggerEvent(() => await TriggerEvent(() =>
{ {
flowEnvironmentEvent.OnNodeConnectChanged( flowEnvironmentEvent.OnNodeConnectChanged(
new NodeConnectChangeEventArgs( new NodeConnectChangeEventArgs(
FlowCanvas.Guid, FlowCanvas.Guid,
FromNode.Guid, // 从哪个节点开始 fromNodeGuid, // 从哪个节点开始
ToNode.Guid, // 连接到那个节点 toNodeGuid, // 连接到那个节点
ArgIndex, // 连接线的样式类型 ArgIndex, // 连接线的样式类型
JunctionOfConnectionType.Arg, JunctionOfConnectionType.Arg,
ConnectionArgSourceType, ConnectionArgSourceType,
@@ -409,8 +428,8 @@ namespace Serein.NodeFlow.Model.Operation
flowEnvironmentEvent.OnNodeConnectChanged( flowEnvironmentEvent.OnNodeConnectChanged(
new NodeConnectChangeEventArgs( new NodeConnectChangeEventArgs(
FlowCanvas.Guid, FlowCanvas.Guid,
FromNode.Guid, // 从哪个节点开始 fromNodeGuid, // 从哪个节点开始
ToNode.Guid, // 连接到那个节点 toNodeGuid, // 连接到那个节点
ArgIndex, // 连接线的样式类型 ArgIndex, // 连接线的样式类型
JunctionOfConnectionType.Arg, JunctionOfConnectionType.Arg,
ConnectionArgSourceType, ConnectionArgSourceType,
@@ -421,18 +440,20 @@ namespace Serein.NodeFlow.Model.Operation
return true; return true;
} }
if (!string.IsNullOrEmpty(toNodeArgSourceGuid)) // 更改关系获取 if (!string.IsNullOrEmpty(toNodeArgSourceGuid)) // 参数入参节点已有来源,更改节点参数来源
{ {
var fromNodeGuid = ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceNodeGuid;
var toNodeGuid = ToNode.Guid;
ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceNodeGuid = null; ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceNodeGuid = null;
ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceType = ConnectionArgSourceType.GetPreviousNodeData; // 恢复默认值 ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceType = ConnectionArgSourceType.GetPreviousNodeData; // 恢复默认值
FromNode.NeedResultNodes[type].Remove(ToNode);
await TriggerEvent(() => await TriggerEvent(() =>
{ {
flowEnvironmentEvent.OnNodeConnectChanged( flowEnvironmentEvent.OnNodeConnectChanged(
new NodeConnectChangeEventArgs( new NodeConnectChangeEventArgs(
FlowCanvas.Guid, FlowCanvas.Guid,
FromNode.Guid, fromNodeGuid,
ToNode.Guid, toNodeGuid,
ArgIndex, ArgIndex,
JunctionOfConnectionType.Arg, JunctionOfConnectionType.Arg,
ConnectionArgSourceType.GetPreviousNodeData, ConnectionArgSourceType.GetPreviousNodeData,
@@ -440,8 +461,15 @@ namespace Serein.NodeFlow.Model.Operation
}); });
} }
ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceNodeGuid = FromNode.Guid; // 设置 ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceNodeGuid = FromNode.Guid;
ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceType = ConnectionArgSourceType; ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceType = ConnectionArgSourceType;
FromNode.NeedResultNodes[type].Add(ToNode);
if (ToNode.ControlType == NodeControlType.Script)
{
// 脚本节点入参确定/改变来源时,更改对应的入参数据类型
ToNode.MethodDetails.ParameterDetailss[ArgIndex].DataType = FromNode.MethodDetails.ReturnType;
}
await TriggerEvent(() => await TriggerEvent(() =>
{ {
@@ -469,6 +497,7 @@ namespace Serein.NodeFlow.Model.Operation
/// <param name="index"></param> /// <param name="index"></param>
private async Task<bool> RemoveArgConnection() private async Task<bool> RemoveArgConnection()
{ {
if (ToNode.MethodDetails.ParameterDetailss is null) return false;
var type = ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceType; var type = ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceType;
FromNode.NeedResultNodes[type].Remove(ToNode); FromNode.NeedResultNodes[type].Remove(ToNode);
ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceNodeGuid = string.Empty; ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceNodeGuid = string.Empty;

View File

@@ -22,7 +22,7 @@ namespace Serein.Script.Node
/// </summary> /// </summary>
public ASTNode Value { get; } public ASTNode Value { get; }
public AssignmentNode(ASTNode targetObject, ASTNode value) => (Target, Value) = (targetObject, value); public AssignmentNode(ASTNode target, ASTNode value) => (Target, Value) = (target, value);
} }

View File

@@ -22,8 +22,28 @@ namespace Serein.Script.Node
/// <summary> /// <summary>
/// 字段名称及字段类型 /// 字段名称及字段类型
/// </summary> /// </summary>
[Obsolete("此属性已经过时将会改为Dictionary<string, string>", false)]
public Dictionary<string, Type> Fields { get; } public Dictionary<string, Type> Fields { get; }
/// <summary>
/// 字段名称及字段类型(Kvp[fididName:fidleTypeName])
/// </summary>
public Dictionary<string, string> FieldInfos { get; }
public ClassTypeDefinitionNode(Dictionary<string, string> fields, string className)
{
this.FieldInfos = fields;
this.ClassName = className;
}
[Obsolete("此构造方法已经过时,可能在下一个版本中移除", false)]
public ClassTypeDefinitionNode(Dictionary<string, Type> fields, string className)
{
this.Fields = fields;
this.ClassName = className;
}
[Obsolete("此构造方法已经过时,可能在下一个版本中移除", false)]
public ClassTypeDefinitionNode(Dictionary<string, Type> fields, string className, bool isOverlay) public ClassTypeDefinitionNode(Dictionary<string, Type> fields, string className, bool isOverlay)
{ {
this.Fields = fields; this.Fields = fields;

View File

@@ -20,10 +20,33 @@ namespace Serein.Script.Node
/// 索引来源 /// 索引来源
/// </summary> /// </summary>
public ASTNode Index { get; } public ASTNode Index { get; }
public CollectionIndexNode(ASTNode TargetValue,ASTNode indexValue)
public CollectionIndexNode(ASTNode Collection, ASTNode indexValue)
{ {
this.Collection = TargetValue; this.Collection = Collection;
this.Index = indexValue; this.Index = indexValue;
} }
} }
/// <summary>
/// 集合赋值节点
/// </summary>
public class CollectionAssignmentNode : ASTNode
{
/// <summary>
/// 集合来源
/// </summary>
public CollectionIndexNode Collection { get; }
/// <summary>
/// 索引来源
/// </summary>
public ASTNode Value { get; }
public CollectionAssignmentNode(CollectionIndexNode collection, ASTNode value)
{
this.Collection = collection;
this.Value = value;
}
}
} }

View File

@@ -1,13 +1,13 @@
namespace Serein.Script.Node namespace Serein.Script.Node
{ {
public class ObjectMemberExpressionNode : ASTNode public class ExpressionNode : ASTNode
{ {
/// <summary> /// <summary>
/// 对象成员(嵌套获取) /// 对象成员(嵌套获取)
/// </summary> /// </summary>
public ASTNode Value { get; } public ASTNode Value { get; }
public ObjectMemberExpressionNode(ASTNode value) public ExpressionNode(ASTNode value)
{ {
this.Value = value; this.Value = value;
} }

View File

@@ -4,7 +4,7 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Serein.Script.Node namespace Serein.Script.Node.FlowControl
{ {
/// <summary> /// <summary>
/// 条件节点 /// 条件节点

View File

@@ -4,7 +4,7 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Serein.Script.Node namespace Serein.Script.Node.FlowControl
{ {
/// <summary> /// <summary>
/// 程序入口 /// 程序入口

View File

@@ -4,7 +4,7 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Serein.Script.Node namespace Serein.Script.Node.FlowControl
{ {
/// <summary> /// <summary>
/// 返回值 /// 返回值

View File

@@ -4,7 +4,7 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Serein.Script.Node namespace Serein.Script.Node.FlowControl
{ {
/// <summary> /// <summary>
/// 循环条件节点 /// 循环条件节点

View File

@@ -2,10 +2,12 @@
using Serein.Library; using Serein.Library;
using Serein.Library.Utils; using Serein.Library.Utils;
using Serein.Script.Node; using Serein.Script.Node;
using Serein.Script.Node.FlowControl;
using System.ComponentModel.Design; using System.ComponentModel.Design;
using System.Reflection; using System.Reflection;
using System.Reflection.Metadata.Ecma335; using System.Reflection.Metadata.Ecma335;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using System.Xml.Linq; using System.Xml.Linq;
namespace Serein.Script namespace Serein.Script
@@ -358,7 +360,10 @@ namespace Serein.Script
case AssignmentNode assignment: // 出现在 = 右侧的表达式 case AssignmentNode assignment: // 出现在 = 右侧的表达式
await ExecutionAssignmentNodeAsync(context, assignment); await ExecutionAssignmentNodeAsync(context, assignment);
break; break;
case ObjectMemberExpressionNode objectMemberExpressionNode: case CollectionAssignmentNode collectionAssignmentNode:
await SetCollectionValue(context,collectionAssignmentNode);
break;
case ExpressionNode objectMemberExpressionNode:
break; break;
case MemberAssignmentNode memberAssignmentNode: // 设置对象属性 case MemberAssignmentNode memberAssignmentNode: // 设置对象属性
await SetMemberValue(context, memberAssignmentNode); await SetMemberValue(context, memberAssignmentNode);
@@ -455,8 +460,8 @@ namespace Serein.Script
return await GetCollectionValue(context, collectionIndexNode); return await GetCollectionValue(context, collectionIndexNode);
case ReturnNode returnNode: // 返回内容 case ReturnNode returnNode: // 返回内容
return await EvaluateAsync(context, returnNode.Value); // 直接返回响应的内容 return await EvaluateAsync(context, returnNode.Value); // 直接返回响应的内容
case ObjectMemberExpressionNode objectMemberExpressionNode: // 对象链式表达式 case ExpressionNode expressionNode: // 表达式
return await EvaluateAsync(context, objectMemberExpressionNode.Value); return await EvaluateAsync(context, expressionNode.Value);
default: default:
throw new SereinSciptException(node, $"解释器 EvaluateAsync() 未实现{node}节点行为"); throw new SereinSciptException(node, $"解释器 EvaluateAsync() 未实现{node}节点行为");
} }
@@ -667,6 +672,79 @@ namespace Serein.Script
} }
/// <summary>
/// 设置集合中的成员
/// </summary>
/// <param name="memberAccessNode"></param>
/// <returns></returns>
/// <exception cref="SereinSciptException"></exception>
public async Task SetCollectionValue(IScriptInvokeContext context, CollectionAssignmentNode collectionAssignmentNode)
{
var collectionValue = await EvaluateAsync(context, collectionAssignmentNode.Collection.Collection);
var indexValue = await EvaluateAsync(context, collectionAssignmentNode.Collection.Index);
if (collectionValue is null)
{
throw new ArgumentNullException($"解析{collectionAssignmentNode}节点时,集合返回空。");
}
if (indexValue is null)
{
throw new ArgumentNullException($"解析{collectionAssignmentNode}节点时,索引返回空。");
}
// 解析数组/集合名与索引部分
var targetType = collectionValue.GetType(); // 目标对象的类型
#region
if (targetType.IsGenericType && targetType.GetGenericTypeDefinition() == typeof(Dictionary<,>))
{
// 目标是键值对
var method = targetType.GetMethod("set_Item", BindingFlags.Public | BindingFlags.Instance);
if (method is not null)
{
var valueValue = await EvaluateAsync(context, collectionAssignmentNode.Value);
method.Invoke(collectionValue, [indexValue, valueValue]);
}
}
#endregion
#region
else
{
if (indexValue is int index)
{
// 获取数组或集合对象
// 访问数组或集合中的指定索引
if (collectionValue is Array array)
{
if (index < 0 || index >= array.Length)
{
throw new ArgumentException($"解析{collectionValue}节点时,数组下标越界。");
}
var valueValue = await EvaluateAsync(context, collectionAssignmentNode.Value);
array.SetValue(valueValue, index);
return;
}
else if (collectionValue is IList<object> list)
{
if (index < 0 || index >= list.Count)
{
throw new ArgumentException($"解析{collectionValue}节点时,数组下标越界。");
}
var valueValue = await EvaluateAsync(context, collectionAssignmentNode.Value);
list[index] = valueValue;
return;
}
else
{
throw new ArgumentException($"解析{collectionValue}节点时,左值并非有效集合。");
}
}
}
#endregion
throw new ArgumentException($"解析{collectionValue}节点时,左值并非有效集合。");
}
/// <summary> /// <summary>
/// 缓存method委托 /// 缓存method委托
/// </summary> /// </summary>

View File

@@ -174,6 +174,15 @@ namespace Serein.Script
return nextToken; // 返回下一个 token return nextToken; // 返回下一个 token
} }
/// <summary>
/// 重置Lexer
/// </summary>
public void Reset()
{
this._row = 0;
this._index = 0;
}
/// <summary> /// <summary>
/// 根据 token 重置Lexer /// 根据 token 重置Lexer
/// </summary> /// </summary>
@@ -184,6 +193,7 @@ namespace Serein.Script
this._index = token.StartIndex; this._index = token.StartIndex;
} }
internal Token NextToken() internal Token NextToken()
{ {

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,7 @@
using Serein.Library; using Serein.Library;
using Serein.Library.Utils; using Serein.Library.Utils;
using Serein.Script.Node; using Serein.Script.Node;
using Serein.Script.Node.FlowControl;
using Serein.Script.Symbol; using Serein.Script.Symbol;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -30,9 +31,21 @@ namespace Serein.Script
} }
public void LoadSymbol(Dictionary<string,Type> identifierNodes)
{
foreach(var kvp in identifierNodes)
{
var name = kvp.Key;
var type = kvp.Value;
var identifierNode = new IdentifierNode(name);
NodeSymbolInfos[identifierNode] = type;
}
}
public void AnalysisProgramNode(ProgramNode astNode) public void AnalysisProgramNode(ProgramNode astNode)
{ {
NodeSymbolInfos.Clear(); //NodeSymbolInfos.Clear();
for (int i = 0; i < astNode.Statements.Count; i++) for (int i = 0; i < astNode.Statements.Count; i++)
{ {
var node = astNode.Statements[i]; var node = astNode.Statements[i];
@@ -59,103 +72,6 @@ namespace Serein.Script
/// <summary>
/// 类型分析
/// </summary>
/// <param name="node"></param>
/// <exception cref="NotImplementedException"></exception>
private void Analysis1(ASTNode node)
{
switch (node)
{
case ProgramNode programNode: // 程序开始节点
break;
case ReturnNode returnNode: // 程序退出节点
Analysis(returnNode); // 解析变量定义的类型
break;
case NullNode nullNode: // null
case CharNode charNode: // char字面量
case StringNode stringNode: // 字符串字面量
case BooleanNode booleanNode: // 布尔值字面量
case NumberIntNode numberIntNode: // int整型数值字面量
case NumberLongNode numberLongNode: // long整型数值字面量
case NumberFloatNode numberFloatNode: // float浮点数值字面量
case NumberDoubleNode numberDoubleNode: // double浮点数值字面量
Analysis(node);
break;
case IdentifierNode identifierNode: // 变量定义
void AnalysisIdentifierNode(IdentifierNode identifierNode)
{
Analysis(identifierNode); // 解析变量定义的类型
}
AnalysisIdentifierNode(identifierNode);
break;
case IfNode ifNode: // if语句结构
void AnalysisIfNode(IfNode ifNode)
{
Analysis(ifNode);
}
AnalysisIfNode(ifNode);
break;
case WhileNode whileNode: // while语句结构
void AnalysisWhileNode(WhileNode whileNode)
{
Analysis(whileNode);
}
AnalysisWhileNode(whileNode);
break;
case AssignmentNode assignmentNode: // 对象赋值语句let x;默认赋值null。默认类型object
void AnalysisAssignmentNode(AssignmentNode assignmentNode)
{
Analysis(assignmentNode);
}
AnalysisAssignmentNode(assignmentNode);
break;
case BinaryOperationNode binaryOperationNode: // 二元运算操作
void AnalysisBinaryOperationNode(BinaryOperationNode binaryOperationNode)
{
Analysis(binaryOperationNode);
}
AnalysisBinaryOperationNode(binaryOperationNode);
break;
case CollectionIndexNode collectionIndexNode: // 集合类型操作
void AnalysisCollectionIndexNode(CollectionIndexNode collectionIndexNode)
{
Analysis(collectionIndexNode);
}
AnalysisCollectionIndexNode(collectionIndexNode);
break;
case ClassTypeDefinitionNode classTypeDefinitionNode: // 类型定义
Analysis(classTypeDefinitionNode);
break;
case ObjectInstantiationNode objectInstantiationNode: // 类型实例化
Analysis(objectInstantiationNode);
break;
case ObjectMemberExpressionNode objectMemberExpressionNode: // 类型表达式(链式调用)
Analysis(objectMemberExpressionNode);
break;
case MemberAccessNode memberAccessNode: // 对象成员访问
Analysis(memberAccessNode);
break;
case MemberAssignmentNode memberAssignmentNode: // 对象成员赋值
void AnalysisMemberAssignmentNode(MemberAssignmentNode memberAssignmentNode)
{
Analysis(memberAssignmentNode);
}
AnalysisMemberAssignmentNode(memberAssignmentNode);
break;
case MemberFunctionCallNode memberFunctionCallNode: // 对象方法调用
Analysis(memberFunctionCallNode);
break;
case FunctionCallNode functionCallNode: // 外部挂载的函数调用
Analysis(functionCallNode);
break;
default: // 未定义的节点类型
break;
}
}
/// <summary> /// <summary>
/// 类型获取 /// 类型获取
/// </summary> /// </summary>
@@ -302,6 +218,20 @@ namespace Serein.Script
return resultType; return resultType;
} }
return AnalysisCollectionIndexNode(collectionIndexNode); return AnalysisCollectionIndexNode(collectionIndexNode);
case CollectionAssignmentNode collectionAssignmentNode: // 集合赋值操作
Type AnalysisCollectionAssignmentNode(CollectionAssignmentNode collectionAssignmentNode)
{
var resultType = Analysis(collectionAssignmentNode.Collection); // 分析集合返回返回类型
var valueType = Analysis(collectionAssignmentNode.Value); // 分析赋值的类型
if (!resultType.IsAssignableFrom(valueType))
throw new Exception($"类型 {resultType} 不支持索引操作");
NodeSymbolInfos[collectionAssignmentNode.Collection] = resultType;
NodeSymbolInfos[collectionAssignmentNode.Value] = valueType;
NodeSymbolInfos[collectionAssignmentNode] = typeof(void); // 赋值语句不产生类型
return typeof(void);
}
return AnalysisCollectionAssignmentNode(collectionAssignmentNode);
case ClassTypeDefinitionNode classTypeDefinitionNode: // 类型定义 case ClassTypeDefinitionNode classTypeDefinitionNode: // 类型定义
Type AnalysisClassTypeDefinitionNode(ClassTypeDefinitionNode classTypeDefinitionNode) Type AnalysisClassTypeDefinitionNode(ClassTypeDefinitionNode classTypeDefinitionNode)
{ {
@@ -331,18 +261,18 @@ namespace Serein.Script
return resultType; return resultType;
} }
return AnalysisObjectInstantiationNode(objectInstantiationNode); return AnalysisObjectInstantiationNode(objectInstantiationNode);
case ObjectMemberExpressionNode objectMemberExpressionNode: // 类型表达式(链式调用) case ExpressionNode expressionNode: // 类型表达式(链式调用)
Type AnalysisObjectMemberExpressionNode(ObjectMemberExpressionNode objectMemberExpressionNode) Type AnalysisObjectMemberExpressionNode(ExpressionNode expressionNode)
{ {
// 1. 对象成员获取 MemberAccessNode // 1. 对象成员获取 MemberAccessNode
// 2. 对象方法调用 MemberFunctionCallNode // 2. 对象方法调用 MemberFunctionCallNode
// 3. 对象集合成员获取 CollectionIndexNode // 3. 对象集合成员获取 CollectionIndexNode
Type? resultType = Analysis(objectMemberExpressionNode.Value); Type? resultType = Analysis(expressionNode.Value);
NodeSymbolInfos[objectMemberExpressionNode.Value] = resultType; NodeSymbolInfos[expressionNode.Value] = resultType;
NodeSymbolInfos[objectMemberExpressionNode] = resultType; NodeSymbolInfos[expressionNode] = resultType;
return resultType; return resultType;
} }
return AnalysisObjectMemberExpressionNode(objectMemberExpressionNode); return AnalysisObjectMemberExpressionNode(expressionNode);
case MemberAccessNode memberAccessNode: // 对象成员访问 case MemberAccessNode memberAccessNode: // 对象成员访问
Type AnalysisMemberAccessNode(MemberAccessNode memberAccessNode) Type AnalysisMemberAccessNode(MemberAccessNode memberAccessNode)
{ {
@@ -416,6 +346,106 @@ namespace Serein.Script
} }
/// <summary>
/// 类型分析
/// </summary>
/// <param name="node"></param>
/// <exception cref="NotImplementedException"></exception>
private void Analysis1(ASTNode node)
{
switch (node)
{
case ProgramNode programNode: // 程序开始节点
break;
case ReturnNode returnNode: // 程序退出节点
Analysis(returnNode); // 解析变量定义的类型
break;
case NullNode nullNode: // null
case CharNode charNode: // char字面量
case StringNode stringNode: // 字符串字面量
case BooleanNode booleanNode: // 布尔值字面量
case NumberIntNode numberIntNode: // int整型数值字面量
case NumberLongNode numberLongNode: // long整型数值字面量
case NumberFloatNode numberFloatNode: // float浮点数值字面量
case NumberDoubleNode numberDoubleNode: // double浮点数值字面量
Analysis(node);
break;
case IdentifierNode identifierNode: // 变量定义
void AnalysisIdentifierNode(IdentifierNode identifierNode)
{
Analysis(identifierNode); // 解析变量定义的类型
}
AnalysisIdentifierNode(identifierNode);
break;
case IfNode ifNode: // if语句结构
void AnalysisIfNode(IfNode ifNode)
{
Analysis(ifNode);
}
AnalysisIfNode(ifNode);
break;
case WhileNode whileNode: // while语句结构
void AnalysisWhileNode(WhileNode whileNode)
{
Analysis(whileNode);
}
AnalysisWhileNode(whileNode);
break;
case AssignmentNode assignmentNode: // 对象赋值语句let x;默认赋值null。默认类型object
void AnalysisAssignmentNode(AssignmentNode assignmentNode)
{
Analysis(assignmentNode);
}
AnalysisAssignmentNode(assignmentNode);
break;
case BinaryOperationNode binaryOperationNode: // 二元运算操作
void AnalysisBinaryOperationNode(BinaryOperationNode binaryOperationNode)
{
Analysis(binaryOperationNode);
}
AnalysisBinaryOperationNode(binaryOperationNode);
break;
case CollectionIndexNode collectionIndexNode: // 集合类型操作
void AnalysisCollectionIndexNode(CollectionIndexNode collectionIndexNode)
{
Analysis(collectionIndexNode);
}
AnalysisCollectionIndexNode(collectionIndexNode);
break;
case ClassTypeDefinitionNode classTypeDefinitionNode: // 类型定义
Analysis(classTypeDefinitionNode);
break;
case ObjectInstantiationNode objectInstantiationNode: // 类型实例化
Analysis(objectInstantiationNode);
break;
case ExpressionNode expressionNode: // 类型表达式(链式调用)
Analysis(expressionNode.Value);
break;
case MemberAccessNode memberAccessNode: // 对象成员访问
Analysis(memberAccessNode);
break;
case MemberAssignmentNode memberAssignmentNode: // 对象成员赋值
void AnalysisMemberAssignmentNode(MemberAssignmentNode memberAssignmentNode)
{
Analysis(memberAssignmentNode);
}
AnalysisMemberAssignmentNode(memberAssignmentNode);
break;
case MemberFunctionCallNode memberFunctionCallNode: // 对象方法调用
Analysis(memberFunctionCallNode);
break;
case FunctionCallNode functionCallNode: // 外部挂载的函数调用
Analysis(functionCallNode);
break;
default: // 未定义的节点类型
break;
}
}
private void Analysis2(ASTNode node) private void Analysis2(ASTNode node)
{ {
switch (node) switch (node)
@@ -450,13 +480,15 @@ namespace Serein.Script
break; break;
case BinaryOperationNode binaryOperationNode: // 二元运算操作 case BinaryOperationNode binaryOperationNode: // 二元运算操作
break; break;
case CollectionAssignmentNode collectionAssignmentNode:
break;
case CollectionIndexNode collectionIndexNode: // 集合类型操作 case CollectionIndexNode collectionIndexNode: // 集合类型操作
break; break;
case ClassTypeDefinitionNode classTypeDefinitionNode: // 类型定义 case ClassTypeDefinitionNode classTypeDefinitionNode: // 类型定义
break; break;
case ObjectInstantiationNode objectInstantiationNode: // 类型实例化 case ObjectInstantiationNode objectInstantiationNode: // 类型实例化
break; break;
case ObjectMemberExpressionNode objectMemberExpressionNode: // 类型表达式(链式调用) case ExpressionNode expressionNode: // 类型表达式(链式调用)
break; break;
case MemberAccessNode memberAccessNode: // 对象成员访问 case MemberAccessNode memberAccessNode: // 对象成员访问
break; break;
@@ -472,6 +504,9 @@ namespace Serein.Script
} }
/// <summary> /// <summary>
/// 获取某个集合类型支持的索引参数类型 /// 获取某个集合类型支持的索引参数类型
/// </summary> /// </summary>

View File

@@ -17,6 +17,8 @@ using Serein.Workbench.Tool;
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics; using System.Diagnostics;
using Serein.Library.Api; using Serein.Library.Api;
using Serein.Workbench.Node.ViewModel;
using Serein.Workbench.Themes;
namespace Serein.Workbench.Node.View namespace Serein.Workbench.Node.View
{ {
@@ -40,6 +42,7 @@ namespace Serein.Workbench.Node.View
} }
} }
/// <summary> /// <summary>
/// 入参控件 /// 入参控件
/// </summary> /// </summary>
@@ -135,7 +138,6 @@ namespace Serein.Workbench.Node.View
{ {
AddOrRemoveParamsAction = RemoveParamAsync; AddOrRemoveParamsAction = RemoveParamAsync;
this.Dispatcher.Invoke(InvalidateVisual);// 触发一次重绘 this.Dispatcher.Invoke(InvalidateVisual);// 触发一次重绘
} }
}); });
} }
@@ -157,11 +159,11 @@ namespace Serein.Workbench.Node.View
private void AddParamAsync() private void AddParamAsync() // 以当前选定入参连接器增加新的入参
{ {
this.MyNode.Env.FlowEdit.ChangeParameter(MyNode.Guid, true, ArgIndex); this.MyNode.Env.FlowEdit.ChangeParameter(MyNode.Guid, true, ArgIndex);
} }
private void RemoveParamAsync() private void RemoveParamAsync() // 移除当前选定的入参连接器
{ {
this.MyNode.Env.FlowEdit.ChangeParameter(MyNode.Guid, false, ArgIndex); this.MyNode.Env.FlowEdit.ChangeParameter(MyNode.Guid, false, ArgIndex);
} }
@@ -194,18 +196,41 @@ namespace Serein.Workbench.Node.View
#region #region
public static readonly DependencyProperty NodeProperty = /* public static readonly DependencyProperty NodeProperty =
DependencyProperty.Register(nameof(MyNode), typeof(IFlowNode), typeof(JunctionControlBase), new PropertyMetadata(default(IFlowNode))); DependencyProperty.Register(nameof(MyNode), typeof(IFlowNode), typeof(JunctionControlBase), new PropertyMetadata(default(IFlowNode)));
//public NodeModelBase NodeModel;
/// <summary>
/// 所在的节点
/// </summary>
public IFlowNode MyNode public IFlowNode MyNode
{ {
get { return (IFlowNode)GetValue(NodeProperty); } get { return (IFlowNode)GetValue(NodeProperty); }
set { SetValue(NodeProperty, value); } set { SetValue(NodeProperty, value); }
} }
*/
/// <summary>
/// 对应的节点Control View Model
/// </summary>
public NodeControlViewModelBase NodeViewModel
{
get { return (NodeControlViewModelBase)GetValue(NodeViewModelProperty); }
set { SetValue(NodeViewModelProperty, value); }
}
public static readonly DependencyProperty NodeViewModelProperty =
DependencyProperty.Register(nameof(NodeViewModel), typeof(NodeControlViewModelBase), typeof(JunctionControlBase), new PropertyMetadata(default(IFlowNode)));
/// <summary>
/// 对应的节点Guid
/// </summary>
public string NodeGuid
{
get
{
return NodeViewModel?.NodeModel.Guid ?? string.Empty;
}
}
#endregion #endregion
#region #region
@@ -253,13 +278,8 @@ namespace Serein.Workbench.Node.View
{ {
if(_isMouseOver != value) if(_isMouseOver != value)
{ {
if(flowNodeService is not null)
{
flowNodeService.ConnectingData.CurrentJunction = this;
}
_isMouseOver = value; _isMouseOver = value;
InvalidateVisual();
} }
} }
@@ -327,6 +347,10 @@ namespace Serein.Workbench.Node.View
//if (IsMouseOver) return; //if (IsMouseOver) return;
IsMouseOver = true; IsMouseOver = true;
flowNodeService.ConnectingData.CurrentJunction = this;
InvalidateVisual();
//Debug.WriteLine(NodeGuid);
//this.InvalidateVisual(); //this.InvalidateVisual();
} }
@@ -339,7 +363,8 @@ namespace Serein.Workbench.Node.View
{ {
IsMouseOver = false; IsMouseOver = false;
e.Handled = true; e.Handled = true;
flowNodeService.ConnectingData.CurrentJunction = this;
InvalidateVisual();
} }

View File

@@ -86,7 +86,7 @@ namespace Serein.Workbench.Node.View
} }
if (!StartJunction.MyNode.Equals(CurrentJunction.MyNode) if (!StartJunction.NodeGuid.Equals(CurrentJunction.NodeGuid)
&& StartJunction.JunctionType.IsCanConnection(CurrentJunction.JunctionType)) && StartJunction.JunctionType.IsCanConnection(CurrentJunction.JunctionType))
{ {
return true; return true;
@@ -139,23 +139,5 @@ namespace Serein.Workbench.Node.View
} }
public static class GlobalJunctionData1
{
//private static ConnectingData? myGlobalData;
//private static object _lockObj = new object();
/// <summary>
/// 创建节点之间控制点的连接行为
/// </summary>
public static ConnectingData MyGlobalConnectingData { get; } = new ConnectingData();
/// <summary>
/// 删除连接视觉效果
/// </summary>
public static void OK()
{
MyGlobalConnectingData.Reset();
}
}
#endregion #endregion
} }

View File

@@ -15,7 +15,7 @@ namespace Serein.Workbench.Node.View
#region #region
public static readonly DependencyProperty ArgIndexProperty = public static readonly DependencyProperty ArgIndexProperty =
DependencyProperty.Register("ArgIndex", typeof(int), typeof(ArgJunctionControl), new PropertyMetadata(default(int))); DependencyProperty.Register(nameof(ArgIndex), typeof(int), typeof(ArgJunctionControl), new PropertyMetadata(default(int)));
/// <summary> /// <summary>
/// 所在的节点 /// 所在的节点

View File

@@ -62,15 +62,15 @@
<ColumnDefinition Width="auto"/> <ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<local:ExecuteJunctionControl Grid.Column="0" MyNode="{Binding NodeModel}" x:Name="ExecuteJunctionControl" HorizontalAlignment="Left" Grid.RowSpan="2"/> <local:ExecuteJunctionControl Grid.Column="0" NodeViewModel="{Binding}" x:Name="ExecuteJunctionControl" HorizontalAlignment="Left" Grid.RowSpan="2"/>
<StackPanel Grid.Column="1" Grid.RowSpan="2" > <StackPanel Grid.Column="1" Grid.RowSpan="2" >
<TextBlock Text="{Binding NodeModel.DisplayName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center"/> <TextBlock Text="{Binding NodeModel.DisplayName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center"/>
</StackPanel> </StackPanel>
<local:NextStepJunctionControl Grid.Column="2" MyNode="{Binding NodeModel}" x:Name="NextStepJunctionControl" HorizontalAlignment="Right" Grid.RowSpan="2"/> <local:NextStepJunctionControl Grid.Column="2" NodeViewModel="{Binding}" x:Name="NextStepJunctionControl" HorizontalAlignment="Right" Grid.RowSpan="2"/>
</Grid> </Grid>
<themes:MethodDetailsControl Grid.Row="2" x:Name="MethodDetailsControl" MethodDetails="{Binding NodeModel.MethodDetails}"/> <themes:MethodDetailsControl Grid.Row="2" x:Name="MethodDetailsControl" MethodDetails="{Binding NodeModel.MethodDetails}" NodeViewModel="{Binding}"/>
<Border Grid.Row="2" x:Name="ParameterProtectionMask" Background="#40508D" Opacity="0.5" BorderThickness="0" <Border Grid.Row="2" x:Name="ParameterProtectionMask" Background="#40508D" Opacity="0.5" BorderThickness="0"
Visibility="{Binding NodeModel.DebugSetting.IsProtectionParameter, Mode=TwoWay, Visibility="{Binding NodeModel.DebugSetting.IsProtectionParameter, Mode=TwoWay,
@@ -90,7 +90,7 @@
</Border> </Border>
<Border Grid.Column="2" BorderThickness="1"> <Border Grid.Column="2" BorderThickness="1">
<local:ResultJunctionControl Grid.Column="2" MyNode="{Binding NodeModel}" x:Name="ResultJunctionControl" HorizontalAlignment="Right"/> <local:ResultJunctionControl Grid.Column="2" NodeViewModel="{Binding}" x:Name="ResultJunctionControl" HorizontalAlignment="Right"/>
</Border> </Border>
</Grid> </Grid>

View File

@@ -18,10 +18,10 @@ namespace Serein.Workbench.Node.View
{ {
DataContext = viewModel; DataContext = viewModel;
InitializeComponent(); InitializeComponent();
if(ExecuteJunctionControl.MyNode != null) /*if(ExecuteJunctionControl.MyNode != null)
{ {
ExecuteJunctionControl.MyNode.Guid = viewModel.NodeModel.Guid; ExecuteJunctionControl.MyNode.Guid = viewModel.NodeModel.Guid;
} }*/
} }
/// <summary> /// <summary>

View File

@@ -37,11 +37,11 @@
<ColumnDefinition Width="auto"/> <ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<local:ExecuteJunctionControl Grid.Column="0" MyNode="{Binding NodeModel}" x:Name="ExecuteJunctionControl" HorizontalAlignment="Left" Grid.RowSpan="2"/> <local:ExecuteJunctionControl Grid.Column="0" NodeViewModel="{Binding}" x:Name="ExecuteJunctionControl" HorizontalAlignment="Left" Grid.RowSpan="2"/>
<Border Grid.Column="1" BorderThickness="1" HorizontalAlignment="Stretch"> <Border Grid.Column="1" BorderThickness="1" HorizontalAlignment="Stretch">
<TextBlock Text="{Binding NodeModel.DisplayName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center"/> <TextBlock Text="{Binding NodeModel.DisplayName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center"/>
</Border> </Border>
<local:NextStepJunctionControl Grid.Column="2" MyNode="{Binding NodeModel}" x:Name="NextStepJunctionControl" HorizontalAlignment="Right" Grid.RowSpan="2"/> <local:NextStepJunctionControl Grid.Column="2" NodeViewModel="{Binding}" x:Name="NextStepJunctionControl" HorizontalAlignment="Right" Grid.RowSpan="2"/>
</Grid> </Grid>
@@ -55,7 +55,7 @@
<ColumnDefinition Width="20"/> <ColumnDefinition Width="20"/>
<ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<local:ArgJunctionControl Grid.Column="0" x:Name="ArgJunctionControl" ArgIndex="0" MyNode="{Binding NodeModel}" /> <local:ArgJunctionControl Grid.Column="0" x:Name="ArgJunctionControl" ArgIndex="0" NodeViewModel="{Binding}" />
<CheckBox Grid.Column="1" IsChecked="{Binding NodeModel.IsExplicitData, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Center"/> <!--Converter={StaticResource BoolToVis}--> <CheckBox Grid.Column="1" IsChecked="{Binding NodeModel.IsExplicitData, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Center"/> <!--Converter={StaticResource BoolToVis}-->
<TextBox Grid.Column="2" MinWidth="50" Text="{Binding NodeModel.ExplicitData, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" <TextBox Grid.Column="2" MinWidth="50" Text="{Binding NodeModel.ExplicitData, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
@@ -94,7 +94,7 @@
<TextBox IsEnabled="{Binding IsEnabledOnView}" Grid.Column="0" Background="#FEFAF4" MinWidth="100" Text="{Binding NodeModel.Expression, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" <TextBox IsEnabled="{Binding IsEnabledOnView}" Grid.Column="0" Background="#FEFAF4" MinWidth="100" Text="{Binding NodeModel.Expression, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
HorizontalAlignment="Stretch" VerticalAlignment="Center"/> HorizontalAlignment="Stretch" VerticalAlignment="Center"/>
<local:ResultJunctionControl Grid.Column="1" MyNode="{Binding NodeModel}" x:Name="ResultJunctionControl" HorizontalAlignment="Right"/> <local:ResultJunctionControl Grid.Column="1" NodeViewModel="{Binding}" x:Name="ResultJunctionControl" HorizontalAlignment="Right"/>
</Grid> </Grid>
</Grid> </Grid>

View File

@@ -3,6 +3,7 @@ using Serein.Library.Api;
using Serein.Workbench.Api; using Serein.Workbench.Api;
using Serein.Workbench.Extension; using Serein.Workbench.Extension;
using Serein.Workbench.Tool; using Serein.Workbench.Tool;
using Serein.Workbench.ViewModels;
using System; using System;
using System.Net; using System.Net;
using System.Windows; using System.Windows;
@@ -260,17 +261,17 @@ namespace Serein.Workbench.Node.View
// //
Canvas.Children.Remove(BezierLine); Canvas.Children.Remove(BezierLine);
var env = Start.MyNode.Env; var env = App.GetService<IFlowEnvironment>();
var canvasGuid = Start.MyNode.CanvasDetails.Guid; var canvasGuid = ((FlowCanvasViewModel)(Canvas.DataContext)).Model.Guid;
var jct = Start.JunctionType.ToConnectyionType(); var jct = Start.JunctionType.ToConnectyionType();
var jctEnd = End.JunctionType.ToConnectyionType(); var jctEnd = End.JunctionType.ToConnectyionType();
if (jct == JunctionOfConnectionType.Invoke) if (jct == JunctionOfConnectionType.Invoke)
{ {
env.FlowEdit.RemoveInvokeConnect(canvasGuid, Start.MyNode.Guid, End.MyNode.Guid, InvokeType); env.FlowEdit.RemoveInvokeConnect(canvasGuid, Start.NodeGuid, End.NodeGuid, InvokeType);
} }
else if (jct == JunctionOfConnectionType.Arg) else if (jct == JunctionOfConnectionType.Arg)
{ {
env.FlowEdit.RemoveArgSourceConnect(canvasGuid, Start.MyNode.Guid, End.MyNode.Guid, ArgIndex); env.FlowEdit.RemoveArgSourceConnect(canvasGuid, Start.NodeGuid, End.NodeGuid, ArgIndex);
} }
} }
@@ -279,10 +280,10 @@ namespace Serein.Workbench.Node.View
/// </summary> /// </summary>
public void Topping() public void Topping()
{ {
var env = Start.MyNode.Env; var env = App.GetService<IFlowEnvironment>();
if (Start.JunctionType.ToConnectyionType() == JunctionOfConnectionType.Invoke) if (Start.JunctionType.ToConnectyionType() == JunctionOfConnectionType.Invoke)
{ {
env.FlowEdit.SetConnectPriorityInvoke(Start.MyNode.Guid, End.MyNode.Guid, InvokeType); env.FlowEdit.SetConnectPriorityInvoke(Start.NodeGuid, End.NodeGuid, InvokeType);
} }
} }

View File

@@ -25,11 +25,11 @@
<ColumnDefinition Width="auto"/> <ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<local:ExecuteJunctionControl Grid.Column="0" MyNode="{Binding NodeModel}" x:Name="ExecuteJunctionControl" HorizontalAlignment="Left" Grid.RowSpan="2"/> <local:ExecuteJunctionControl Grid.Column="0" NodeViewModel="{Binding}" x:Name="ExecuteJunctionControl" HorizontalAlignment="Left" Grid.RowSpan="2"/>
<Border Grid.Column="1" BorderThickness="1" HorizontalAlignment="Stretch"> <Border Grid.Column="1" BorderThickness="1" HorizontalAlignment="Stretch">
<TextBlock Text="{Binding NodeModel.DisplayName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center"/> <TextBlock Text="{Binding NodeModel.DisplayName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center"/>
</Border> </Border>
<local:NextStepJunctionControl Grid.Column="2" MyNode="{Binding NodeModel}" x:Name="NextStepJunctionControl" HorizontalAlignment="Right" Grid.RowSpan="2"/> <local:NextStepJunctionControl Grid.Column="2" NodeViewModel="{Binding}" x:Name="NextStepJunctionControl" HorizontalAlignment="Right" Grid.RowSpan="2"/>
</Grid> </Grid>
<Grid Grid.Row="1" Background="#FEFAF4"> <Grid Grid.Row="1" Background="#FEFAF4">
@@ -38,9 +38,9 @@
<ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/>
<ColumnDefinition Width="auto"/> <ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<local:ArgJunctionControl Grid.Column="0" x:Name="ArgJunctionControl" ArgIndex="0" MyNode="{Binding NodeModel}" /> <local:ArgJunctionControl Grid.Column="0" x:Name="ArgJunctionControl" ArgIndex="0" NodeViewModel="{Binding}" />
<TextBox Grid.Column="1" IsEnabled="{Binding IsEnabledOnView}" Text="{Binding NodeModel.Expression, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Stretch"></TextBox> <TextBox Grid.Column="1" IsEnabled="{Binding IsEnabledOnView}" Text="{Binding NodeModel.Expression, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Stretch"></TextBox>
<local:ResultJunctionControl Grid.Column="2" MyNode="{Binding NodeModel}" x:Name="ResultJunctionControl" HorizontalAlignment="Right"/> <local:ResultJunctionControl Grid.Column="2" NodeViewModel="{Binding}" x:Name="ResultJunctionControl" HorizontalAlignment="Right"/>
</Grid> </Grid>
</Grid> </Grid>

View File

@@ -43,16 +43,16 @@
<ColumnDefinition Width="auto"/> <ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<local:ExecuteJunctionControl Grid.Column="0" MyNode="{Binding NodeModel}" x:Name="ExecuteJunctionControl" HorizontalAlignment="Left" Grid.RowSpan="2"/> <local:ExecuteJunctionControl Grid.Column="0" NodeViewModel="{Binding}" x:Name="ExecuteJunctionControl" HorizontalAlignment="Left" Grid.RowSpan="2"/>
<StackPanel Grid.Column="1" Grid.RowSpan="2" > <StackPanel Grid.Column="1" Grid.RowSpan="2" >
<TextBlock Text="{Binding NodeModel.DisplayName, Mode=TwoWay}" HorizontalAlignment="Center"/> <TextBlock Text="{Binding NodeModel.DisplayName, Mode=TwoWay}" HorizontalAlignment="Center"/>
</StackPanel> </StackPanel>
<local:NextStepJunctionControl Grid.Column="2" MyNode="{Binding NodeModel}" x:Name="NextStepJunctionControl" HorizontalAlignment="Right" Grid.RowSpan="2"/> <local:NextStepJunctionControl Grid.Column="2" NodeViewModel="{Binding}" x:Name="NextStepJunctionControl" HorizontalAlignment="Right" Grid.RowSpan="2"/>
</Grid> </Grid>
<!--方法描述--> <!--方法描述-->
<themes:MethodDetailsControl x:Name="MethodDetailsControl" Grid.Row="1" MethodDetails="{Binding NodeModel.MethodDetails}" /> <themes:MethodDetailsControl x:Name="MethodDetailsControl" Grid.Row="1" MethodDetails="{Binding NodeModel.MethodDetails}" NodeViewModel="{Binding}"/>
<Border Grid.Row="2" x:Name="ParameterProtectionMask" Background="#40508D" Opacity="0.5" BorderBrush="#0A4651" BorderThickness="0" <Border Grid.Row="2" x:Name="ParameterProtectionMask" Background="#40508D" Opacity="0.5" BorderBrush="#0A4651" BorderThickness="0"
Visibility="{Binding NodeModel.DebugSetting.IsProtectionParameter, Converter={StaticResource InvertedBoolConverter},ConverterParameter=Normal}" /> Visibility="{Binding NodeModel.DebugSetting.IsProtectionParameter, Converter={StaticResource InvertedBoolConverter},ConverterParameter=Normal}" />
@@ -74,7 +74,7 @@
</Border> </Border>
<Border Grid.Column="2" BorderThickness="1"> <Border Grid.Column="2" BorderThickness="1">
<local:ResultJunctionControl Grid.Column="2" MyNode="{Binding NodeModel}" x:Name="ResultJunctionControl" HorizontalAlignment="Right"/> <local:ResultJunctionControl Grid.Column="2" NodeViewModel="{Binding}" x:Name="ResultJunctionControl" HorizontalAlignment="Right"/>
</Border> </Border>
</Grid> </Grid>

View File

@@ -64,7 +64,7 @@
<ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<local:ExecuteJunctionControl Grid.Column="0" MyNode="{Binding NodeModel}" x:Name="ExecuteJunctionControl" HorizontalAlignment="Left" Grid.RowSpan="2"/> <local:ExecuteJunctionControl Grid.Column="0" NodeViewModel="{Binding}" x:Name="ExecuteJunctionControl" HorizontalAlignment="Left" Grid.RowSpan="2"/>
<StackPanel Grid.Column="1" Grid.RowSpan="2" Orientation="Horizontal"> <StackPanel Grid.Column="1" Grid.RowSpan="2" Orientation="Horizontal">
<TextBlock Text="{Binding NodeModel.DisplayName, Mode=TwoWay}" HorizontalAlignment="Center"/> <TextBlock Text="{Binding NodeModel.DisplayName, Mode=TwoWay}" HorizontalAlignment="Center"/>
@@ -109,7 +109,7 @@
<TextBlock Text="接口名称" Grid.Row="2" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Center" Width="50"/> <TextBlock Text="接口名称" Grid.Row="2" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Center" Width="50"/>
<TextBox Text="{Binding FlowCallNode.ApiGlobalName, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Grid.Row="2" Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Left" Width="{Binding ElementName=MethodDetailsControl,Path=ActualWidth}"/> <TextBox Text="{Binding FlowCallNode.ApiGlobalName, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Grid.Row="2" Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Left" Width="{Binding ElementName=MethodDetailsControl,Path=ActualWidth}"/>
<themes:MethodDetailsControl Grid.Row="3" Grid.ColumnSpan="2" x:Name="MethodDetailsControl"> <themes:MethodDetailsControl Grid.Row="3" Grid.ColumnSpan="2" x:Name="MethodDetailsControl" NodeViewModel="{Binding}">
<themes:MethodDetailsControl.MethodDetails> <themes:MethodDetailsControl.MethodDetails>
<MultiBinding Converter="{StaticResource MethodDetailsSelector}"> <MultiBinding Converter="{StaticResource MethodDetailsSelector}">
<Binding Path="FlowCallNode.IsShareParam" UpdateSourceTrigger="PropertyChanged"/> <Binding Path="FlowCallNode.IsShareParam" UpdateSourceTrigger="PropertyChanged"/>

View File

@@ -35,11 +35,11 @@
<ColumnDefinition Width="auto"/> <ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<local:ExecuteJunctionControl Grid.Column="0" MyNode="{Binding NodeModel}" x:Name="ExecuteJunctionControl" HorizontalAlignment="Left" Grid.RowSpan="2"/> <local:ExecuteJunctionControl Grid.Column="0" NodeViewModel="{Binding}" x:Name="ExecuteJunctionControl" HorizontalAlignment="Left" Grid.RowSpan="2"/>
<Border Grid.Column="1" BorderThickness="1" HorizontalAlignment="Stretch"> <Border Grid.Column="1" BorderThickness="1" HorizontalAlignment="Stretch">
<TextBlock Text="{Binding NodeModel.DisplayName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center"/> <TextBlock Text="{Binding NodeModel.DisplayName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center"/>
</Border> </Border>
<local:NextStepJunctionControl Grid.Column="2" MyNode="{Binding NodeModel}" x:Name="NextStepJunctionControl" HorizontalAlignment="Right" Grid.RowSpan="2"/> <local:NextStepJunctionControl Grid.Column="2" NodeViewModel="{Binding}" x:Name="NextStepJunctionControl" HorizontalAlignment="Right" Grid.RowSpan="2"/>
</Grid> </Grid>

View File

@@ -30,11 +30,11 @@
<ColumnDefinition Width="auto"/> <ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<local:ExecuteJunctionControl Grid.Column="0" MyNode="{Binding NodeModel}" x:Name="ExecuteJunctionControl" HorizontalAlignment="Left" Grid.RowSpan="2"/> <local:ExecuteJunctionControl Grid.Column="0" NodeViewModel="{Binding}" x:Name="ExecuteJunctionControl" HorizontalAlignment="Left" Grid.RowSpan="2"/>
<Border Grid.Column="1" BorderThickness="1" HorizontalAlignment="Stretch"> <Border Grid.Column="1" BorderThickness="1" HorizontalAlignment="Stretch">
<TextBlock Text="C#脚本节点" HorizontalAlignment="Center" VerticalAlignment="Center"/> <TextBlock Text="C#脚本节点" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border> </Border>
<local:NextStepJunctionControl Grid.Column="2" MyNode="{Binding NodeModel}" x:Name="NextStepJunctionControl" HorizontalAlignment="Right" Grid.RowSpan="2"/> <local:NextStepJunctionControl Grid.Column="2" NodeViewModel="{Binding}" x:Name="NextStepJunctionControl" HorizontalAlignment="Right" Grid.RowSpan="2"/>
</Grid> </Grid>

View File

@@ -29,11 +29,11 @@
<ColumnDefinition Width="auto"/> <ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<local:ExecuteJunctionControl Grid.Column="0" MyNode="{Binding NodeModel}" x:Name="ExecuteJunctionControl" HorizontalAlignment="Left" Grid.RowSpan="2"/> <local:ExecuteJunctionControl Grid.Column="0" NodeViewModel="{Binding}" x:Name="ExecuteJunctionControl" HorizontalAlignment="Left" Grid.RowSpan="2"/>
<Border Grid.Column="1" BorderThickness="1" HorizontalAlignment="Stretch"> <Border Grid.Column="1" BorderThickness="1" HorizontalAlignment="Stretch">
<TextBlock Text="{Binding NodeModel.DisplayName, Mode=TwoWay}" HorizontalAlignment="Center" VerticalAlignment="Center"/> <TextBlock Text="{Binding NodeModel.DisplayName, Mode=TwoWay}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border> </Border>
<local:NextStepJunctionControl Grid.Column="2" MyNode="{Binding NodeModel}" x:Name="NextStepJunctionControl" HorizontalAlignment="Right" Grid.RowSpan="2"/> <local:NextStepJunctionControl Grid.Column="2" NodeViewModel="{Binding}" x:Name="NextStepJunctionControl" HorizontalAlignment="Right" Grid.RowSpan="2"/>
</Grid> </Grid>
@@ -54,9 +54,8 @@
<Button Content="加载" Margin="3,0,1,0" Command="{Binding CommandLoadScript}" Height="17.2"></Button> <Button Content="加载" Margin="3,0,1,0" Command="{Binding CommandLoadScript}" Height="17.2"></Button>
<Button Content="执行" Margin="3,0,1,0" Command="{Binding CommandExecuting}" Height="17.2"></Button> <Button Content="执行" Margin="3,0,1,0" Command="{Binding CommandExecuting}" Height="17.2"></Button>
<!--<Button Content="刷新 " Command="{Binding CommandCopyDataExp}" Height="17.2" Margin="2,0,0,0"></Button>-->
</StackPanel> </StackPanel>
<themes:MethodDetailsControl Grid.Row="1" x:Name="MethodDetailsControl" MethodDetails="{Binding NodeModel.MethodDetails}"/> <themes:MethodDetailsControl Grid.Row="1" x:Name="MethodDetailsControl" MethodDetails="{Binding NodeModel.MethodDetails}" NodeViewModel="{Binding}"/>
<TextBox Grid.Row="2" MinHeight="20" MinWidth="100" MaxWidth="270" TextWrapping="Wrap" AcceptsReturn="True" IsEnabled="{Binding IsEnabledOnView}" Text="{Binding Script}"></TextBox> <TextBox Grid.Row="2" MinHeight="20" MinWidth="100" MaxWidth="270" TextWrapping="Wrap" AcceptsReturn="True" IsEnabled="{Binding IsEnabledOnView}" Text="{Binding Script}"></TextBox>
<Grid Grid.Row="3" > <Grid Grid.Row="3" >
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
@@ -68,11 +67,11 @@
<TextBlock Text="result ->" HorizontalAlignment="Center" VerticalAlignment="Center" /> <TextBlock Text="result ->" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border> </Border>
<Border Grid.Column="1" BorderThickness="1"> <Border Grid.Column="1" BorderThickness="1">
<TextBlock Text="{Binding NodeModel.MethodDetails.ReturnType.FullName, Mode=OneTime}" TextTrimming="CharacterEllipsis" HorizontalAlignment="Left" VerticalAlignment="Center"/> <TextBlock Text="{Binding NodeModel.MethodDetails.ReturnType}" TextTrimming="CharacterEllipsis" HorizontalAlignment="Left" VerticalAlignment="Center"/>
</Border> </Border>
<Border Grid.Column="2" BorderThickness="1"> <Border Grid.Column="2" BorderThickness="1">
<local:ResultJunctionControl Grid.Column="2" MyNode="{Binding NodeModel}" x:Name="ResultJunctionControl" HorizontalAlignment="Right"/> <local:ResultJunctionControl Grid.Column="2" NodeViewModel="{Binding}" x:Name="ResultJunctionControl" HorizontalAlignment="Right"/>
</Border> </Border>

View File

@@ -25,7 +25,7 @@
<ColumnDefinition Width="auto"/> <ColumnDefinition Width="auto"/>
<ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<local:ExecuteJunctionControl Grid.Column="0" MyNode="{Binding NodeModel}" x:Name="ExecuteJunctionControl" HorizontalAlignment="Left" Grid.RowSpan="2"/> <local:ExecuteJunctionControl Grid.Column="0" NodeViewModel="{Binding}" x:Name="ExecuteJunctionControl" HorizontalAlignment="Left" Grid.RowSpan="2"/>
<Border Grid.Column="1" BorderThickness="1" HorizontalAlignment="Stretch"> <Border Grid.Column="1" BorderThickness="1" HorizontalAlignment="Stretch">
<TextBlock Text="{Binding NodeModel.DisplayName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center"/> <TextBlock Text="{Binding NodeModel.DisplayName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center"/>
</Border> </Border>

View File

@@ -83,22 +83,32 @@ namespace Serein.Workbench.Node.ViewModel
} }
/// <summary>
/// 选择画布发生改变
/// </summary>
/// <param name="value"></param>
partial void OnSelectCanvasChanged(FlowCanvasViewModel value) partial void OnSelectCanvasChanged(FlowCanvasViewModel value)
{ {
FlowCallNode.ResetTargetNode(); FlowCallNode.ResetTargetNode(); // 改变画布直接重置
} }
/// <summary>
/// 选择的节点发生改变
/// </summary>
/// <param name="value"></param>
partial void OnSelectNodeChanged(IFlowNode value) partial void OnSelectNodeChanged(IFlowNode value)
{ {
if(value is null) if(value is null)
{ {
FlowCallNode.ResetTargetNode(); FlowCallNode.ResetTargetNode(); // 如果是不选择了,则重置一下
return; return;
} }
FlowCallNode.SetTargetNode(value.Guid); FlowCallNode.SetTargetNode(value.Guid); // 重新设置目标节点
} }
/// <summary>
/// 刷新可选画布
/// </summary>
private void RershCanvass() private void RershCanvass()
{ {
var canvass = flowNodeService.FlowCanvass.Select(f => (FlowCanvasViewModel)f.DataContext).ToArray(); // .Where(f => f.Model.PublicNodes.Count > 0) var canvass = flowNodeService.FlowCanvass.Select(f => (FlowCanvasViewModel)f.DataContext).ToArray(); // .Where(f => f.Model.PublicNodes.Count > 0)

View File

@@ -345,10 +345,6 @@ namespace Serein.Workbench.Services
} }
#endregion #endregion
//if (nodeModel.ControlType == NodeControlType.FlowCall)
//{
// Console.WriteLine("test");
//}
#region #region

View File

@@ -19,13 +19,13 @@
<Style TargetType="{x:Type local:MethodDetailsControl}"> <Style TargetType="{x:Type local:MethodDetailsControl}">
<Setter Property="Template"> <Setter Property="Template">
<Setter.Value> <Setter.Value>
<ControlTemplate TargetType="{x:Type local:MethodDetailsControl}"> <ControlTemplate x:Name="MethodControlTemplate" TargetType="{x:Type local:MethodDetailsControl}">
<!--根据方法入参数量生成相应的控件--> <!--根据方法入参数量生成相应的控件-->
<ItemsControl ItemsSource="{Binding MethodDetails.ParameterDetailss, RelativeSource={RelativeSource TemplatedParent}}" Background="#E3FDFD" > <ItemsControl ItemsSource="{Binding MethodDetails.ParameterDetailss, RelativeSource={RelativeSource TemplatedParent}}" Background="#E3FDFD" >
<ItemsControl.ItemTemplate> <ItemsControl.ItemTemplate>
<DataTemplate DataType="serein:ParameterData"> <DataTemplate DataType="serein:ParameterData">
<Grid DataContext="{Binding}"> <Grid DataContext="{Binding}" >
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/> <ColumnDefinition Width="auto"/>
<ColumnDefinition Width="auto"/> <ColumnDefinition Width="auto"/>
@@ -35,12 +35,15 @@
<ColumnDefinition Width="auto"/> <ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<!--连接控制器--> <!--连接控制器-->
<view:ArgJunctionControl x:Name="ArgJunctionControl" Grid.Column="0" ArgIndex="{Binding Index}" MyNode="{Binding NodeModel}" /> <view:ArgJunctionControl x:Name="ArgJunctionControl" Grid.Column="0" ArgIndex="{Binding Index}"
<!--参数索引提示--> NodeViewModel="{Binding NodeViewModel,
<!--<TextBlock Grid.Column="1" Text="{Binding Index,StringFormat=agr{0}}" Margin="2,0,2,0" VerticalAlignment="Center"/>--> RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MethodDetailsControl}}}" />
<!--是否设置为显式参数--> <!--是否设置为显式参数-->
<CheckBox Grid.Column="2" IsChecked="{Binding IsExplicitData, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Margin="2,0,2,0" VerticalContentAlignment="Center"/> <CheckBox Grid.Column="1" IsChecked="{Binding IsExplicitData, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Margin="2,0,2,0" VerticalContentAlignment="Center"/>
<!--参数类型提示-->
<TextBlock Grid.Column="2" Text="{Binding DataType}" Margin="2,0,2,0" VerticalAlignment="Center"/>
<!--入参参数名称--> <!--入参参数名称-->

View File

@@ -1,5 +1,7 @@
using Serein.Library; using Serein.Library;
using Serein.Workbench.Node; using Serein.Workbench.Node;
using Serein.Workbench.Node.View;
using Serein.Workbench.Node.ViewModel;
using System.Collections; using System.Collections;
using System.Globalization; using System.Globalization;
using System.Windows; using System.Windows;
@@ -98,9 +100,21 @@ namespace Serein.Workbench.Themes
set { SetValue(MethodDetailsProperty, value); } set { SetValue(MethodDetailsProperty, value); }
} }
public static readonly DependencyProperty MethodDetailsProperty = DependencyProperty.Register(nameof(MethodDetails), typeof(MethodDetails), public static readonly DependencyProperty MethodDetailsProperty = DependencyProperty.Register(nameof(MethodDetails), typeof(MethodDetails),
typeof(MethodDetailsControl), new PropertyMetadata(null, new PropertyChangedCallback(OnPropertyChange))); typeof(MethodDetailsControl), new PropertyMetadata(null, new PropertyChangedCallback(OnPropertyChange)));
public NodeControlViewModelBase NodeViewModel
{
get { return (NodeControlViewModelBase)GetValue(NodeViewModelProperty); }
set { SetValue(NodeViewModelProperty, value); }
}
public static readonly DependencyProperty NodeViewModelProperty = DependencyProperty.Register(nameof(NodeViewModel), typeof(NodeControlViewModelBase),
typeof(MethodDetailsControl), new PropertyMetadata(null, new PropertyChangedCallback(OnPropertyChange)));
#endregion #endregion

View File

@@ -190,8 +190,8 @@ namespace Serein.Workbench.Views
var connectionControl = Connections.FirstOrDefault(c => var connectionControl = Connections.FirstOrDefault(c =>
{ {
if (c.Start.MyNode.Guid != e.FromNodeGuid if (c.Start.NodeGuid != e.FromNodeGuid
|| c.End.MyNode.Guid != e.ToNodeGuid) || c.End.NodeGuid != e.ToNodeGuid)
{ {
return false; // 不是当前连接 return false; // 不是当前连接
} }
@@ -312,33 +312,6 @@ namespace Serein.Workbench.Views
RefreshAllLine(); RefreshAllLine();
} }
/// <summary>
/// 当前画布创建了节点
/// </summary>
/// <param name="nodeControl"></param>
/* private void OnCreateNode(NodeControlBase nodeControl)
{
if (!nodeControl.FlowCanvas.Guid.Equals(Guid)) // 防止事件传播到其它画布
{
return;
}
var p = nodeControl.ViewModel.NodeModel.Position;
PositionOfUI position = new PositionOfUI(p.X, p.Y);
if (TryPlaceNodeInRegion(nodeControl, position, out var regionControl)) // 判断添加到区域容器
{
// 通知运行环境调用加载节点子项的方法
_ = flowEnvironment.PlaceNodeToContainerAsync(Guid,
nodeControl.ViewModel.NodeModel.Guid, // 待移动的节点
regionControl.ViewModel.NodeModel.Guid); // 目标的容器节点
}
else
{
// 并非添加在容器中,直接放置节点
Api.Add(nodeControl); // 添加到对应的画布上
}
}*/
/// <summary> /// <summary>
/// 尝试判断是否为区域,如果是,将节点放置在区域中 /// 尝试判断是否为区域,如果是,将节点放置在区域中
@@ -388,15 +361,11 @@ namespace Serein.Workbench.Views
#region #region
private IFlowCanvas Api => this; private IFlowCanvas Api => this;
public string Guid /// <inheritdoc/>
{ public string Guid => ViewModel.Model.Guid;
get
{
return ViewModel.Model.Guid;
}
}
public string Name => ViewModel.Model.Name; /// <inheritdoc/>
public new string Name => ViewModel.Model.Name;
FlowCanvasDetails IFlowCanvas.Model => ViewModel.Model; FlowCanvasDetails IFlowCanvas.Model => ViewModel.Model;
void IFlowCanvas.Remove(NodeControlBase nodeControl) void IFlowCanvas.Remove(NodeControlBase nodeControl)
{ {
@@ -559,8 +528,8 @@ namespace Serein.Workbench.Views
JunctionControlBase endJunction = IToJunction.ExecuteJunction; JunctionControlBase endJunction = IToJunction.ExecuteJunction;
var removeConnections = Connections.Where(c => var removeConnections = Connections.Where(c =>
c.Start.MyNode.Guid == startJunction.MyNode.Guid c.Start.NodeGuid == startJunction.NodeGuid
&& c.End.MyNode.Guid == endJunction.MyNode.Guid && c.End.NodeGuid == endJunction.NodeGuid
&& (c.Start.JunctionType.ToConnectyionType() == JunctionOfConnectionType.Arg && (c.Start.JunctionType.ToConnectyionType() == JunctionOfConnectionType.Arg
|| c.End.JunctionType.ToConnectyionType() == JunctionOfConnectionType.Arg)) || c.End.JunctionType.ToConnectyionType() == JunctionOfConnectionType.Arg))
.ToList(); .ToList();
@@ -941,8 +910,8 @@ namespace Serein.Workbench.Views
flowEnvironment.FlowEdit.ConnectInvokeNode( flowEnvironment.FlowEdit.ConnectInvokeNode(
canvasGuid, canvasGuid,
cd.StartJunction.MyNode.Guid, cd.StartJunction.NodeGuid,
cd.CurrentJunction.MyNode.Guid, cd.CurrentJunction.NodeGuid,
cd.StartJunction.JunctionType, cd.StartJunction.JunctionType,
cd.CurrentJunction.JunctionType, cd.CurrentJunction.JunctionType,
cd.ConnectionInvokeType); cd.ConnectionInvokeType);
@@ -952,23 +921,31 @@ namespace Serein.Workbench.Views
#region #region
else if (cd.Type == JunctionOfConnectionType.Arg) else if (cd.Type == JunctionOfConnectionType.Arg)
{ {
var canvasGuid = this.Guid;
var argIndex = 0; var argIndex = 0;
var startNodeGuid = "";
var toNodeGuid = "";
if (cd.StartJunction is ArgJunctionControl argJunction1) if (cd.StartJunction is ArgJunctionControl argJunction1)
{ {
startNodeGuid = cd.CurrentJunction.NodeGuid;
argIndex = argJunction1.ArgIndex; argIndex = argJunction1.ArgIndex;
toNodeGuid = argJunction1.NodeGuid;
} }
else if (cd.CurrentJunction is ArgJunctionControl argJunction2) else if (cd.CurrentJunction is ArgJunctionControl argJunction2)
{ {
startNodeGuid = cd.StartJunction.NodeGuid;
startNodeGuid = cd.StartJunction.NodeGuid;
argIndex = argJunction2.ArgIndex; argIndex = argJunction2.ArgIndex;
toNodeGuid = argJunction2.NodeGuid;
} }
var canvasGuid = this.Guid;
flowEnvironment.FlowEdit.ConnectArgSourceNode( flowEnvironment.FlowEdit.ConnectArgSourceNode(
canvasGuid, canvasGuid,
cd.StartJunction.MyNode.Guid, startNodeGuid,
cd.CurrentJunction.MyNode.Guid, toNodeGuid,
cd.StartJunction.JunctionType, JunctionType.ReturnData,
cd.CurrentJunction.JunctionType, JunctionType.ArgData,
cd.ConnectionArgSourceType, cd.ConnectionArgSourceType,
argIndex); argIndex);
} }
@@ -1367,11 +1344,18 @@ namespace Serein.Workbench.Views
if (IsSelectControl) if (IsSelectControl)
return; return;
if(sender is not NodeControlBase nodeControlMain)
{
return;
}
flowNodeService.CurrentSelectNodeControl = nodeControlMain;
if (IsControlDragging && !flowNodeService.ConnectingData.IsCreateing) // 如果正在拖动控件 if (IsControlDragging && !flowNodeService.ConnectingData.IsCreateing) // 如果正在拖动控件
{ {
Point currentPosition = e.GetPosition(FlowChartCanvas); // 获取当前鼠标位置 Point currentPosition = e.GetPosition(FlowChartCanvas); // 获取当前鼠标位置
if (selectNodeControls.Count > 0 && sender is NodeControlBase nodeControlMain && selectNodeControls.Contains(nodeControlMain)) if (selectNodeControls.Count > 0 && selectNodeControls.Contains(nodeControlMain))
{ {
// 进行批量移动 // 进行批量移动
// 获取旧位置 // 获取旧位置
@@ -1419,28 +1403,24 @@ namespace Serein.Workbench.Views
} }
else else
{ // 单个节点移动 { // 单个节点移动
if (sender is not NodeControlBase nodeControl)
{
return;
}
double deltaX = currentPosition.X - startControlDragPoint.X; // 计算X轴方向的偏移量 double deltaX = currentPosition.X - startControlDragPoint.X; // 计算X轴方向的偏移量
double deltaY = currentPosition.Y - startControlDragPoint.Y; // 计算Y轴方向的偏移量 double deltaY = currentPosition.Y - startControlDragPoint.Y; // 计算Y轴方向的偏移量
double newLeft = Canvas.GetLeft(nodeControl) + deltaX; // 新的左边距 double newLeft = Canvas.GetLeft(nodeControlMain) + deltaX; // 新的左边距
double newTop = Canvas.GetTop(nodeControl) + deltaY; // 新的上边距 double newTop = Canvas.GetTop(nodeControlMain) + deltaY; // 新的上边距
// 如果被移动的控件接触到画布边缘,则限制移动范围 // 如果被移动的控件接触到画布边缘,则限制移动范围
var canvasModel = nodeControl.FlowCanvas.Model; var canvasModel = nodeControlMain.FlowCanvas.Model;
var canvasWidth = canvasModel.Width - nodeControl.ActualWidth - 10; var canvasWidth = canvasModel.Width - nodeControlMain.ActualWidth - 10;
var canvasHeight= canvasModel.Height - nodeControl.ActualHeight - 10; var canvasHeight= canvasModel.Height - nodeControlMain.ActualHeight - 10;
newLeft = newLeft < 5 ? 5 : newLeft > canvasWidth ? canvasWidth : newLeft; newLeft = newLeft < 5 ? 5 : newLeft > canvasWidth ? canvasWidth : newLeft;
newTop = newTop < 5 ? 5 : newTop > canvasHeight ? canvasHeight : newTop; newTop = newTop < 5 ? 5 : newTop > canvasHeight ? canvasHeight : newTop;
var node = nodeControl.ViewModel.NodeModel; var node = nodeControlMain.ViewModel.NodeModel;
node.Position.X = newLeft; node.Position.X = newLeft;
node.Position.Y = newTop; node.Position.Y = newTop;
//this.flowEnvironment.MoveNode(Guid, nodeControl.ViewModel.NodeModel.Guid, newLeft, newTop); // 移动节点 //this.flowEnvironment.MoveNode(Guid, nodeControl.ViewModel.NodeModel.Guid, newLeft, newTop); // 移动节点
nodeControl.UpdateLocationConnections(); nodeControlMain.UpdateLocationConnections();
} }
startControlDragPoint = currentPosition; // 更新起始点位置 startControlDragPoint = currentPosition; // 更新起始点位置
} }