mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-19 16:06:33 +08:00
重写脚本解释器的实现,提高其可读性。
This commit is contained in:
@@ -292,7 +292,7 @@ namespace Serein.Library
|
||||
/// 从DLL拖动出来时,从元数据拷贝新的实例,作为属于节点独享的方法描述
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public MethodDetails CloneOfNode( IFlowNode nodeModel)
|
||||
public MethodDetails CloneOfNode(IFlowNode nodeModel)
|
||||
{
|
||||
// this => 是元数据
|
||||
var md = new MethodDetails(nodeModel) // 创建新节点时拷贝实例
|
||||
|
||||
@@ -48,11 +48,7 @@ namespace Serein.NodeFlow.Env
|
||||
/// </summary>
|
||||
private RunState FlipFlopState = RunState.NoStart;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 异步运行
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <inheritdoc/>
|
||||
public async Task<bool> StartFlowAsync(string[] canvasGuids)
|
||||
{
|
||||
#region 校验参数
|
||||
@@ -144,12 +140,7 @@ namespace Serein.NodeFlow.Env
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 从选定节点开始运行
|
||||
/// </summary>
|
||||
/// <param name="startNodeGuid"></param>
|
||||
/// <returns></returns>
|
||||
/// <inheritdoc/>
|
||||
public async Task<TResult> StartFlowAsync<TResult>(string startNodeGuid)
|
||||
{
|
||||
|
||||
@@ -207,10 +198,7 @@ namespace Serein.NodeFlow.Env
|
||||
}
|
||||
return result;
|
||||
}*/
|
||||
|
||||
/// <summary>
|
||||
/// 结束流程
|
||||
/// </summary>
|
||||
/// <inheritdoc/>
|
||||
public Task<bool> ExitFlowAsync()
|
||||
{
|
||||
flowWorkManagement?.Exit();
|
||||
@@ -220,11 +208,7 @@ namespace Serein.NodeFlow.Env
|
||||
GC.Collect();
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 激活全局触发器
|
||||
/// </summary>
|
||||
/// <param name="nodeGuid"></param>
|
||||
/// <inheritdoc/>
|
||||
public void ActivateFlipflopNode(string nodeGuid)
|
||||
{
|
||||
/*if (!TryGetNodeModel(nodeGuid, out var nodeModel))
|
||||
@@ -242,11 +226,7 @@ namespace Serein.NodeFlow.Env
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 关闭全局触发器
|
||||
/// </summary>
|
||||
/// <param name="nodeGuid"></param>
|
||||
/// <inheritdoc/>
|
||||
public void TerminateFlipflopNode(string nodeGuid)
|
||||
{
|
||||
/* if (!TryGetNodeModel(nodeGuid, out var nodeModel))
|
||||
@@ -264,24 +244,12 @@ namespace Serein.NodeFlow.Env
|
||||
{
|
||||
this.sereinIOC = ioc; // 设置IOC容器
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启动器调用,运行到某个节点时触发了监视对象的更新(对象预览视图将会自动更新)
|
||||
/// </summary>
|
||||
/// <param name="nodeGuid"></param>
|
||||
/// <param name="monitorData"></param>
|
||||
/// <param name="sourceType"></param>
|
||||
/// <inheritdoc/>
|
||||
public void MonitorObjectNotification(string nodeGuid, object monitorData, MonitorObjectEventArgs.ObjSourceType sourceType)
|
||||
{
|
||||
flowEnvironmentEvent.OnMonitorObjectChanged(new MonitorObjectEventArgs(nodeGuid, monitorData, sourceType));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启动器调用,节点触发了中断。
|
||||
/// </summary>
|
||||
/// <param name="nodeGuid">节点</param>
|
||||
/// <param name="expression">表达式</param>
|
||||
/// <param name="type">类型,0用户主动的中断,1表达式中断</param>
|
||||
/// <inheritdoc/>
|
||||
public void TriggerInterrupt(string nodeGuid, string expression, InterruptTriggerEventArgs.InterruptTriggerType type)
|
||||
{
|
||||
flowEnvironmentEvent.OnInterruptTriggered(new InterruptTriggerEventArgs(nodeGuid, expression, type));
|
||||
@@ -292,28 +260,14 @@ namespace Serein.NodeFlow.Env
|
||||
|
||||
#region 流程接口调用
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 调用流程接口,将返回 FlowResult.Value。如果需要 FlowResult 对象,请使用该方法的泛型版本。
|
||||
/// </summary>
|
||||
/// <param name="apiGuid">流程接口节点Guid</param>
|
||||
/// <param name="dict">调用时入参参数</param>
|
||||
/// <returns></returns>
|
||||
/// <inheritdoc/>
|
||||
public async Task<object> InvokeAsync(string apiGuid, Dictionary<string, object> dict)
|
||||
{
|
||||
var result = await InvokeAsync<object>(apiGuid, dict);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 调用流程接口,泛型类型为 FlowResult 时,将返回 FlowResult 对象。
|
||||
/// </summary>
|
||||
/// <typeparam name="TResult"></typeparam>
|
||||
/// <param name="apiGuid">流程接口节点Guid</param>
|
||||
/// <param name="dict">调用时入参参数</param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
/// <inheritdoc/>
|
||||
public async Task<TResult> InvokeAsync<TResult>(string apiGuid, Dictionary<string, object> dict)
|
||||
{
|
||||
if (sereinIOC is null)
|
||||
|
||||
@@ -201,7 +201,7 @@ namespace Serein.NodeFlow.Env
|
||||
private int _add_canvas_count = 1;
|
||||
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void CreateCanvas(string canvasName, int width, int height)
|
||||
{
|
||||
IOperation operation = new CreateCanvasOperation
|
||||
@@ -219,7 +219,7 @@ namespace Serein.NodeFlow.Env
|
||||
|
||||
flowOperationService.Execute(operation);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void RemoveCanvas(string canvasGuid)
|
||||
{
|
||||
IOperation operation = new RemoveCanvasOperation
|
||||
@@ -228,7 +228,7 @@ namespace Serein.NodeFlow.Env
|
||||
};
|
||||
flowOperationService.Execute(operation);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void ConnectInvokeNode(string canvasGuid, string fromNodeGuid, string toNodeGuid, JunctionType fromNodeJunctionType, JunctionType toNodeJunctionType, ConnectionInvokeType invokeType)
|
||||
{
|
||||
IOperation operation = new ChangeNodeConnectionOperation
|
||||
@@ -245,7 +245,7 @@ namespace Serein.NodeFlow.Env
|
||||
|
||||
flowOperationService.Execute(operation);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void ConnectArgSourceNode(string canvasGuid, string fromNodeGuid, string toNodeGuid, JunctionType fromNodeJunctionType, JunctionType toNodeJunctionType, ConnectionArgSourceType argSourceType, int argIndex)
|
||||
{
|
||||
IOperation operation = new ChangeNodeConnectionOperation
|
||||
@@ -262,7 +262,7 @@ namespace Serein.NodeFlow.Env
|
||||
};
|
||||
flowOperationService.Execute(operation);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void RemoveInvokeConnect(string canvasGuid, string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType)
|
||||
{
|
||||
IOperation operation = new ChangeNodeConnectionOperation
|
||||
@@ -276,7 +276,7 @@ namespace Serein.NodeFlow.Env
|
||||
};
|
||||
flowOperationService.Execute(operation);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void RemoveArgSourceConnect(string canvasGuid, string fromNodeGuid, string toNodeGuid, int argIndex)
|
||||
{
|
||||
IOperation operation = new ChangeNodeConnectionOperation
|
||||
@@ -290,7 +290,7 @@ namespace Serein.NodeFlow.Env
|
||||
};
|
||||
flowOperationService.Execute(operation);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void CreateNode(string canvasGuid, NodeControlType nodeType, PositionOfUI position, MethodDetailsInfo methodDetailsInfo = null)
|
||||
{
|
||||
IOperation operation = new CreateNodeOperation
|
||||
@@ -302,7 +302,7 @@ namespace Serein.NodeFlow.Env
|
||||
};
|
||||
flowOperationService.Execute(operation);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void RemoveNode(string canvasGuid, string nodeGuid)
|
||||
{
|
||||
IOperation operation = new RemoveNodeOperation
|
||||
@@ -312,7 +312,7 @@ namespace Serein.NodeFlow.Env
|
||||
};
|
||||
flowOperationService.Execute(operation);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void PlaceNodeToContainer(string canvasGuid, string nodeGuid, string containerNodeGuid)
|
||||
{
|
||||
IOperation operation = new ContainerPlaceNodeOperation
|
||||
@@ -323,7 +323,7 @@ namespace Serein.NodeFlow.Env
|
||||
};
|
||||
flowOperationService.Execute(operation);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void TakeOutNodeToContainer(string canvasGuid, string nodeGuid)
|
||||
{
|
||||
IOperation operation = new ContainerTakeOutNodeOperation
|
||||
@@ -333,7 +333,7 @@ namespace Serein.NodeFlow.Env
|
||||
};
|
||||
flowOperationService.Execute(operation);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void SetStartNode(string canvasGuid, string nodeGuid)
|
||||
{
|
||||
|
||||
@@ -363,7 +363,7 @@ namespace Serein.NodeFlow.Env
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void SetConnectPriorityInvoke(string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType)
|
||||
{
|
||||
|
||||
@@ -377,7 +377,7 @@ namespace Serein.NodeFlow.Env
|
||||
};
|
||||
flowOperationService.Execute(operation);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void ChangeParameter(string nodeGuid, bool isAdd, int paramIndex)
|
||||
{
|
||||
IOperation operation = new ChangeParameterOperation
|
||||
@@ -389,12 +389,7 @@ namespace Serein.NodeFlow.Env
|
||||
flowOperationService.Execute(operation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从节点信息集合批量加载节点控件
|
||||
/// </summary>
|
||||
/// <param name="List<NodeInfo>">节点信息</param>
|
||||
/// <returns></returns>
|
||||
///
|
||||
/// <inheritdoc/>
|
||||
public async Task LoadNodeInfosAsync(List<NodeInfo> nodeInfos)
|
||||
{
|
||||
#region 从NodeInfo创建NodeModel
|
||||
@@ -635,11 +630,7 @@ namespace Serein.NodeFlow.Env
|
||||
|
||||
|
||||
#region 视觉效果
|
||||
|
||||
/// <summary>
|
||||
/// 定位节点
|
||||
/// </summary>
|
||||
/// <param name="nodeGuid"></param>
|
||||
/// <inheritdoc/>
|
||||
public void NodeLocate(string nodeGuid)
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
|
||||
@@ -85,43 +85,47 @@ namespace Serein.NodeFlow.Model
|
||||
TargetNodeGuid = nodeGuid;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 目标节点发生改变
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
partial void OnTargetNodeGuidChanged(string value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value) || !Env.TryGetNodeModel(value, out var targetNode))
|
||||
{
|
||||
// 取消设置接口节点
|
||||
TargetNode.PropertyChanged -= TargetNode_PropertyChanged;
|
||||
TargetNode.PropertyChanged -= TargetNode_PropertyChanged; // 不再监听目标属通知
|
||||
TargetNode = null;
|
||||
this.ApiGlobalName = "";
|
||||
this.MethodDetails = new MethodDetails();
|
||||
}
|
||||
else
|
||||
{
|
||||
//if (this.MethodDetails.ActingInstanceType.FullName.Equals())
|
||||
TargetNode = targetNode;
|
||||
if (!this.IsShareParam
|
||||
&& CacheMethodDetails is not null
|
||||
&& TargetNode.MethodDetails is not null
|
||||
&& TargetNode.MethodDetails.AssemblyName == CacheMethodDetails.AssemblyName
|
||||
&& TargetNode.MethodDetails.MethodName == CacheMethodDetails.MethodName)
|
||||
if (!this.IsShareParam // 不共享参数
|
||||
&& TargetNode.MethodDetails is not null // 目标节点有方法描述
|
||||
&& CacheMethodDetails is not null // 存在缓存
|
||||
&& TargetNode.MethodDetails.AssemblyName == CacheMethodDetails.AssemblyName // 与缓存中一致
|
||||
&& TargetNode.MethodDetails.MethodName == CacheMethodDetails.MethodName) // 与缓存中一致
|
||||
{
|
||||
this.MethodDetails = CacheMethodDetails;
|
||||
this.ApiGlobalName = GetApiInvokeName(this);
|
||||
this.MethodDetails = CacheMethodDetails; // 直接使用缓存
|
||||
this.ApiGlobalName = GetApiInvokeName(this); // 生成新的接口名称
|
||||
}
|
||||
else
|
||||
{
|
||||
if (TargetNode.MethodDetails is not null)
|
||||
if (TargetNode.MethodDetails is not null) // // 目标节点有方法描述
|
||||
{
|
||||
CacheMethodDetails = TargetNode.MethodDetails.CloneOfNode(this); // 从目标节点复制一份
|
||||
TargetNode.PropertyChanged += TargetNode_PropertyChanged;
|
||||
this.MethodDetails = CacheMethodDetails;
|
||||
this.ApiGlobalName = GetApiInvokeName(this);
|
||||
CacheMethodDetails = TargetNode.MethodDetails.CloneOfNode(this); // 从目标节点复制一份到缓存中
|
||||
TargetNode.PropertyChanged += TargetNode_PropertyChanged; // 监听目标属性通知(“IsPublic”属性)
|
||||
this.MethodDetails = CacheMethodDetails; // 设置流程接口节点的方法描述为目标节点的方法描述(共享参数更改)
|
||||
this.ApiGlobalName = GetApiInvokeName(this); // 生成新的接口名称
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
OnPropertyChanged(nameof(MethodDetails));
|
||||
OnPropertyChanged(nameof(MethodDetails)); // 通知控件,MethodDetails属性发生改变
|
||||
}
|
||||
|
||||
partial void OnIsShareParamChanged(bool value)
|
||||
@@ -132,6 +136,7 @@ namespace Serein.NodeFlow.Model
|
||||
}
|
||||
if (value)
|
||||
{
|
||||
// 不再与目标节点共享参数,而是拷贝新的实体,缓存起来,自己单独使用
|
||||
CacheMethodDetails = TargetNode.MethodDetails.CloneOfNode(this);
|
||||
this.MethodDetails = CacheMethodDetails;
|
||||
}
|
||||
@@ -140,13 +145,18 @@ namespace Serein.NodeFlow.Model
|
||||
|
||||
if(TargetNode.ControlType == NodeControlType.Script)
|
||||
{
|
||||
// 脚本节点入参需不可编辑入参数量、入参名称
|
||||
// 限制脚本节点对于入参数量、入参名称的修改
|
||||
foreach (var item in CacheMethodDetails.ParameterDetailss)
|
||||
{
|
||||
item.IsParams = false;
|
||||
}
|
||||
}
|
||||
this.MethodDetails = CacheMethodDetails;
|
||||
// 与目标节点共享参数
|
||||
if(CacheMethodDetails is null)
|
||||
{
|
||||
CacheMethodDetails = TargetNode.MethodDetails; // 防御性代码,几乎不可能触发
|
||||
}
|
||||
this.MethodDetails = CacheMethodDetails;
|
||||
}
|
||||
|
||||
OnPropertyChanged(nameof(MethodDetails));
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
using Serein.Library.Api;
|
||||
using Serein.Library.Utils;
|
||||
using Serein.Script;
|
||||
using Serein.Script.Node;
|
||||
using Serein.Script.Node.FlowControl;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
@@ -35,7 +35,7 @@ namespace Serein.NodeFlow.Model
|
||||
|
||||
private IScriptFlowApi ScriptFlowApi;
|
||||
private ProgramNode programNode;
|
||||
private SereinScriptInterpreter ScriptInterpreter;
|
||||
private readonly SereinScriptInterpreter scriptInterpreter;
|
||||
private bool IsScriptChanged = false;
|
||||
|
||||
/// <summary>
|
||||
@@ -45,7 +45,7 @@ namespace Serein.NodeFlow.Model
|
||||
public SingleScriptNode(IFlowEnvironment environment):base(environment)
|
||||
{
|
||||
ScriptFlowApi = new ScriptFlowApi(environment, this);
|
||||
ScriptInterpreter = new SereinScriptInterpreter();
|
||||
scriptInterpreter = new SereinScriptInterpreter();
|
||||
}
|
||||
|
||||
static SingleScriptNode()
|
||||
@@ -79,11 +79,11 @@ namespace Serein.NodeFlow.Model
|
||||
/// </summary>
|
||||
public override void OnCreating()
|
||||
{
|
||||
MethodInfo? method = this.GetType().GetMethod(nameof(GetFlowApi));
|
||||
/* MethodInfo? method = this.GetType().GetMethod(nameof(GetFlowApi));
|
||||
if (method != null)
|
||||
{
|
||||
ScriptInterpreter.AddFunction(nameof(GetFlowApi), method, () => this); // 挂载获取流程接口
|
||||
}
|
||||
}*/
|
||||
|
||||
var md = MethodDetails;
|
||||
var pd = md.ParameterDetailss ??= new ParameterDetails[1];
|
||||
@@ -103,8 +103,8 @@ namespace Serein.NodeFlow.Model
|
||||
Items = null,
|
||||
IsParams = true,
|
||||
//Description = "脚本节点入参"
|
||||
|
||||
};
|
||||
md.ReturnType = typeof(object); // 默认返回 object
|
||||
|
||||
}
|
||||
|
||||
@@ -157,19 +157,24 @@ namespace Serein.NodeFlow.Model
|
||||
varNames.Add(pd.Name);
|
||||
}
|
||||
|
||||
var sb = new StringBuilder();
|
||||
/*var sb = new StringBuilder();
|
||||
foreach (var pd in MethodDetails.ParameterDetailss)
|
||||
{
|
||||
sb.AppendLine($"let {pd.Name};"); // 提前声明这些变量
|
||||
}
|
||||
sb.Append(Script);
|
||||
var script = sb.ToString();
|
||||
var p = new SereinScriptParser(script);
|
||||
//var p = new SereinScriptParser(Script);
|
||||
programNode = p.Parse(); // 开始解析
|
||||
var typeAnalysis = new SereinScriptTypeAnalysis();
|
||||
ScriptInterpreter.SetTypeAnalysis(typeAnalysis);
|
||||
typeAnalysis.AnalysisProgramNode(programNode);
|
||||
var script = sb.ToString();*/
|
||||
var parser = new SereinScriptParser(); // 准备解析器
|
||||
var typeAnalysis = new SereinScriptTypeAnalysis(); // 准备分析器
|
||||
programNode = parser.Parse(Script); // 开始解析获取程序主节点
|
||||
|
||||
var dict = MethodDetails.ParameterDetailss.ToDictionary(pd => pd.Name, pd => pd.DataType);
|
||||
typeAnalysis.NodeSymbolInfos.Clear(); // 清空符号表
|
||||
typeAnalysis.LoadSymbol(dict); // 提前加载脚本节点定义的符号
|
||||
typeAnalysis.AnalysisProgramNode(programNode); // 分析节点类型
|
||||
var returnType = typeAnalysis.NodeSymbolInfos[programNode]; // 获取返回类型
|
||||
MethodDetails.ReturnType = returnType;
|
||||
//scriptInterpreter.SetTypeAnalysis(typeAnalysis); // 设置类型分析器
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -240,17 +245,17 @@ namespace Serein.NodeFlow.Model
|
||||
if (token.IsCancellationRequested) return null;
|
||||
|
||||
|
||||
var result = await ScriptInterpreter.InterpretAsync(scriptContext, programNode); // 从入口节点执行
|
||||
var result = await scriptInterpreter.InterpretAsync(scriptContext, programNode); // 从入口节点执行
|
||||
envEvent.FlowRunComplete -= onFlowStop;
|
||||
return new FlowResult(this.Guid, context, result);
|
||||
}
|
||||
|
||||
#region 挂载的方法
|
||||
|
||||
public IScriptFlowApi GetFlowApi()
|
||||
/*public IScriptFlowApi GetFlowApi()
|
||||
{
|
||||
return ScriptFlowApi;
|
||||
}
|
||||
}*/
|
||||
|
||||
private static class ScriptBaseFunc
|
||||
{
|
||||
|
||||
@@ -375,13 +375,28 @@ namespace Serein.NodeFlow.Model.Operation
|
||||
$"{Environment.NewLine}目标节点:{ToNode.Guid}");
|
||||
return false;
|
||||
}*/
|
||||
|
||||
if (FromNode.MethodDetails.ReturnType == typeof(void))
|
||||
{
|
||||
SereinEnv.WriteLine(InfoType.WARN, $"连接失败,节点参数入参不允许接收 void 返回值");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
var toNodeArgSourceGuid = ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceNodeGuid; // 目标节点对应参数可能已经有其它连接
|
||||
var toNodeArgSourceType = ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceType;
|
||||
|
||||
if (FromNode.Guid == toNodeArgSourceGuid
|
||||
&& toNodeArgSourceType == ConnectionArgSourceType)
|
||||
|
||||
if (false && string.IsNullOrWhiteSpace(toNodeArgSourceGuid) && flowModelService.ContainsNodeModel(toNodeArgSourceGuid))
|
||||
{
|
||||
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, $"节点之间已建立过连接关系" +
|
||||
$"起始节点:{FromNode.Guid}" +
|
||||
@@ -390,14 +405,18 @@ namespace Serein.NodeFlow.Model.Operation
|
||||
$"参数类型:{ConnectionArgSourceType}");
|
||||
return false;
|
||||
}
|
||||
|
||||
var fromNodeGuid = FromNode.Guid;
|
||||
var toNodeGuid = ToNode.Guid;
|
||||
// 目标节点需要参数,但却没有被依赖的记录,则添加依赖记录并出现连接
|
||||
FromNode.NeedResultNodes[type].Add(ToNode);
|
||||
await TriggerEvent(() =>
|
||||
{
|
||||
flowEnvironmentEvent.OnNodeConnectChanged(
|
||||
new NodeConnectChangeEventArgs(
|
||||
FlowCanvas.Guid,
|
||||
FromNode.Guid, // 从哪个节点开始
|
||||
ToNode.Guid, // 连接到那个节点
|
||||
fromNodeGuid, // 从哪个节点开始
|
||||
toNodeGuid, // 连接到那个节点
|
||||
ArgIndex, // 连接线的样式类型
|
||||
JunctionOfConnectionType.Arg,
|
||||
ConnectionArgSourceType,
|
||||
@@ -409,8 +428,8 @@ namespace Serein.NodeFlow.Model.Operation
|
||||
flowEnvironmentEvent.OnNodeConnectChanged(
|
||||
new NodeConnectChangeEventArgs(
|
||||
FlowCanvas.Guid,
|
||||
FromNode.Guid, // 从哪个节点开始
|
||||
ToNode.Guid, // 连接到那个节点
|
||||
fromNodeGuid, // 从哪个节点开始
|
||||
toNodeGuid, // 连接到那个节点
|
||||
ArgIndex, // 连接线的样式类型
|
||||
JunctionOfConnectionType.Arg,
|
||||
ConnectionArgSourceType,
|
||||
@@ -421,18 +440,20 @@ namespace Serein.NodeFlow.Model.Operation
|
||||
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].ArgDataSourceType = ConnectionArgSourceType.GetPreviousNodeData; // 恢复默认值
|
||||
|
||||
FromNode.NeedResultNodes[type].Remove(ToNode);
|
||||
await TriggerEvent(() =>
|
||||
{
|
||||
flowEnvironmentEvent.OnNodeConnectChanged(
|
||||
new NodeConnectChangeEventArgs(
|
||||
FlowCanvas.Guid,
|
||||
FromNode.Guid,
|
||||
ToNode.Guid,
|
||||
fromNodeGuid,
|
||||
toNodeGuid,
|
||||
ArgIndex,
|
||||
JunctionOfConnectionType.Arg,
|
||||
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;
|
||||
FromNode.NeedResultNodes[type].Add(ToNode);
|
||||
|
||||
if (ToNode.ControlType == NodeControlType.Script)
|
||||
{
|
||||
// 脚本节点入参确定/改变来源时,更改对应的入参数据类型
|
||||
ToNode.MethodDetails.ParameterDetailss[ArgIndex].DataType = FromNode.MethodDetails.ReturnType;
|
||||
}
|
||||
|
||||
await TriggerEvent(() =>
|
||||
{
|
||||
@@ -469,6 +497,7 @@ namespace Serein.NodeFlow.Model.Operation
|
||||
/// <param name="index"></param>
|
||||
private async Task<bool> RemoveArgConnection()
|
||||
{
|
||||
if (ToNode.MethodDetails.ParameterDetailss is null) return false;
|
||||
var type = ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceType;
|
||||
FromNode.NeedResultNodes[type].Remove(ToNode);
|
||||
ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceNodeGuid = string.Empty;
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Serein.Script.Node
|
||||
/// </summary>
|
||||
public ASTNode Value { get; }
|
||||
|
||||
public AssignmentNode(ASTNode targetObject, ASTNode value) => (Target, Value) = (targetObject, value);
|
||||
public AssignmentNode(ASTNode target, ASTNode value) => (Target, Value) = (target, value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -22,8 +22,28 @@ namespace Serein.Script.Node
|
||||
/// <summary>
|
||||
/// 字段名称及字段类型
|
||||
/// </summary>
|
||||
[Obsolete("此属性已经过时,将会改为Dictionary<string, string>", false)]
|
||||
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)
|
||||
{
|
||||
this.Fields = fields;
|
||||
|
||||
@@ -20,10 +20,33 @@ namespace Serein.Script.Node
|
||||
/// 索引来源
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
namespace Serein.Script.Node
|
||||
{
|
||||
public class ObjectMemberExpressionNode : ASTNode
|
||||
public class ExpressionNode : ASTNode
|
||||
{
|
||||
/// <summary>
|
||||
/// 对象成员(嵌套获取)
|
||||
/// </summary>
|
||||
public ASTNode Value { get; }
|
||||
|
||||
public ObjectMemberExpressionNode(ASTNode value)
|
||||
public ExpressionNode(ASTNode value)
|
||||
{
|
||||
this.Value = value;
|
||||
}
|
||||
@@ -4,7 +4,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Script.Node
|
||||
namespace Serein.Script.Node.FlowControl
|
||||
{
|
||||
/// <summary>
|
||||
/// 条件节点
|
||||
@@ -4,7 +4,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Script.Node
|
||||
namespace Serein.Script.Node.FlowControl
|
||||
{
|
||||
/// <summary>
|
||||
/// 程序入口
|
||||
@@ -4,7 +4,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Script.Node
|
||||
namespace Serein.Script.Node.FlowControl
|
||||
{
|
||||
/// <summary>
|
||||
/// 返回值
|
||||
@@ -4,7 +4,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Script.Node
|
||||
namespace Serein.Script.Node.FlowControl
|
||||
{
|
||||
/// <summary>
|
||||
/// 循环条件节点
|
||||
@@ -2,10 +2,12 @@
|
||||
using Serein.Library;
|
||||
using Serein.Library.Utils;
|
||||
using Serein.Script.Node;
|
||||
using Serein.Script.Node.FlowControl;
|
||||
using System.ComponentModel.Design;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Metadata.Ecma335;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Serein.Script
|
||||
@@ -358,7 +360,10 @@ namespace Serein.Script
|
||||
case AssignmentNode assignment: // 出现在 = 右侧的表达式
|
||||
await ExecutionAssignmentNodeAsync(context, assignment);
|
||||
break;
|
||||
case ObjectMemberExpressionNode objectMemberExpressionNode:
|
||||
case CollectionAssignmentNode collectionAssignmentNode:
|
||||
await SetCollectionValue(context,collectionAssignmentNode);
|
||||
break;
|
||||
case ExpressionNode objectMemberExpressionNode:
|
||||
break;
|
||||
case MemberAssignmentNode memberAssignmentNode: // 设置对象属性
|
||||
await SetMemberValue(context, memberAssignmentNode);
|
||||
@@ -455,8 +460,8 @@ namespace Serein.Script
|
||||
return await GetCollectionValue(context, collectionIndexNode);
|
||||
case ReturnNode returnNode: // 返回内容
|
||||
return await EvaluateAsync(context, returnNode.Value); // 直接返回响应的内容
|
||||
case ObjectMemberExpressionNode objectMemberExpressionNode: // 对象链式表达式
|
||||
return await EvaluateAsync(context, objectMemberExpressionNode.Value);
|
||||
case ExpressionNode expressionNode: // 表达式
|
||||
return await EvaluateAsync(context, expressionNode.Value);
|
||||
default:
|
||||
throw new SereinSciptException(node, $"解释器 EvaluateAsync() 未实现{node}节点行为");
|
||||
}
|
||||
@@ -666,6 +671,79 @@ namespace Serein.Script
|
||||
throw new ArgumentException($"解析{collectionIndexNode}节点时,左值并非有效集合。");
|
||||
|
||||
}
|
||||
|
||||
/// <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>
|
||||
/// 缓存method委托
|
||||
|
||||
@@ -174,6 +174,15 @@ namespace Serein.Script
|
||||
return nextToken; // 返回下一个 token
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重置Lexer
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
this._row = 0;
|
||||
this._index = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据 token 重置Lexer
|
||||
/// </summary>
|
||||
@@ -184,6 +193,7 @@ namespace Serein.Script
|
||||
this._index = token.StartIndex;
|
||||
}
|
||||
|
||||
|
||||
internal Token NextToken()
|
||||
{
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,7 @@
|
||||
using Serein.Library;
|
||||
using Serein.Library.Utils;
|
||||
using Serein.Script.Node;
|
||||
using Serein.Script.Node.FlowControl;
|
||||
using Serein.Script.Symbol;
|
||||
using System;
|
||||
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)
|
||||
{
|
||||
NodeSymbolInfos.Clear();
|
||||
//NodeSymbolInfos.Clear();
|
||||
for (int i = 0; i < astNode.Statements.Count; 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>
|
||||
@@ -302,6 +218,20 @@ namespace Serein.Script
|
||||
return resultType;
|
||||
}
|
||||
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: // 类型定义
|
||||
Type AnalysisClassTypeDefinitionNode(ClassTypeDefinitionNode classTypeDefinitionNode)
|
||||
{
|
||||
@@ -331,18 +261,18 @@ namespace Serein.Script
|
||||
return resultType;
|
||||
}
|
||||
return AnalysisObjectInstantiationNode(objectInstantiationNode);
|
||||
case ObjectMemberExpressionNode objectMemberExpressionNode: // 类型表达式(链式调用)
|
||||
Type AnalysisObjectMemberExpressionNode(ObjectMemberExpressionNode objectMemberExpressionNode)
|
||||
case ExpressionNode expressionNode: // 类型表达式(链式调用)
|
||||
Type AnalysisObjectMemberExpressionNode(ExpressionNode expressionNode)
|
||||
{
|
||||
// 1. 对象成员获取 MemberAccessNode
|
||||
// 2. 对象方法调用 MemberFunctionCallNode
|
||||
// 3. 对象集合成员获取 CollectionIndexNode
|
||||
Type? resultType = Analysis(objectMemberExpressionNode.Value);
|
||||
NodeSymbolInfos[objectMemberExpressionNode.Value] = resultType;
|
||||
NodeSymbolInfos[objectMemberExpressionNode] = resultType;
|
||||
Type? resultType = Analysis(expressionNode.Value);
|
||||
NodeSymbolInfos[expressionNode.Value] = resultType;
|
||||
NodeSymbolInfos[expressionNode] = resultType;
|
||||
return resultType;
|
||||
}
|
||||
return AnalysisObjectMemberExpressionNode(objectMemberExpressionNode);
|
||||
return AnalysisObjectMemberExpressionNode(expressionNode);
|
||||
case 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)
|
||||
{
|
||||
switch (node)
|
||||
@@ -450,13 +480,15 @@ namespace Serein.Script
|
||||
break;
|
||||
case BinaryOperationNode binaryOperationNode: // 二元运算操作
|
||||
break;
|
||||
case CollectionAssignmentNode collectionAssignmentNode:
|
||||
break;
|
||||
case CollectionIndexNode collectionIndexNode: // 集合类型操作
|
||||
break;
|
||||
case ClassTypeDefinitionNode classTypeDefinitionNode: // 类型定义
|
||||
break;
|
||||
case ObjectInstantiationNode objectInstantiationNode: // 类型实例化
|
||||
break;
|
||||
case ObjectMemberExpressionNode objectMemberExpressionNode: // 类型表达式(链式调用)
|
||||
case ExpressionNode expressionNode: // 类型表达式(链式调用)
|
||||
break;
|
||||
case MemberAccessNode memberAccessNode: // 对象成员访问
|
||||
break;
|
||||
@@ -472,6 +504,9 @@ namespace Serein.Script
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取某个集合类型支持的索引参数类型
|
||||
/// </summary>
|
||||
|
||||
@@ -17,6 +17,8 @@ using Serein.Workbench.Tool;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using Serein.Library.Api;
|
||||
using Serein.Workbench.Node.ViewModel;
|
||||
using Serein.Workbench.Themes;
|
||||
|
||||
namespace Serein.Workbench.Node.View
|
||||
{
|
||||
@@ -39,6 +41,7 @@ namespace Serein.Workbench.Node.View
|
||||
return pen;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 入参控件
|
||||
@@ -135,7 +138,6 @@ namespace Serein.Workbench.Node.View
|
||||
{
|
||||
AddOrRemoveParamsAction = RemoveParamAsync;
|
||||
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);
|
||||
}
|
||||
private void RemoveParamAsync()
|
||||
private void RemoveParamAsync() // 移除当前选定的入参连接器
|
||||
{
|
||||
this.MyNode.Env.FlowEdit.ChangeParameter(MyNode.Guid, false, ArgIndex);
|
||||
}
|
||||
@@ -194,18 +196,41 @@ namespace Serein.Workbench.Node.View
|
||||
|
||||
|
||||
#region 控件属性,所在的节点
|
||||
public static readonly DependencyProperty NodeProperty =
|
||||
/* public static readonly DependencyProperty NodeProperty =
|
||||
DependencyProperty.Register(nameof(MyNode), typeof(IFlowNode), typeof(JunctionControlBase), new PropertyMetadata(default(IFlowNode)));
|
||||
//public NodeModelBase NodeModel;
|
||||
|
||||
/// <summary>
|
||||
/// 所在的节点
|
||||
/// </summary>
|
||||
public IFlowNode MyNode
|
||||
{
|
||||
get { return (IFlowNode)GetValue(NodeProperty); }
|
||||
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
|
||||
|
||||
#region 控件属性,连接器类型
|
||||
@@ -253,13 +278,8 @@ namespace Serein.Workbench.Node.View
|
||||
{
|
||||
if(_isMouseOver != value)
|
||||
{
|
||||
if(flowNodeService is not null)
|
||||
{
|
||||
|
||||
flowNodeService.ConnectingData.CurrentJunction = this;
|
||||
}
|
||||
|
||||
_isMouseOver = value;
|
||||
InvalidateVisual();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -326,7 +346,11 @@ namespace Serein.Workbench.Node.View
|
||||
|
||||
//if (IsMouseOver) return;
|
||||
IsMouseOver = true;
|
||||
|
||||
|
||||
flowNodeService.ConnectingData.CurrentJunction = this;
|
||||
InvalidateVisual();
|
||||
|
||||
//Debug.WriteLine(NodeGuid);
|
||||
//this.InvalidateVisual();
|
||||
}
|
||||
|
||||
@@ -339,7 +363,8 @@ namespace Serein.Workbench.Node.View
|
||||
{
|
||||
IsMouseOver = false;
|
||||
e.Handled = true;
|
||||
|
||||
flowNodeService.ConnectingData.CurrentJunction = this;
|
||||
InvalidateVisual();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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))
|
||||
{
|
||||
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
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Serein.Workbench.Node.View
|
||||
|
||||
#region 控件属性,对应的参数
|
||||
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>
|
||||
/// 所在的节点
|
||||
|
||||
@@ -62,15 +62,15 @@
|
||||
<ColumnDefinition Width="auto"/>
|
||||
</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" >
|
||||
<TextBlock Text="{Binding NodeModel.DisplayName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center"/>
|
||||
</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>
|
||||
|
||||
<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"
|
||||
Visibility="{Binding NodeModel.DebugSetting.IsProtectionParameter, Mode=TwoWay,
|
||||
@@ -90,7 +90,7 @@
|
||||
</Border>
|
||||
|
||||
<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>
|
||||
</Grid>
|
||||
|
||||
|
||||
@@ -18,10 +18,10 @@ namespace Serein.Workbench.Node.View
|
||||
{
|
||||
DataContext = viewModel;
|
||||
InitializeComponent();
|
||||
if(ExecuteJunctionControl.MyNode != null)
|
||||
/*if(ExecuteJunctionControl.MyNode != null)
|
||||
{
|
||||
ExecuteJunctionControl.MyNode.Guid = viewModel.NodeModel.Guid;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -37,11 +37,11 @@
|
||||
<ColumnDefinition Width="auto"/>
|
||||
</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">
|
||||
<TextBlock Text="{Binding NodeModel.DisplayName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center"/>
|
||||
</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>
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
<ColumnDefinition Width="20"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</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}-->
|
||||
<TextBox Grid.Column="2" MinWidth="50" Text="{Binding NodeModel.ExplicitData, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
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}"
|
||||
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>
|
||||
|
||||
@@ -3,6 +3,7 @@ using Serein.Library.Api;
|
||||
using Serein.Workbench.Api;
|
||||
using Serein.Workbench.Extension;
|
||||
using Serein.Workbench.Tool;
|
||||
using Serein.Workbench.ViewModels;
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Windows;
|
||||
@@ -260,17 +261,17 @@ namespace Serein.Workbench.Node.View
|
||||
|
||||
//
|
||||
Canvas.Children.Remove(BezierLine);
|
||||
var env = Start.MyNode.Env;
|
||||
var canvasGuid = Start.MyNode.CanvasDetails.Guid;
|
||||
var env = App.GetService<IFlowEnvironment>();
|
||||
var canvasGuid = ((FlowCanvasViewModel)(Canvas.DataContext)).Model.Guid;
|
||||
var jct = Start.JunctionType.ToConnectyionType();
|
||||
var jctEnd = End.JunctionType.ToConnectyionType();
|
||||
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)
|
||||
{
|
||||
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>
|
||||
public void Topping()
|
||||
{
|
||||
var env = Start.MyNode.Env;
|
||||
var env = App.GetService<IFlowEnvironment>();
|
||||
if (Start.JunctionType.ToConnectyionType() == JunctionOfConnectionType.Invoke)
|
||||
{
|
||||
env.FlowEdit.SetConnectPriorityInvoke(Start.MyNode.Guid, End.MyNode.Guid, InvokeType);
|
||||
env.FlowEdit.SetConnectPriorityInvoke(Start.NodeGuid, End.NodeGuid, InvokeType);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,11 +25,11 @@
|
||||
<ColumnDefinition Width="auto"/>
|
||||
</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">
|
||||
<TextBlock Text="{Binding NodeModel.DisplayName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center"/>
|
||||
</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.Row="1" Background="#FEFAF4">
|
||||
@@ -38,9 +38,9 @@
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
</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>
|
||||
<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>
|
||||
|
||||
@@ -43,16 +43,16 @@
|
||||
<ColumnDefinition Width="auto"/>
|
||||
</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" >
|
||||
<TextBlock Text="{Binding NodeModel.DisplayName, Mode=TwoWay}" HorizontalAlignment="Center"/>
|
||||
</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>
|
||||
|
||||
<!--方法描述-->
|
||||
<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"
|
||||
Visibility="{Binding NodeModel.DebugSetting.IsProtectionParameter, Converter={StaticResource InvertedBoolConverter},ConverterParameter=Normal}" />
|
||||
@@ -74,7 +74,7 @@
|
||||
</Border>
|
||||
|
||||
<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>
|
||||
</Grid>
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
<ColumnDefinition Width="*"/>
|
||||
</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">
|
||||
|
||||
<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"/>
|
||||
<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>
|
||||
<MultiBinding Converter="{StaticResource MethodDetailsSelector}">
|
||||
<Binding Path="FlowCallNode.IsShareParam" UpdateSourceTrigger="PropertyChanged"/>
|
||||
|
||||
@@ -35,11 +35,11 @@
|
||||
<ColumnDefinition Width="auto"/>
|
||||
</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">
|
||||
<TextBlock Text="{Binding NodeModel.DisplayName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center"/>
|
||||
</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>
|
||||
|
||||
|
||||
@@ -30,11 +30,11 @@
|
||||
<ColumnDefinition Width="auto"/>
|
||||
</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">
|
||||
<TextBlock Text="C#脚本节点" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</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>
|
||||
|
||||
|
||||
@@ -29,11 +29,11 @@
|
||||
<ColumnDefinition Width="auto"/>
|
||||
</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">
|
||||
<TextBlock Text="{Binding NodeModel.DisplayName, Mode=TwoWay}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</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>
|
||||
|
||||
@@ -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 CommandExecuting}" Height="17.2"></Button>
|
||||
<!--<Button Content="刷新 " Command="{Binding CommandCopyDataExp}" Height="17.2" Margin="2,0,0,0"></Button>-->
|
||||
</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>
|
||||
<Grid Grid.Row="3" >
|
||||
<Grid.ColumnDefinitions>
|
||||
@@ -68,11 +67,11 @@
|
||||
<TextBlock Text="result ->" HorizontalAlignment="Center" VerticalAlignment="Center" />
|
||||
</Border>
|
||||
<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 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>
|
||||
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</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">
|
||||
<TextBlock Text="{Binding NodeModel.DisplayName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center"/>
|
||||
</Border>
|
||||
|
||||
@@ -83,22 +83,32 @@ namespace Serein.Workbench.Node.ViewModel
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 选择画布发生改变
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
partial void OnSelectCanvasChanged(FlowCanvasViewModel value)
|
||||
{
|
||||
FlowCallNode.ResetTargetNode();
|
||||
FlowCallNode.ResetTargetNode(); // 改变画布直接重置
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 选择的节点发生改变
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
partial void OnSelectNodeChanged(IFlowNode value)
|
||||
{
|
||||
if(value is null)
|
||||
{
|
||||
FlowCallNode.ResetTargetNode();
|
||||
FlowCallNode.ResetTargetNode(); // 如果是不选择了,则重置一下
|
||||
return;
|
||||
}
|
||||
FlowCallNode.SetTargetNode(value.Guid);
|
||||
FlowCallNode.SetTargetNode(value.Guid); // 重新设置目标节点
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 刷新可选画布
|
||||
/// </summary>
|
||||
private void RershCanvass()
|
||||
{
|
||||
var canvass = flowNodeService.FlowCanvass.Select(f => (FlowCanvasViewModel)f.DataContext).ToArray(); // .Where(f => f.Model.PublicNodes.Count > 0)
|
||||
|
||||
@@ -345,10 +345,6 @@ namespace Serein.Workbench.Services
|
||||
}
|
||||
#endregion
|
||||
|
||||
//if (nodeModel.ControlType == NodeControlType.FlowCall)
|
||||
//{
|
||||
// Console.WriteLine("test");
|
||||
//}
|
||||
|
||||
#region 创建控件
|
||||
|
||||
|
||||
@@ -19,13 +19,13 @@
|
||||
<Style TargetType="{x:Type local:MethodDetailsControl}">
|
||||
<Setter Property="Template">
|
||||
<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.ItemTemplate>
|
||||
<DataTemplate DataType="serein:ParameterData">
|
||||
<Grid DataContext="{Binding}">
|
||||
<Grid DataContext="{Binding}" >
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
@@ -35,12 +35,15 @@
|
||||
<ColumnDefinition Width="auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<!--连接控制器-->
|
||||
<view:ArgJunctionControl x:Name="ArgJunctionControl" Grid.Column="0" ArgIndex="{Binding Index}" MyNode="{Binding NodeModel}" />
|
||||
<!--参数索引提示-->
|
||||
<!--<TextBlock Grid.Column="1" Text="{Binding Index,StringFormat=agr{0}}" Margin="2,0,2,0" VerticalAlignment="Center"/>-->
|
||||
|
||||
<view:ArgJunctionControl x:Name="ArgJunctionControl" Grid.Column="0" ArgIndex="{Binding Index}"
|
||||
NodeViewModel="{Binding NodeViewModel,
|
||||
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"/>
|
||||
|
||||
|
||||
<!--入参参数名称-->
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using Serein.Library;
|
||||
using Serein.Workbench.Node;
|
||||
using Serein.Workbench.Node.View;
|
||||
using Serein.Workbench.Node.ViewModel;
|
||||
using System.Collections;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
@@ -98,9 +100,21 @@ namespace Serein.Workbench.Themes
|
||||
set { SetValue(MethodDetailsProperty, value); }
|
||||
}
|
||||
|
||||
|
||||
public static readonly DependencyProperty MethodDetailsProperty = DependencyProperty.Register(nameof(MethodDetails), typeof(MethodDetails),
|
||||
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
|
||||
|
||||
|
||||
|
||||
@@ -190,8 +190,8 @@ namespace Serein.Workbench.Views
|
||||
|
||||
var connectionControl = Connections.FirstOrDefault(c =>
|
||||
{
|
||||
if (c.Start.MyNode.Guid != e.FromNodeGuid
|
||||
|| c.End.MyNode.Guid != e.ToNodeGuid)
|
||||
if (c.Start.NodeGuid != e.FromNodeGuid
|
||||
|| c.End.NodeGuid != e.ToNodeGuid)
|
||||
{
|
||||
return false; // 不是当前连接
|
||||
}
|
||||
@@ -312,33 +312,6 @@ namespace Serein.Workbench.Views
|
||||
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>
|
||||
/// 尝试判断是否为区域,如果是,将节点放置在区域中
|
||||
@@ -388,15 +361,11 @@ namespace Serein.Workbench.Views
|
||||
#region 接口实现
|
||||
private IFlowCanvas Api => this;
|
||||
|
||||
public string Guid
|
||||
{
|
||||
get
|
||||
{
|
||||
return ViewModel.Model.Guid;
|
||||
}
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public string Guid => ViewModel.Model.Guid;
|
||||
|
||||
public string Name => ViewModel.Model.Name;
|
||||
/// <inheritdoc/>
|
||||
public new string Name => ViewModel.Model.Name;
|
||||
FlowCanvasDetails IFlowCanvas.Model => ViewModel.Model;
|
||||
void IFlowCanvas.Remove(NodeControlBase nodeControl)
|
||||
{
|
||||
@@ -559,8 +528,8 @@ namespace Serein.Workbench.Views
|
||||
JunctionControlBase endJunction = IToJunction.ExecuteJunction;
|
||||
|
||||
var removeConnections = Connections.Where(c =>
|
||||
c.Start.MyNode.Guid == startJunction.MyNode.Guid
|
||||
&& c.End.MyNode.Guid == endJunction.MyNode.Guid
|
||||
c.Start.NodeGuid == startJunction.NodeGuid
|
||||
&& c.End.NodeGuid == endJunction.NodeGuid
|
||||
&& (c.Start.JunctionType.ToConnectyionType() == JunctionOfConnectionType.Arg
|
||||
|| c.End.JunctionType.ToConnectyionType() == JunctionOfConnectionType.Arg))
|
||||
.ToList();
|
||||
@@ -941,8 +910,8 @@ namespace Serein.Workbench.Views
|
||||
|
||||
flowEnvironment.FlowEdit.ConnectInvokeNode(
|
||||
canvasGuid,
|
||||
cd.StartJunction.MyNode.Guid,
|
||||
cd.CurrentJunction.MyNode.Guid,
|
||||
cd.StartJunction.NodeGuid,
|
||||
cd.CurrentJunction.NodeGuid,
|
||||
cd.StartJunction.JunctionType,
|
||||
cd.CurrentJunction.JunctionType,
|
||||
cd.ConnectionInvokeType);
|
||||
@@ -952,23 +921,31 @@ namespace Serein.Workbench.Views
|
||||
#region 参数来源关系创建
|
||||
else if (cd.Type == JunctionOfConnectionType.Arg)
|
||||
{
|
||||
var canvasGuid = this.Guid;
|
||||
var argIndex = 0;
|
||||
var startNodeGuid = "";
|
||||
var toNodeGuid = "";
|
||||
if (cd.StartJunction is ArgJunctionControl argJunction1)
|
||||
{
|
||||
startNodeGuid = cd.CurrentJunction.NodeGuid;
|
||||
argIndex = argJunction1.ArgIndex;
|
||||
toNodeGuid = argJunction1.NodeGuid;
|
||||
}
|
||||
else if (cd.CurrentJunction is ArgJunctionControl argJunction2)
|
||||
{
|
||||
startNodeGuid = cd.StartJunction.NodeGuid;
|
||||
startNodeGuid = cd.StartJunction.NodeGuid;
|
||||
argIndex = argJunction2.ArgIndex;
|
||||
toNodeGuid = argJunction2.NodeGuid;
|
||||
}
|
||||
var canvasGuid = this.Guid;
|
||||
|
||||
|
||||
flowEnvironment.FlowEdit.ConnectArgSourceNode(
|
||||
canvasGuid,
|
||||
cd.StartJunction.MyNode.Guid,
|
||||
cd.CurrentJunction.MyNode.Guid,
|
||||
cd.StartJunction.JunctionType,
|
||||
cd.CurrentJunction.JunctionType,
|
||||
startNodeGuid,
|
||||
toNodeGuid,
|
||||
JunctionType.ReturnData,
|
||||
JunctionType.ArgData,
|
||||
cd.ConnectionArgSourceType,
|
||||
argIndex);
|
||||
}
|
||||
@@ -1335,7 +1312,7 @@ namespace Serein.Workbench.Views
|
||||
nodeControl.MouseLeftButtonDown += Block_MouseLeftButtonDown;
|
||||
nodeControl.MouseMove += Block_MouseMove;
|
||||
nodeControl.MouseLeftButtonUp += Block_MouseLeftButtonUp;
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1367,11 +1344,18 @@ namespace Serein.Workbench.Views
|
||||
if (IsSelectControl)
|
||||
return;
|
||||
|
||||
if(sender is not NodeControlBase nodeControlMain)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
flowNodeService.CurrentSelectNodeControl = nodeControlMain;
|
||||
|
||||
if (IsControlDragging && !flowNodeService.ConnectingData.IsCreateing) // 如果正在拖动控件
|
||||
{
|
||||
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
|
||||
{ // 单个节点移动
|
||||
if (sender is not NodeControlBase nodeControl)
|
||||
{
|
||||
return;
|
||||
}
|
||||
double deltaX = currentPosition.X - startControlDragPoint.X; // 计算X轴方向的偏移量
|
||||
double deltaY = currentPosition.Y - startControlDragPoint.Y; // 计算Y轴方向的偏移量
|
||||
double newLeft = Canvas.GetLeft(nodeControl) + deltaX; // 新的左边距
|
||||
double newTop = Canvas.GetTop(nodeControl) + deltaY; // 新的上边距
|
||||
double newLeft = Canvas.GetLeft(nodeControlMain) + deltaX; // 新的左边距
|
||||
double newTop = Canvas.GetTop(nodeControlMain) + deltaY; // 新的上边距
|
||||
|
||||
// 如果被移动的控件接触到画布边缘,则限制移动范围
|
||||
var canvasModel = nodeControl.FlowCanvas.Model;
|
||||
var canvasWidth = canvasModel.Width - nodeControl.ActualWidth - 10;
|
||||
var canvasHeight= canvasModel.Height - nodeControl.ActualHeight - 10;
|
||||
var canvasModel = nodeControlMain.FlowCanvas.Model;
|
||||
var canvasWidth = canvasModel.Width - nodeControlMain.ActualWidth - 10;
|
||||
var canvasHeight= canvasModel.Height - nodeControlMain.ActualHeight - 10;
|
||||
newLeft = newLeft < 5 ? 5 : newLeft > canvasWidth ? canvasWidth : newLeft;
|
||||
newTop = newTop < 5 ? 5 : newTop > canvasHeight ? canvasHeight : newTop;
|
||||
|
||||
var node = nodeControl.ViewModel.NodeModel;
|
||||
var node = nodeControlMain.ViewModel.NodeModel;
|
||||
node.Position.X = newLeft;
|
||||
node.Position.Y = newTop;
|
||||
|
||||
//this.flowEnvironment.MoveNode(Guid, nodeControl.ViewModel.NodeModel.Guid, newLeft, newTop); // 移动节点
|
||||
nodeControl.UpdateLocationConnections();
|
||||
nodeControlMain.UpdateLocationConnections();
|
||||
}
|
||||
startControlDragPoint = currentPosition; // 更新起始点位置
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user