mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-03 00:00:49 +08:00
重新设计了项目的保存文件结构
This commit is contained in:
@@ -124,6 +124,11 @@ namespace Serein.Library
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[Description("base")]
|
[Description("base")]
|
||||||
Script,
|
Script,
|
||||||
|
/// <summary>
|
||||||
|
/// C#脚本节点
|
||||||
|
/// </summary>
|
||||||
|
[Description("base")]
|
||||||
|
NetScript,
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,17 +65,21 @@ namespace Serein.Library
|
|||||||
}
|
}
|
||||||
this.DebugSetting.NodeModel = null;
|
this.DebugSetting.NodeModel = null;
|
||||||
this.DebugSetting = null;
|
this.DebugSetting = null;
|
||||||
foreach (var pd in this.MethodDetails.ParameterDetailss)
|
if(this.MethodDetails.ParameterDetailss != null)
|
||||||
{
|
{
|
||||||
pd.DataValue = null;
|
foreach (var pd in this.MethodDetails.ParameterDetailss)
|
||||||
pd.Items = null;
|
{
|
||||||
pd.NodeModel = null;
|
pd.DataValue = null;
|
||||||
pd.ExplicitType = null;
|
pd.Items = null;
|
||||||
pd.DataType = null;
|
pd.NodeModel = null;
|
||||||
pd.Name = null;
|
pd.ExplicitType = null;
|
||||||
pd.ArgDataSourceNodeGuid = null;
|
pd.DataType = null;
|
||||||
pd.InputType = ParameterValueInputType.Input;
|
pd.Name = null;
|
||||||
|
pd.ArgDataSourceNodeGuid = null;
|
||||||
|
pd.InputType = ParameterValueInputType.Input;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.MethodDetails.ParameterDetailss = null;
|
this.MethodDetails.ParameterDetailss = null;
|
||||||
this.MethodDetails.ActingInstance = null;
|
this.MethodDetails.ActingInstance = null;
|
||||||
this.MethodDetails.NodeModel = null;
|
this.MethodDetails.NodeModel = null;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ using System.Text;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
|
|
||||||
namespace Serein.Library.Utils
|
namespace Serein.Library
|
||||||
{
|
{
|
||||||
public static class SereinEnv
|
public static class SereinEnv
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using Serein.Library.Utils.SereinExpression;
|
|||||||
using Serein.NodeFlow.Model;
|
using Serein.NodeFlow.Model;
|
||||||
using Serein.NodeFlow.Tool;
|
using Serein.NodeFlow.Tool;
|
||||||
using System.Reactive;
|
using System.Reactive;
|
||||||
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Serein.NodeFlow.Env
|
namespace Serein.NodeFlow.Env
|
||||||
@@ -52,6 +53,7 @@ namespace Serein.NodeFlow.Env
|
|||||||
NodeMVVMManagement.RegisterModel(NodeControlType.ConditionRegion, typeof(CompositeConditionNode)); // 条件区域
|
NodeMVVMManagement.RegisterModel(NodeControlType.ConditionRegion, typeof(CompositeConditionNode)); // 条件区域
|
||||||
NodeMVVMManagement.RegisterModel(NodeControlType.GlobalData, typeof(SingleGlobalDataNode)); // 全局数据节点
|
NodeMVVMManagement.RegisterModel(NodeControlType.GlobalData, typeof(SingleGlobalDataNode)); // 全局数据节点
|
||||||
NodeMVVMManagement.RegisterModel(NodeControlType.Script, typeof(SingleScriptNode)); // 脚本节点
|
NodeMVVMManagement.RegisterModel(NodeControlType.Script, typeof(SingleScriptNode)); // 脚本节点
|
||||||
|
NodeMVVMManagement.RegisterModel(NodeControlType.NetScript, typeof(SingleNetScriptNode)); // 脚本节点
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 注册基本服务类
|
#region 注册基本服务类
|
||||||
@@ -647,9 +649,30 @@ namespace Serein.NodeFlow.Env
|
|||||||
{
|
{
|
||||||
SereinEnv.WriteLine(InfoType.ERROR, $"无法加载DLL文件:{ex}");
|
SereinEnv.WriteLine(InfoType.ERROR, $"无法加载DLL文件:{ex}");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 加载本地程序集
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="assembly"></param>
|
||||||
|
public void LoadLibrary(Assembly assembly)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
(var libraryInfo, var mdInfos) = FlowLibraryManagement.LoadLibraryOfPath(assembly);
|
||||||
|
if (mdInfos.Count > 0)
|
||||||
|
{
|
||||||
|
UIContextOperation?.Invoke(() => OnDllLoad?.Invoke(new LoadDllEventArgs(libraryInfo, mdInfos))); // 通知UI创建dll面板显示
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
SereinEnv.WriteLine(InfoType.ERROR, $"无法加载DLL文件:{ex}");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 移除DLL
|
/// 移除DLL
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ namespace Serein.NodeFlow
|
|||||||
|
|
||||||
flipflopNodes = nodes.Where(it => it.MethodDetails?.MethodDynamicType == NodeType.Flipflop && it.IsStart == false)
|
flipflopNodes = nodes.Where(it => it.MethodDetails?.MethodDynamicType == NodeType.Flipflop && it.IsStart == false)
|
||||||
.Select(it => (SingleFlipflopNode)it)
|
.Select(it => (SingleFlipflopNode)it)
|
||||||
.Where(node => node is SingleFlipflopNode flipflopNode && flipflopNode.NotExitPreviousNode())
|
.Where(node => node.DebugSetting.IsEnable && node is SingleFlipflopNode flipflopNode && flipflopNode.NotExitPreviousNode())
|
||||||
.ToList();// 获取需要再运行开始之前启动的触发器节点
|
.ToList();// 获取需要再运行开始之前启动的触发器节点
|
||||||
runNodeMd = nodes.Select(item => item.MethodDetails).ToList(); // 获取环境中所有节点的方法信息
|
runNodeMd = nodes.Select(item => item.MethodDetails).ToList(); // 获取环境中所有节点的方法信息
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ namespace Serein.NodeFlow.Model
|
|||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Expression Operation - 表达式操作
|
/// Expression Operation - 表达式操作
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[NodeProperty(ValuePath = NodeValuePath.Node)]
|
[NodeProperty(ValuePath = NodeValuePath.Node)]
|
||||||
@@ -51,7 +51,11 @@ namespace Serein.NodeFlow.Model
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private NodeModelBase? DataNode;
|
private NodeModelBase? DataNode;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 有节点被放置
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="nodeModel"></param>
|
||||||
|
/// <returns></returns>
|
||||||
public bool PlaceNode(NodeModelBase nodeModel)
|
public bool PlaceNode(NodeModelBase nodeModel)
|
||||||
{
|
{
|
||||||
if(DataNode is null)
|
if(DataNode is null)
|
||||||
|
|||||||
122
NodeFlow/Model/SingleNetScriptNode.cs
Normal file
122
NodeFlow/Model/SingleNetScriptNode.cs
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
using Serein.Library;
|
||||||
|
using Serein.Library.Api;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Dynamic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Serein.NodeFlow.Model
|
||||||
|
{
|
||||||
|
|
||||||
|
[NodeProperty(ValuePath = NodeValuePath.Node)]
|
||||||
|
public partial class SingleNetScriptNode : NodeModelBase
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 脚本代码
|
||||||
|
/// </summary>
|
||||||
|
[PropertyInfo(IsNotification = true)]
|
||||||
|
private string _script;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 功能提示
|
||||||
|
/// </summary>
|
||||||
|
[PropertyInfo(IsNotification = true)]
|
||||||
|
private string _tips = "写一下提示吧";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 依赖路径
|
||||||
|
/// </summary>
|
||||||
|
[PropertyInfo(IsNotification = true)]
|
||||||
|
private List<string> _libraryFilePaths;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public partial class SingleNetScriptNode
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 表达式节点是基础节点
|
||||||
|
/// </summary>
|
||||||
|
public override bool IsBase => true;
|
||||||
|
|
||||||
|
public SingleNetScriptNode(IFlowEnvironment environment) : base(environment)
|
||||||
|
{
|
||||||
|
this.Env = environment;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public override void OnCreating()
|
||||||
|
{
|
||||||
|
//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];
|
||||||
|
//md.ParamsArgIndex = 0;
|
||||||
|
//pd[0] = new ParameterDetails
|
||||||
|
//{
|
||||||
|
// Index = 0,
|
||||||
|
// Name = "object",
|
||||||
|
// IsExplicitData = true,
|
||||||
|
// DataValue = string.Empty,
|
||||||
|
// DataType = typeof(object),
|
||||||
|
// ExplicitType = typeof(object),
|
||||||
|
// ArgDataSourceNodeGuid = string.Empty,
|
||||||
|
// ArgDataSourceType = ConnectionArgSourceType.GetPreviousNodeData,
|
||||||
|
// NodeModel = this,
|
||||||
|
// InputType = ParameterValueInputType.Input,
|
||||||
|
// Items = null,
|
||||||
|
// IsParams = true,
|
||||||
|
// Description = "脚本节点入参"
|
||||||
|
|
||||||
|
//};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 导出脚本代码
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="nodeInfo"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public override NodeInfo SaveCustomData(NodeInfo nodeInfo)
|
||||||
|
{
|
||||||
|
dynamic data = new ExpandoObject();
|
||||||
|
data.Script = this.Script ?? "";
|
||||||
|
nodeInfo.CustomData = data;
|
||||||
|
return nodeInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 加载自定义数据
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="nodeInfo"></param>
|
||||||
|
public override void LoadCustomData(NodeInfo nodeInfo)
|
||||||
|
{
|
||||||
|
this.Script = nodeInfo.CustomData?.Script ?? "";
|
||||||
|
|
||||||
|
// 更新变量名
|
||||||
|
//for (int i = 0; i < Math.Min(this.MethodDetails.ParameterDetailss.Length, nodeInfo.ParameterData.Length); i++)
|
||||||
|
//{
|
||||||
|
// this.MethodDetails.ParameterDetailss[i].Name = nodeInfo.ParameterData[i].ArgName;
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,13 +28,11 @@ namespace Serein.NodeFlow.Model
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class SingleScriptNode : NodeModelBase
|
public partial class SingleScriptNode : NodeModelBase
|
||||||
{
|
{
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 脚本节点是基础节点
|
/// 脚本节点是基础节点
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public override bool IsBase => true;
|
public override bool IsBase => true;
|
||||||
|
|
||||||
|
|
||||||
private IScriptFlowApi ScriptFlowApi { get; }
|
private IScriptFlowApi ScriptFlowApi { get; }
|
||||||
|
|
||||||
private ASTNode mainNode;
|
private ASTNode mainNode;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ using System.Reflection;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Serein.Library.Utils
|
namespace Serein.NodeFlow.Tool
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 动态编译
|
/// 动态编译
|
||||||
@@ -22,7 +22,7 @@ namespace Serein.Library.Utils
|
|||||||
{
|
{
|
||||||
// 默认添加当前 AppDomain 加载的所有程序集
|
// 默认添加当前 AppDomain 加载的所有程序集
|
||||||
var defaultReferences = AppDomain.CurrentDomain.GetAssemblies()
|
var defaultReferences = AppDomain.CurrentDomain.GetAssemblies()
|
||||||
.Where(a => !string.IsNullOrEmpty(a.Location)) // a.IsDynamic 动态程序集
|
.Where(a => !string.IsNullOrEmpty(a.Location)) // a.IsDynamic 动态程序集
|
||||||
.Select(a => MetadataReference.CreateFromFile(a.Location));
|
.Select(a => MetadataReference.CreateFromFile(a.Location));
|
||||||
|
|
||||||
|
|
||||||
@@ -64,17 +64,28 @@ namespace Serein.Library.Utils
|
|||||||
public Assembly Compile(string code, string assemblyName = null)
|
public Assembly Compile(string code, string assemblyName = null)
|
||||||
{
|
{
|
||||||
SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(code);
|
SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(code);
|
||||||
if(assemblyName is null)
|
if (assemblyName is null)
|
||||||
{
|
{
|
||||||
assemblyName = Path.GetRandomFileName(); // 生成随机程序集名称
|
assemblyName = Path.GetRandomFileName(); // 生成随机程序集名称
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var temp_dir = Path.Combine(Directory.GetCurrentDirectory(), "temp");
|
||||||
|
if (!Directory.Exists(temp_dir))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(temp_dir);
|
||||||
|
}
|
||||||
|
var savePath = Path.Combine(temp_dir, $"{assemblyName}.dll");
|
||||||
|
|
||||||
|
var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary);
|
||||||
|
|
||||||
|
|
||||||
CSharpCompilation compilation = CSharpCompilation.Create(
|
CSharpCompilation compilation = CSharpCompilation.Create(
|
||||||
assemblyName,
|
assemblyName,
|
||||||
new[] { syntaxTree },
|
new[] { syntaxTree },
|
||||||
_references,
|
_references,
|
||||||
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
|
options
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
using (var ms = new MemoryStream())
|
using (var ms = new MemoryStream())
|
||||||
@@ -90,11 +101,27 @@ namespace Serein.Library.Utils
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
ms.Seek(0, SeekOrigin.Begin);
|
ms.Seek(0, SeekOrigin.Begin);
|
||||||
return Assembly.Load(ms.ToArray());
|
var assembly = Assembly.Load(ms.ToArray());
|
||||||
|
var t1 = assembly.Location;
|
||||||
|
var t = assembly.GetType().Assembly.Location;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 保存
|
||||||
|
|
||||||
|
compilation.Emit(savePath);
|
||||||
|
return assembly;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Save()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -26,19 +26,33 @@ namespace Serein.NodeFlow
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class FlowLibrary
|
public class FlowLibrary
|
||||||
{
|
{
|
||||||
private readonly Assembly assembly;
|
private readonly Assembly _assembly;
|
||||||
private readonly Action actionOfUnloadAssmbly;
|
|
||||||
|
|
||||||
public FlowLibrary(Assembly assembly,
|
|
||||||
Action actionOfUnloadAssmbly)
|
|
||||||
|
//private readonly Action actionOfUnloadAssmbly;
|
||||||
|
/*, Action actionOfUnloadAssmbly*/
|
||||||
|
//this.actionOfUnloadAssmbly = actionOfUnloadAssmbly;
|
||||||
|
|
||||||
|
public FlowLibrary(Assembly assembly)
|
||||||
{
|
{
|
||||||
this.assembly = assembly;
|
this._assembly = assembly;
|
||||||
this.actionOfUnloadAssmbly = actionOfUnloadAssmbly;
|
this.FullName = Path.GetFileName(_assembly.Location);
|
||||||
|
|
||||||
|
this.FilePath = _assembly.Location;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string FullName => assembly.GetName().FullName;
|
public FlowLibrary(Assembly assembly,
|
||||||
|
string filePath)
|
||||||
|
{
|
||||||
|
this._assembly = assembly;
|
||||||
|
this.FullName = Path.GetFileName(filePath); ;
|
||||||
|
this.FilePath = filePath;
|
||||||
|
}
|
||||||
|
|
||||||
public string Version => assembly.GetName().Version.ToString();
|
public string FullName { get; private set; }
|
||||||
|
|
||||||
|
public string FilePath { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 加载程序集时创建的方法描述
|
/// 加载程序集时创建的方法描述
|
||||||
@@ -68,7 +82,7 @@ namespace Serein.NodeFlow
|
|||||||
DelegateDetailss.Clear();
|
DelegateDetailss.Clear();
|
||||||
RegisterTypes.Clear();
|
RegisterTypes.Clear();
|
||||||
MethodDetailss.Clear();
|
MethodDetailss.Clear();
|
||||||
actionOfUnloadAssmbly?.Invoke();
|
//actionOfUnloadAssmbly?.Invoke();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,11 +92,12 @@ namespace Serein.NodeFlow
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public NodeLibraryInfo ToInfo()
|
public NodeLibraryInfo ToInfo()
|
||||||
{
|
{
|
||||||
|
var assemblyName = _assembly.GetName().Name;
|
||||||
return new NodeLibraryInfo
|
return new NodeLibraryInfo
|
||||||
{
|
{
|
||||||
AssemblyName = assembly.GetName().Name,
|
AssemblyName = assemblyName,
|
||||||
FileName = Path.GetFileName(assembly.Location),
|
FileName = this.FullName,
|
||||||
FilePath = assembly.Location,
|
FilePath = this.FilePath,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -94,8 +109,9 @@ namespace Serein.NodeFlow
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="assembly">程序集本身</param>
|
/// <param name="assembly">程序集本身</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public bool LoadAssembly(Assembly assembly)
|
public bool LoadAssembly()
|
||||||
{
|
{
|
||||||
|
Assembly assembly = this._assembly;
|
||||||
#region 检查入参
|
#region 检查入参
|
||||||
|
|
||||||
// 加载DLL,创建 MethodDetails、实例作用对象、委托方法
|
// 加载DLL,创建 MethodDetails、实例作用对象、委托方法
|
||||||
|
|||||||
@@ -39,7 +39,36 @@ namespace Serein.NodeFlow.Tool
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public (NodeLibraryInfo, List<MethodDetailsInfo>) LoadLibraryOfPath(string libraryfilePath)
|
public (NodeLibraryInfo, List<MethodDetailsInfo>) LoadLibraryOfPath(string libraryfilePath)
|
||||||
{
|
{
|
||||||
return LoadDllNodeInfo(libraryfilePath);
|
|
||||||
|
var dir = Path.GetDirectoryName(libraryfilePath); // 获取目录路径
|
||||||
|
var sereinFlowBaseLibraryPath = Path.Combine(dir, SereinBaseLibrary);// 每个类库下面至少需要有“Serein.Library.dll”类库依赖
|
||||||
|
if (!Path.Exists(sereinFlowBaseLibraryPath))
|
||||||
|
{
|
||||||
|
throw new Exception($"从文件加载DLL失败,目标文件夹不存在{SereinBaseLibrary}文件" );
|
||||||
|
}
|
||||||
|
|
||||||
|
var flowAlc = new FlowLibraryAssemblyContext(sereinFlowBaseLibraryPath, Path.GetFileName(libraryfilePath));
|
||||||
|
var assembly = flowAlc.LoadFromAssemblyPath(libraryfilePath); // 加载指定路径的程序集
|
||||||
|
var reulst = LoadDllNodeInfo(assembly);
|
||||||
|
if(reulst.Item1 is null || reulst.Item2.Count == 0)
|
||||||
|
{
|
||||||
|
flowAlc?.Unload(); // 卸载程序集
|
||||||
|
flowAlc = null;
|
||||||
|
GC.Collect(); // 强制触发GC确保卸载成功
|
||||||
|
GC.WaitForPendingFinalizers();
|
||||||
|
throw new Exception("从文件加载DLL失败:"+ libraryfilePath);
|
||||||
|
}
|
||||||
|
return reulst;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 加载类库
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="assembly"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public (NodeLibraryInfo, List<MethodDetailsInfo>) LoadLibraryOfPath(Assembly assembly)
|
||||||
|
{
|
||||||
|
return LoadDllNodeInfo(assembly);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -206,84 +235,44 @@ namespace Serein.NodeFlow.Tool
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly static string SereinBaseLibrary = $"{nameof(Serein)}.{nameof(Serein.Library)}.dll";
|
public readonly static string SereinBaseLibrary = $"{nameof(Serein)}.{nameof(Serein.Library)}.dll";
|
||||||
|
|
||||||
private (NodeLibraryInfo, List<MethodDetailsInfo>) LoadDllNodeInfo(string dllFilePath)
|
private (NodeLibraryInfo, List<MethodDetailsInfo>) LoadDllNodeInfo(Assembly assembly)
|
||||||
{
|
{
|
||||||
var fileName = Path.GetFileName(dllFilePath); // 获取文件名
|
|
||||||
if (SereinBaseLibrary.Equals(fileName))
|
if (assembly.FullName?.ToString().Equals(typeof(IFlowEnvironment).Assembly.FullName?.ToString()) == true)
|
||||||
{
|
{
|
||||||
return LoadAssembly(typeof(IFlowEnvironment).Assembly, () => {
|
// 加载基础依赖
|
||||||
//SereinEnv.PrintInfo(InfoType.WRAN, "基础模块不能卸载");
|
return LoadAssembly(typeof(IFlowEnvironment).Assembly);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var dir = Path.GetDirectoryName(dllFilePath); // 获取目录路径
|
try
|
||||||
var sereinFlowBaseLibraryPath = Path.Combine(dir, SereinBaseLibrary);
|
|
||||||
// 每个类库下面至少需要有“Serein.Library.dll”类库依赖
|
|
||||||
|
|
||||||
//AssemblyLoader assemblyLoader = new AssemblyLoader(dllFilePath);
|
|
||||||
|
|
||||||
|
|
||||||
var flowAlc = new FlowLibraryAssemblyContext(sereinFlowBaseLibraryPath, fileName);
|
|
||||||
Action actionUnload = () =>
|
|
||||||
{
|
{
|
||||||
flowAlc?.Unload(); // 卸载程序集
|
var assembly_result = LoadAssembly(assembly);
|
||||||
flowAlc = null;
|
return assembly_result;
|
||||||
GC.Collect(); // 强制触发GC确保卸载成功
|
}
|
||||||
GC.WaitForPendingFinalizers();
|
catch (Exception)
|
||||||
};
|
{
|
||||||
var assembly = flowAlc.LoadFromAssemblyPath(dllFilePath); // 加载指定路径的程序集
|
return (null,[]);
|
||||||
var assembly_result = LoadAssembly(assembly, actionUnload);
|
}
|
||||||
return assembly_result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* var dir = Path.GetDirectoryName(dllFilePath); // 获取目录路径
|
|
||||||
var sereinFlowLibraryPath = Path.Combine(dir, SereinLibraryDll);
|
|
||||||
// 每个类库下面至少需要有“Serein.Library.dll”类库依赖
|
|
||||||
var flowAlc = new FlowLibraryAssemblyContext(sereinFlowLibraryPath, fileName);
|
|
||||||
Action actionUnload = () =>
|
|
||||||
{
|
|
||||||
flowAlc?.Unload(); // 卸载程序集
|
|
||||||
flowAlc = null;
|
|
||||||
GC.Collect(); // 强制触发GC确保卸载成功
|
|
||||||
GC.WaitForPendingFinalizers();
|
|
||||||
};
|
|
||||||
var assembly = flowAlc.LoadFromAssemblyPath(dllFilePath); // 加载指定路径的程序集
|
|
||||||
if (_myFlowLibrarys.ContainsKey(assembly.GetName().Name))
|
|
||||||
{
|
|
||||||
actionUnload.Invoke();
|
|
||||||
throw new Exception($"程序集[{assembly.GetName().FullName}]已经加载过!");
|
|
||||||
}
|
|
||||||
FlowLibrary flowLibrary = new FlowLibrary(assembly, actionUnload);
|
|
||||||
if (flowLibrary.LoadAssembly(assembly))
|
|
||||||
{
|
|
||||||
_myFlowLibrarys.TryAdd(assembly.GetName().Name, flowLibrary);
|
|
||||||
(NodeLibraryInfo, List<MethodDetailsInfo>) result = (flowLibrary.ToInfo(),
|
|
||||||
flowLibrary.MethodDetailss.Values.Select(md => md.ToInfo()).ToList());
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new Exception($"程序集[{assembly.GetName().FullName}]加载失败");
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private (NodeLibraryInfo, List<MethodDetailsInfo>) LoadAssembly(Assembly assembly,Action actionUnload)
|
private (NodeLibraryInfo, List<MethodDetailsInfo>) LoadAssembly(Assembly assembly)
|
||||||
{
|
{
|
||||||
if (_myFlowLibrarys.ContainsKey(assembly.GetName().Name))
|
if (_myFlowLibrarys.ContainsKey(assembly.GetName().Name))
|
||||||
{
|
{
|
||||||
actionUnload.Invoke();
|
|
||||||
throw new Exception($"程序集[{assembly.GetName().FullName}]已经加载过!");
|
throw new Exception($"程序集[{assembly.GetName().FullName}]已经加载过!");
|
||||||
}
|
}
|
||||||
|
|
||||||
FlowLibrary flowLibrary = new FlowLibrary(assembly, actionUnload);
|
FlowLibrary flowLibrary = new FlowLibrary(assembly);
|
||||||
var loadResult = flowLibrary.LoadAssembly(assembly); // 加载程序集
|
var loadResult = flowLibrary.LoadAssembly(); // 加载程序集
|
||||||
if (loadResult)
|
if (loadResult)
|
||||||
{
|
{
|
||||||
var assemblyName = assembly.GetName().Name;
|
var assemblyName = assembly.GetName().Name;
|
||||||
if (string.IsNullOrEmpty(assemblyName))
|
if (string.IsNullOrEmpty(assemblyName))
|
||||||
{
|
{
|
||||||
actionUnload.Invoke();
|
|
||||||
throw new Exception($"程序集[{assembly.GetName().FullName}]加载失败,没有程序集名称");
|
throw new Exception($"程序集[{assembly.GetName().FullName}]加载失败,没有程序集名称");
|
||||||
}
|
}
|
||||||
_myFlowLibrarys.TryAdd(assemblyName, flowLibrary);
|
_myFlowLibrarys.TryAdd(assemblyName, flowLibrary);
|
||||||
@@ -296,7 +285,6 @@ namespace Serein.NodeFlow.Tool
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
actionUnload.Invoke();
|
|
||||||
throw new Exception($"程序集[{assembly.GetName().FullName}]加载失败");
|
throw new Exception($"程序集[{assembly.GetName().FullName}]加载失败");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ public static class NodeMethodDetailsHelper
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static IEnumerable<MethodInfo> GetMethodsToProcess(Type type)
|
public static IEnumerable<MethodInfo> GetMethodsToProcess(Type type)
|
||||||
{
|
{
|
||||||
return type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
|
return type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)
|
||||||
.Where(m => m.GetCustomAttribute<NodeActionAttribute>()?.Scan == true);
|
.Where(m => m.GetCustomAttribute<NodeActionAttribute>()?.Scan == true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ namespace Serein.Workbench
|
|||||||
filePath = @"C:\Users\Az\source\repos\CLBanyunqiState\CLBanyunqiState\bin\Release\net8.0\PLCproject.dnf";
|
filePath = @"C:\Users\Az\source\repos\CLBanyunqiState\CLBanyunqiState\bin\Release\net8.0\PLCproject.dnf";
|
||||||
filePath = @"C:\Users\Az\source\repos\CLBanyunqiState\CLBanyunqiState\bin\Release\banyunqi\project.dnf";
|
filePath = @"C:\Users\Az\source\repos\CLBanyunqiState\CLBanyunqiState\bin\Release\banyunqi\project.dnf";
|
||||||
filePath = @"F:\临时\project\project.dnf";
|
filePath = @"F:\临时\project\project.dnf";
|
||||||
|
filePath = @"F:\临时\flow\qrcode\project.dnf";
|
||||||
//filePath = @"C:\Users\Az\source\repos\CLBanyunqiState\CLBanyunqiState\bin\debug\net8.0\test.dnf";
|
//filePath = @"C:\Users\Az\source\repos\CLBanyunqiState\CLBanyunqiState\bin\debug\net8.0\test.dnf";
|
||||||
string content = System.IO.File.ReadAllText(filePath); // 读取整个文件内容
|
string content = System.IO.File.ReadAllText(filePath); // 读取整个文件内容
|
||||||
App.FlowProjectData = JsonConvert.DeserializeObject<SereinProjectData>(content);
|
App.FlowProjectData = JsonConvert.DeserializeObject<SereinProjectData>(content);
|
||||||
|
|||||||
@@ -46,11 +46,16 @@
|
|||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
<Menu DockPanel.Dock="Top" Grid.Row="0" Grid.ColumnSpan="5" Height="20">
|
<Menu DockPanel.Dock="Top" Grid.Row="0" Grid.ColumnSpan="5" Height="20">
|
||||||
|
|
||||||
<MenuItem Header="项目">
|
<MenuItem Header="项目">
|
||||||
<!--菜单项为MenuItem,文字使用属性 Header-->
|
<!--菜单项为MenuItem,文字使用属性 Header-->
|
||||||
<MenuItem Header="保存项目" Click="ButtonSaveFile_Click" ></MenuItem>
|
<MenuItem Header="保存项目" Click="ButtonSaveFile_Click" ></MenuItem>
|
||||||
<MenuItem Header="打开本地文件" Click="ButtonOpenLocalProject_Click"></MenuItem>
|
<MenuItem Header="打开本地文件" Click="ButtonOpenLocalProject_Click"></MenuItem>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
<MenuItem Header="拓展">
|
||||||
|
<!--菜单项为MenuItem,文字使用属性 Header-->
|
||||||
|
<MenuItem Header="动态编译" Click="OpenDynamicCompileEdit_Click" ></MenuItem>
|
||||||
|
</MenuItem>
|
||||||
<MenuItem Header="调试">
|
<MenuItem Header="调试">
|
||||||
<MenuItem Header="运行(从起始节点)" Click="ButtonDebugRun_Click"></MenuItem>
|
<MenuItem Header="运行(从起始节点)" Click="ButtonDebugRun_Click"></MenuItem>
|
||||||
<MenuItem Header="运行(从选定节点)" Click="ButtonStartFlowInSelectNode_Click"></MenuItem>
|
<MenuItem Header="运行(从选定节点)" Click="ButtonStartFlowInSelectNode_Click"></MenuItem>
|
||||||
@@ -84,6 +89,7 @@
|
|||||||
<!--暂时隐藏基础面板 Visibility="Collapsed" -->
|
<!--暂时隐藏基础面板 Visibility="Collapsed" -->
|
||||||
<ScrollViewer Grid.Row="0" HorizontalScrollBarVisibility="Auto">
|
<ScrollViewer Grid.Row="0" HorizontalScrollBarVisibility="Auto">
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<!--<nodeView:NetScriptNodeControl x:Name="NetScriptNodeControl" Margin="10" AllowDrop="True" PreviewMouseMove="BaseNodeControl_PreviewMouseMove"/>-->
|
||||||
<nodeView:ScriptNodeControl x:Name="ScriptNodeControl" Margin="10" AllowDrop="True" PreviewMouseMove="BaseNodeControl_PreviewMouseMove"/>
|
<nodeView:ScriptNodeControl x:Name="ScriptNodeControl" Margin="10" AllowDrop="True" PreviewMouseMove="BaseNodeControl_PreviewMouseMove"/>
|
||||||
<nodeView:GlobalDataControl x:Name="GlobalDataControl" Margin="10" AllowDrop="True" PreviewMouseMove="BaseNodeControl_PreviewMouseMove"/>
|
<nodeView:GlobalDataControl x:Name="GlobalDataControl" Margin="10" AllowDrop="True" PreviewMouseMove="BaseNodeControl_PreviewMouseMove"/>
|
||||||
<nodeView:ExpOpNodeControl x:Name="ExpOpNodeControl" Margin="10" AllowDrop="True" PreviewMouseMove="BaseNodeControl_PreviewMouseMove"/>
|
<nodeView:ExpOpNodeControl x:Name="ExpOpNodeControl" Margin="10" AllowDrop="True" PreviewMouseMove="BaseNodeControl_PreviewMouseMove"/>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using Serein.Library;
|
|||||||
using Serein.Library.Api;
|
using Serein.Library.Api;
|
||||||
using Serein.Library.Utils;
|
using Serein.Library.Utils;
|
||||||
using Serein.NodeFlow;
|
using Serein.NodeFlow;
|
||||||
|
using Serein.NodeFlow.Env;
|
||||||
using Serein.NodeFlow.Tool;
|
using Serein.NodeFlow.Tool;
|
||||||
using Serein.Workbench.Extension;
|
using Serein.Workbench.Extension;
|
||||||
using Serein.Workbench.Node;
|
using Serein.Workbench.Node;
|
||||||
@@ -12,6 +13,7 @@ using Serein.Workbench.Node.View;
|
|||||||
using Serein.Workbench.Node.ViewModel;
|
using Serein.Workbench.Node.ViewModel;
|
||||||
using Serein.Workbench.Themes;
|
using Serein.Workbench.Themes;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
@@ -170,6 +172,7 @@ namespace Serein.Workbench
|
|||||||
NodeMVVMManagement.RegisterUI(NodeControlType.ConditionRegion, typeof(ConditionRegionControl), typeof(ConditionRegionNodeControlViewModel));
|
NodeMVVMManagement.RegisterUI(NodeControlType.ConditionRegion, typeof(ConditionRegionControl), typeof(ConditionRegionNodeControlViewModel));
|
||||||
NodeMVVMManagement.RegisterUI(NodeControlType.GlobalData, typeof(GlobalDataControl), typeof(GlobalDataNodeControlViewModel));
|
NodeMVVMManagement.RegisterUI(NodeControlType.GlobalData, typeof(GlobalDataControl), typeof(GlobalDataNodeControlViewModel));
|
||||||
NodeMVVMManagement.RegisterUI(NodeControlType.Script, typeof(ScriptNodeControl), typeof(ScriptNodeControlViewModel));
|
NodeMVVMManagement.RegisterUI(NodeControlType.Script, typeof(ScriptNodeControl), typeof(ScriptNodeControlViewModel));
|
||||||
|
NodeMVVMManagement.RegisterUI(NodeControlType.NetScript, typeof(NetScriptNodeControl), typeof(NetScriptNodeControlViewModel));
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
@@ -398,7 +401,12 @@ namespace Serein.Workbench
|
|||||||
{
|
{
|
||||||
NodeLibraryInfo? library = projectData.Librarys[index];
|
NodeLibraryInfo? library = projectData.Librarys[index];
|
||||||
string sourceFilePath = new Uri(library.FilePath).LocalPath; // 源文件夹
|
string sourceFilePath = new Uri(library.FilePath).LocalPath; // 源文件夹
|
||||||
string targetFilePath = System.IO.Path.Combine(librarySavePath, library.FileName); // 目标文件夹
|
string targetDir = System.IO.Path.Combine(librarySavePath, library.AssemblyName); // 目标文件夹
|
||||||
|
if (!Path.Exists(targetDir))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(targetDir);
|
||||||
|
}
|
||||||
|
string targetFilePath = System.IO.Path.Combine(targetDir, library.FileName); // 目标文件夹
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -432,9 +440,6 @@ namespace Serein.Workbench
|
|||||||
var tmpUri2 = new Uri(targetFilePath);
|
var tmpUri2 = new Uri(targetFilePath);
|
||||||
var relativePath = saveProjectFileUri.MakeRelativeUri(tmpUri2).ToString(); // 转为类库的相对文件路径
|
var relativePath = saveProjectFileUri.MakeRelativeUri(tmpUri2).ToString(); // 转为类库的相对文件路径
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//string relativePath = System.IO.Path.GetRelativePath(savePath, targetPath);
|
//string relativePath = System.IO.Path.GetRelativePath(savePath, targetPath);
|
||||||
projectData.Librarys[index].FilePath = relativePath;
|
projectData.Librarys[index].FilePath = relativePath;
|
||||||
}
|
}
|
||||||
@@ -1417,6 +1422,7 @@ namespace Serein.Workbench
|
|||||||
Type when typeof(ExpOpNodeControl).IsAssignableFrom(droppedType) => NodeControlType.ExpOp,
|
Type when typeof(ExpOpNodeControl).IsAssignableFrom(droppedType) => NodeControlType.ExpOp,
|
||||||
Type when typeof(GlobalDataControl).IsAssignableFrom(droppedType) => NodeControlType.GlobalData,
|
Type when typeof(GlobalDataControl).IsAssignableFrom(droppedType) => NodeControlType.GlobalData,
|
||||||
Type when typeof(ScriptNodeControl).IsAssignableFrom(droppedType) => NodeControlType.Script,
|
Type when typeof(ScriptNodeControl).IsAssignableFrom(droppedType) => NodeControlType.Script,
|
||||||
|
Type when typeof(NetScriptNodeControl).IsAssignableFrom(droppedType) => NodeControlType.NetScript,
|
||||||
_ => NodeControlType.None,
|
_ => NodeControlType.None,
|
||||||
};
|
};
|
||||||
if (nodeControlType != NodeControlType.None)
|
if (nodeControlType != NodeControlType.None)
|
||||||
@@ -2669,6 +2675,55 @@ namespace Serein.Workbench
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region 顶部菜单栏 - 拓展
|
||||||
|
/// <summary>
|
||||||
|
/// 动态编译
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender"></param>
|
||||||
|
/// <param name="e"></param>
|
||||||
|
private async void OpenDynamicCompileEdit_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string script = @"using Serein.Library;
|
||||||
|
using Serein.Library.Api;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
[DynamicFlow(""[动态编译]"")]
|
||||||
|
public class FlowLibrary
|
||||||
|
{
|
||||||
|
[NodeAction(NodeType.Action, AnotherName = ""输出"")]
|
||||||
|
public void Print(IDynamicContext context,string value = ""Hello World!"")
|
||||||
|
{
|
||||||
|
context.Env.WriteLine(InfoType.INFO, value);
|
||||||
|
}
|
||||||
|
}";
|
||||||
|
|
||||||
|
DynamicCompilerView dynamicCompilerView = new DynamicCompilerView();
|
||||||
|
dynamicCompilerView.ScriptCode = script;
|
||||||
|
dynamicCompilerView.OnCompileComplete = (assembly) =>
|
||||||
|
{
|
||||||
|
if(EnvDecorator.CurrentEnv is FlowEnvironment environment)
|
||||||
|
{
|
||||||
|
environment.LoadLibrary(assembly);
|
||||||
|
}
|
||||||
|
//EnvDecorator.LoadLibrary
|
||||||
|
};
|
||||||
|
dynamicCompilerView.ShowDialog();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
SereinEnv.WriteLine(ex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
#region 顶部菜单栏 - 远程管理
|
#region 顶部菜单栏 - 远程管理
|
||||||
private async void ButtonStartRemoteServer_Click(object sender, RoutedEventArgs e)
|
private async void ButtonStartRemoteServer_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
|
|||||||
64
Workbench/Node/View/NetScriptNodeControl.xaml
Normal file
64
Workbench/Node/View/NetScriptNodeControl.xaml
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
<local:NodeControlBase x:Class="Serein.Workbench.Node.View.NetScriptNodeControl"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:local="clr-namespace:Serein.Workbench.Node.View"
|
||||||
|
xmlns:vm="clr-namespace:Serein.Workbench.Node.ViewModel"
|
||||||
|
xmlns:themes="clr-namespace:Serein.Workbench.Themes"
|
||||||
|
xmlns:avalonEdit="http://icsharpcode.net/sharpdevelop/avalonedit"
|
||||||
|
d:DataContext="{d:DesignInstance vm:NetScriptNodeControlViewModel}"
|
||||||
|
|
||||||
|
mc:Ignorable="d"
|
||||||
|
MinWidth="50">
|
||||||
|
<Grid Background="#FEFAF4">
|
||||||
|
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<Grid Grid.Row="0" Background="#E7EFF5" >
|
||||||
|
<!--<Grid Grid.Row="0" >-->
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="auto"/>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
<ColumnDefinition Width="auto"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<local:ExecuteJunctionControl Grid.Column="0" MyNode="{Binding NodeModel}" 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"/>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid Grid.Row="1" HorizontalAlignment="Stretch" Margin="4">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<StackPanel Grid.Row="0" Grid.Column="0" Orientation="Horizontal" HorizontalAlignment="Center">
|
||||||
|
<TextBox Grid.Row="2" MinHeight="20" MinWidth="100" MaxWidth="270" TextWrapping="Wrap" AcceptsReturn="True" IsEnabled="{Binding IsEnabledOnView}" Text="{Binding Tips}"></TextBox>
|
||||||
|
<!--<TextBlock Text="脚本代码:" Margin="2" HorizontalAlignment="Stretch" VerticalAlignment="Center"/>-->
|
||||||
|
<Button Content="编辑" Margin="3,0,1,0" Command="{Binding CommandOpenScriptEdit}"></Button>
|
||||||
|
</StackPanel>
|
||||||
|
<themes:MethodDetailsControl Grid.Row="1" x:Name="MethodDetailsControl" MethodDetails="{Binding NodeModel.MethodDetails}"/>
|
||||||
|
<Grid Grid.Row="3" x:Name="NodeScriptGrid">
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</local:NodeControlBase>
|
||||||
58
Workbench/Node/View/NetScriptNodeControl.xaml.cs
Normal file
58
Workbench/Node/View/NetScriptNodeControl.xaml.cs
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
using Serein.NodeFlow.Model;
|
||||||
|
using Serein.Workbench.Node.ViewModel;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Documents;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
using System.Windows.Navigation;
|
||||||
|
using System.Windows.Shapes;
|
||||||
|
|
||||||
|
namespace Serein.Workbench.Node.View
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// NetScriptNodeControl.xaml 的交互逻辑
|
||||||
|
/// </summary>
|
||||||
|
public partial class NetScriptNodeControl : NodeControlBase , INodeJunction
|
||||||
|
{
|
||||||
|
public NetScriptNodeControl()
|
||||||
|
{
|
||||||
|
base.ViewModel = new NetScriptNodeControlViewModel(new SingleNetScriptNode(null));
|
||||||
|
base.ViewModel.IsEnabledOnView = false;
|
||||||
|
base.DataContext = ViewModel;
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public NetScriptNodeControl(NetScriptNodeControlViewModel viewModel) : base(viewModel)
|
||||||
|
{
|
||||||
|
DataContext = viewModel;
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 入参控制点(可能有,可能没)
|
||||||
|
/// </summary>
|
||||||
|
JunctionControlBase INodeJunction.ExecuteJunction => this.ExecuteJunctionControl;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 下一个调用方法控制点(可能有,可能没)
|
||||||
|
/// </summary>
|
||||||
|
JunctionControlBase INodeJunction.NextStepJunction => this.NextStepJunctionControl;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 返回值控制点(可能有,可能没)
|
||||||
|
/// </summary>
|
||||||
|
JunctionControlBase INodeJunction.ReturnDataJunction => throw new Exception();
|
||||||
|
|
||||||
|
|
||||||
|
public JunctionControlBase[] ArgDataJunction => [];
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,11 +9,8 @@
|
|||||||
d:DataContext="{d:DesignInstance vm:ScriptNodeControlViewModel}"
|
d:DataContext="{d:DesignInstance vm:ScriptNodeControlViewModel}"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
MinWidth="50">
|
MinWidth="50">
|
||||||
|
|
||||||
<Grid Background="#FEFAF4">
|
<Grid Background="#FEFAF4">
|
||||||
<!--<Grid.ToolTip>
|
|
||||||
<ToolTip Background="LightYellow" Foreground="Black" Content="{Binding NodeModel.MethodDetails.MethodAnotherName, UpdateSourceTrigger=PropertyChanged}" />
|
|
||||||
</Grid.ToolTip>-->
|
|
||||||
|
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="*"/>
|
<RowDefinition Height="*"/>
|
||||||
|
|||||||
99
Workbench/Node/ViewModel/NetScriptNodeControlViewModel.cs
Normal file
99
Workbench/Node/ViewModel/NetScriptNodeControlViewModel.cs
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
|
using Serein.Library;
|
||||||
|
using Serein.NodeFlow;
|
||||||
|
using Serein.NodeFlow.Model;
|
||||||
|
using Serein.Workbench.Themes;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Documents;
|
||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace Serein.Workbench.Node.ViewModel
|
||||||
|
{
|
||||||
|
public class NetScriptNodeControlViewModel : NodeControlViewModelBase
|
||||||
|
{
|
||||||
|
private SingleNetScriptNode NodeModel => (SingleNetScriptNode)base.NodeModel;
|
||||||
|
|
||||||
|
public string Tips
|
||||||
|
{
|
||||||
|
get => NodeModel.Tips;
|
||||||
|
set { NodeModel.Tips = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Script
|
||||||
|
{
|
||||||
|
get => NodeModel.Script;
|
||||||
|
set { NodeModel.Script = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public NetScriptNodeControlViewModel(NodeModelBase nodeModel) : base(nodeModel)
|
||||||
|
{
|
||||||
|
Script = @"using Serein.Library;
|
||||||
|
using Serein.Library.Api;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
[DynamicFlow(""[动态编译]"")]
|
||||||
|
public class FlowLibrary
|
||||||
|
{
|
||||||
|
[NodeAction(NodeType.Action, AnotherName = ""输出"")]
|
||||||
|
public void Print(IDynamicContext context,string value = ""Hello World!"")
|
||||||
|
{
|
||||||
|
context.Env.WriteLine(InfoType.INFO, value);
|
||||||
|
}
|
||||||
|
}";
|
||||||
|
|
||||||
|
CommandOpenScriptEdit = new RelayCommand(async o =>
|
||||||
|
{
|
||||||
|
DynamicCompilerView dynamicCompilerView = new DynamicCompilerView();
|
||||||
|
dynamicCompilerView.ScriptCode = this.Script ;
|
||||||
|
dynamicCompilerView.OnCompileComplete = OnCompileComplete;
|
||||||
|
dynamicCompilerView.ShowDialog();
|
||||||
|
|
||||||
|
//try
|
||||||
|
//{
|
||||||
|
// var result = await NodeModel.ExecutingAsync(new Library.DynamicContext(nodeModel.Env));
|
||||||
|
// nodeModel.Env.WriteLine(InfoType.INFO, result?.ToString());
|
||||||
|
//}
|
||||||
|
//catch (Exception ex)
|
||||||
|
//{
|
||||||
|
// nodeModel.Env.WriteLine(InfoType.ERROR, ex.ToString());
|
||||||
|
//}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void OnCompileComplete(System.Reflection.Assembly assembly)
|
||||||
|
{
|
||||||
|
FlowLibrary flowLibrary = new FlowLibrary(assembly);
|
||||||
|
var loadResult = flowLibrary.LoadAssembly(); // 动态编译完成后加载程序集
|
||||||
|
if (!loadResult)
|
||||||
|
{
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
var md = flowLibrary.MethodDetailss.Values.FirstOrDefault();
|
||||||
|
if (md is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 打开编辑窗口
|
||||||
|
/// </summary>
|
||||||
|
public ICommand CommandOpenScriptEdit { get; }
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -59,10 +59,11 @@
|
|||||||
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="AvalonEdit" Version="6.3.0.90" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
|
|
||||||
|
|
||||||
<PackageReference Include="OpenCvSharp4.Extensions" Version="4.10.0.20241108" />
|
<!--<PackageReference Include="OpenCvSharp4.Extensions" Version="4.10.0.20241108" />-->
|
||||||
|
|
||||||
<!--<PackageReference Include="Lagrange.Core" Version="0.3.1" />-->
|
<!--<PackageReference Include="Lagrange.Core" Version="0.3.1" />-->
|
||||||
<!--<PackageReference Include="SixLabors.ImageSharp" Version="3.1.6" />-->
|
<!--<PackageReference Include="SixLabors.ImageSharp" Version="3.1.6" />-->
|
||||||
|
|||||||
69
Workbench/Themes/DynamicCompilerView.xaml
Normal file
69
Workbench/Themes/DynamicCompilerView.xaml
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
<Window x:Class="Serein.Workbench.Themes.DynamicCompilerView"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:local="clr-namespace:Serein.Workbench.Themes"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
xmlns:avalonEdit="http://icsharpcode.net/sharpdevelop/avalonedit"
|
||||||
|
Title="动态编译器" Height="600" Width="800">
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
<RowDefinition Height="150"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<!-- 上方DLL引用部分 -->
|
||||||
|
<Grid Grid.Row="0" Margin="10">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<StackPanel Grid.Row="0" Orientation="Horizontal" Margin="0,0,0,5">
|
||||||
|
<Button x:Name="btnAdd" Content="添加引用" Click="btnAdd_Click" Width="100" Margin="0,0,10,0"/>
|
||||||
|
<Button x:Name="btnBatchAdd" Content="批量添加" Click="btnBatchAdd_Click" Width="100" Margin="0,0,10,0"/>
|
||||||
|
<Button x:Name="btnRemove" Content="删除引用" Click="btnRemove_Click" Width="100"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<ListBox x:Name="lstReferences" Grid.Row="1"
|
||||||
|
MouseDoubleClick="lstReferences_MouseDoubleClick" MaxHeight="150"/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<!-- 中间代码编辑器部分 -->
|
||||||
|
<avalonEdit:TextEditor Grid.Row="1"
|
||||||
|
x:Name="codeEditor"
|
||||||
|
FontFamily="Consolas"
|
||||||
|
FontSize="12"
|
||||||
|
SyntaxHighlighting="C#"
|
||||||
|
ShowLineNumbers="True"
|
||||||
|
Margin="10"/>
|
||||||
|
|
||||||
|
<!-- 下方编译结果部分 -->
|
||||||
|
<Grid Grid.Row="2" Margin="10">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<StackPanel Orientation="Horizontal"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
>
|
||||||
|
<TextBlock Text="程序集名称:" Width="70" Margin="10,0,5,0"/>
|
||||||
|
<TextBox x:Name="textboxAssemblyName" Text="FlowLibrary" Width="150" Margin="10,0,10,0"/>
|
||||||
|
<Button x:Name="btnCompile"
|
||||||
|
Content="编译"
|
||||||
|
Click="btnCompile_Click"
|
||||||
|
/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
|
||||||
|
<TextBox x:Name="txtErrors"
|
||||||
|
Grid.Row="1"
|
||||||
|
IsReadOnly="True"
|
||||||
|
TextWrapping="Wrap"
|
||||||
|
VerticalScrollBarVisibility="Auto"
|
||||||
|
Background="LightYellow"/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Window>
|
||||||
150
Workbench/Themes/DynamicCompilerView.xaml.cs
Normal file
150
Workbench/Themes/DynamicCompilerView.xaml.cs
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
using Microsoft.Win32;
|
||||||
|
using Serein.NodeFlow.Tool;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Documents;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
using System.Windows.Shapes;
|
||||||
|
|
||||||
|
namespace Serein.Workbench.Themes
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// DynamicCompilerApp.xaml 的交互逻辑
|
||||||
|
/// </summary>
|
||||||
|
public partial class DynamicCompilerView : Window
|
||||||
|
{
|
||||||
|
private static int count = 1;
|
||||||
|
private readonly DynamicCompiler _compiler;
|
||||||
|
/// <summary>
|
||||||
|
/// 脚本代码
|
||||||
|
/// </summary>
|
||||||
|
public string ScriptCode { get => codeEditor.Text; set => codeEditor.Text = value; }
|
||||||
|
/// <summary>
|
||||||
|
/// 编译成功回调
|
||||||
|
/// </summary>
|
||||||
|
public Action<Assembly> OnCompileComplete { get; set; }
|
||||||
|
public DynamicCompilerView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
textboxAssemblyName.Text = $"FlowLibrary{count}";
|
||||||
|
_compiler = new DynamicCompiler();
|
||||||
|
// 初始化代码编辑器
|
||||||
|
//codeEditor.Text =
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnAdd_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
var openFileDialog = new Microsoft.Win32.OpenFileDialog
|
||||||
|
{
|
||||||
|
Filter = "DLL文件|*.dll|所有文件|*.*",
|
||||||
|
Title = "选择要引用的DLL文件"
|
||||||
|
};
|
||||||
|
|
||||||
|
if (openFileDialog.ShowDialog() == true)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_compiler.AddReference(openFileDialog.FileName);
|
||||||
|
lstReferences.Items.Add(openFileDialog.FileName);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
System.Windows.MessageBox.Show($"添加引用失败:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnBatchAdd_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
using (var folderDialog = new FolderBrowserDialog())
|
||||||
|
{
|
||||||
|
folderDialog.Description = "选择包含DLL文件的文件夹";
|
||||||
|
if (folderDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string[] dllFiles = Directory.GetFiles(folderDialog.SelectedPath, "*.dll", SearchOption.AllDirectories);
|
||||||
|
int successCount = 0;
|
||||||
|
int failCount = 0;
|
||||||
|
|
||||||
|
foreach (string dllFile in dllFiles)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_compiler.AddReference(dllFile);
|
||||||
|
lstReferences.Items.Add(dllFile);
|
||||||
|
successCount++;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
failCount++;
|
||||||
|
System.Diagnostics.Debug.WriteLine($"添加引用失败 {dllFile}: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
System.Windows.MessageBox.Show($"批量添加完成!\n成功:{successCount}个\n失败:{failCount}个",
|
||||||
|
"批量添加结果",
|
||||||
|
MessageBoxButton.OK,
|
||||||
|
failCount > 0 ? MessageBoxImage.Warning : MessageBoxImage.Information);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
System.Windows.MessageBox.Show($"批量添加过程中发生错误:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnRemove_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (lstReferences.SelectedItem != null)
|
||||||
|
{
|
||||||
|
lstReferences.Items.Remove(lstReferences.SelectedItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void lstReferences_MouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
if (lstReferences.SelectedItem != null)
|
||||||
|
{
|
||||||
|
System.Windows.MessageBox.Show(lstReferences.SelectedItem.ToString(), "引用路径", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnCompile_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
txtErrors.Clear();
|
||||||
|
string code = codeEditor.Text;
|
||||||
|
Assembly assembly = _compiler.Compile(code, textboxAssemblyName.Text);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (assembly != null)
|
||||||
|
{
|
||||||
|
txtErrors.Text = "编译成功!";
|
||||||
|
txtErrors.Background = System.Windows.Media.Brushes.LightGreen;
|
||||||
|
OnCompileComplete.Invoke(assembly);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
txtErrors.Text = $"编译错误:\n{ex.Message}";
|
||||||
|
txtErrors.Background = System.Windows.Media.Brushes.LightPink;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,7 +14,8 @@
|
|||||||
|
|
||||||
<converters:InvertableBooleanToVisibilityConverter x:Key="InvertedBoolConverter"/>
|
<converters:InvertableBooleanToVisibilityConverter x:Key="InvertedBoolConverter"/>
|
||||||
<converters:EnumToBooleanConverter x:Key="EnumToBooleanConverter"/>
|
<converters:EnumToBooleanConverter x:Key="EnumToBooleanConverter"/>
|
||||||
|
<local:DescriptionOrNameConverter x:Key="DescOrNameConverter"/>
|
||||||
|
|
||||||
<Style TargetType="{x:Type local:MethodDetailsControl}">
|
<Style TargetType="{x:Type local:MethodDetailsControl}">
|
||||||
<Setter Property="Template">
|
<Setter Property="Template">
|
||||||
<Setter.Value>
|
<Setter.Value>
|
||||||
@@ -66,7 +67,6 @@
|
|||||||
</Setter>
|
</Setter>
|
||||||
</MultiDataTrigger>
|
</MultiDataTrigger>
|
||||||
|
|
||||||
|
|
||||||
<!--显示Action节点方法入参名称-->
|
<!--显示Action节点方法入参名称-->
|
||||||
<MultiDataTrigger>
|
<MultiDataTrigger>
|
||||||
<MultiDataTrigger.Conditions>
|
<MultiDataTrigger.Conditions>
|
||||||
@@ -75,7 +75,16 @@
|
|||||||
<Setter Property="ContentTemplate">
|
<Setter Property="ContentTemplate">
|
||||||
<Setter.Value>
|
<Setter.Value>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<TextBlock Grid.Column="0" MinWidth="50" Text="{Binding Name}"/>
|
|
||||||
|
<TextBlock Grid.Column="0" MinWidth="50">
|
||||||
|
<TextBlock.Text>
|
||||||
|
<MultiBinding Converter="{StaticResource DescOrNameConverter}">
|
||||||
|
<Binding Path="Description"/>
|
||||||
|
<Binding Path="Name"/>
|
||||||
|
</MultiBinding>
|
||||||
|
</TextBlock.Text>
|
||||||
|
</TextBlock>
|
||||||
|
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</Setter.Value>
|
</Setter.Value>
|
||||||
</Setter>
|
</Setter>
|
||||||
@@ -89,7 +98,16 @@
|
|||||||
<Setter Property="ContentTemplate">
|
<Setter Property="ContentTemplate">
|
||||||
<Setter.Value>
|
<Setter.Value>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<TextBlock Grid.Column="0" MinWidth="50" Text="{Binding Name}"/>
|
|
||||||
|
<TextBlock Grid.Column="0" MinWidth="50">
|
||||||
|
<TextBlock.Text>
|
||||||
|
<MultiBinding Converter="{StaticResource DescOrNameConverter}">
|
||||||
|
<Binding Path="Description"/>
|
||||||
|
<Binding Path="Name"/>
|
||||||
|
</MultiBinding>
|
||||||
|
</TextBlock.Text>
|
||||||
|
</TextBlock>
|
||||||
|
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</Setter.Value>
|
</Setter.Value>
|
||||||
</Setter>
|
</Setter>
|
||||||
@@ -169,7 +187,7 @@
|
|||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="*"/>
|
<ColumnDefinition Width="*"/>
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<TextBox Grid.Column="0" MinWidth="50" Text="{Binding DataValue, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"/>
|
<TextBox Grid.Column="0" MinWidth="50" Text="{Binding DataValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</Setter.Value>
|
</Setter.Value>
|
||||||
|
|||||||
@@ -9,6 +9,23 @@ using System.Windows.Input;
|
|||||||
|
|
||||||
namespace Serein.Workbench.Themes
|
namespace Serein.Workbench.Themes
|
||||||
{
|
{
|
||||||
|
|
||||||
|
public class DescriptionOrNameConverter : IMultiValueConverter
|
||||||
|
{
|
||||||
|
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
string description = values[0] as string;
|
||||||
|
string name = values[1] as string;
|
||||||
|
return string.IsNullOrWhiteSpace(description) ? name : description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public class MultiConditionConverter : IMultiValueConverter
|
public class MultiConditionConverter : IMultiValueConverter
|
||||||
{
|
{
|
||||||
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
|||||||
Reference in New Issue
Block a user