mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-02 15:50:47 +08:00
重新设计了项目的保存文件结构
This commit is contained in:
@@ -124,6 +124,11 @@ namespace Serein.Library
|
||||
/// </summary>
|
||||
[Description("base")]
|
||||
Script,
|
||||
/// <summary>
|
||||
/// C#脚本节点
|
||||
/// </summary>
|
||||
[Description("base")]
|
||||
NetScript,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -65,17 +65,21 @@ namespace Serein.Library
|
||||
}
|
||||
this.DebugSetting.NodeModel = null;
|
||||
this.DebugSetting = null;
|
||||
foreach (var pd in this.MethodDetails.ParameterDetailss)
|
||||
if(this.MethodDetails.ParameterDetailss != null)
|
||||
{
|
||||
pd.DataValue = null;
|
||||
pd.Items = null;
|
||||
pd.NodeModel = null;
|
||||
pd.ExplicitType = null;
|
||||
pd.DataType = null;
|
||||
pd.Name = null;
|
||||
pd.ArgDataSourceNodeGuid = null;
|
||||
pd.InputType = ParameterValueInputType.Input;
|
||||
foreach (var pd in this.MethodDetails.ParameterDetailss)
|
||||
{
|
||||
pd.DataValue = null;
|
||||
pd.Items = null;
|
||||
pd.NodeModel = null;
|
||||
pd.ExplicitType = null;
|
||||
pd.DataType = null;
|
||||
pd.Name = null;
|
||||
pd.ArgDataSourceNodeGuid = null;
|
||||
pd.InputType = ParameterValueInputType.Input;
|
||||
}
|
||||
}
|
||||
|
||||
this.MethodDetails.ParameterDetailss = null;
|
||||
this.MethodDetails.ActingInstance = null;
|
||||
this.MethodDetails.NodeModel = null;
|
||||
|
||||
@@ -9,7 +9,7 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Serein.Library.Utils
|
||||
namespace Serein.Library
|
||||
{
|
||||
public static class SereinEnv
|
||||
{
|
||||
|
||||
@@ -5,6 +5,7 @@ using Serein.Library.Utils.SereinExpression;
|
||||
using Serein.NodeFlow.Model;
|
||||
using Serein.NodeFlow.Tool;
|
||||
using System.Reactive;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace Serein.NodeFlow.Env
|
||||
@@ -52,6 +53,7 @@ namespace Serein.NodeFlow.Env
|
||||
NodeMVVMManagement.RegisterModel(NodeControlType.ConditionRegion, typeof(CompositeConditionNode)); // 条件区域
|
||||
NodeMVVMManagement.RegisterModel(NodeControlType.GlobalData, typeof(SingleGlobalDataNode)); // 全局数据节点
|
||||
NodeMVVMManagement.RegisterModel(NodeControlType.Script, typeof(SingleScriptNode)); // 脚本节点
|
||||
NodeMVVMManagement.RegisterModel(NodeControlType.NetScript, typeof(SingleNetScriptNode)); // 脚本节点
|
||||
#endregion
|
||||
|
||||
#region 注册基本服务类
|
||||
@@ -647,9 +649,30 @@ namespace Serein.NodeFlow.Env
|
||||
{
|
||||
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>
|
||||
/// 移除DLL
|
||||
/// </summary>
|
||||
|
||||
@@ -76,7 +76,7 @@ namespace Serein.NodeFlow
|
||||
|
||||
flipflopNodes = nodes.Where(it => it.MethodDetails?.MethodDynamicType == NodeType.Flipflop && it.IsStart == false)
|
||||
.Select(it => (SingleFlipflopNode)it)
|
||||
.Where(node => node is SingleFlipflopNode flipflopNode && flipflopNode.NotExitPreviousNode())
|
||||
.Where(node => node.DebugSetting.IsEnable && node is SingleFlipflopNode flipflopNode && flipflopNode.NotExitPreviousNode())
|
||||
.ToList();// 获取需要再运行开始之前启动的触发器节点
|
||||
runNodeMd = nodes.Select(item => item.MethodDetails).ToList(); // 获取环境中所有节点的方法信息
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Serein.NodeFlow.Model
|
||||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// <summary>
|
||||
/// Expression Operation - 表达式操作
|
||||
/// </summary>
|
||||
[NodeProperty(ValuePath = NodeValuePath.Node)]
|
||||
@@ -51,7 +51,11 @@ namespace Serein.NodeFlow.Model
|
||||
/// </summary>
|
||||
private NodeModelBase? DataNode;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 有节点被放置
|
||||
/// </summary>
|
||||
/// <param name="nodeModel"></param>
|
||||
/// <returns></returns>
|
||||
public bool PlaceNode(NodeModelBase nodeModel)
|
||||
{
|
||||
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>
|
||||
public partial class SingleScriptNode : NodeModelBase
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 脚本节点是基础节点
|
||||
/// </summary>
|
||||
public override bool IsBase => true;
|
||||
|
||||
|
||||
private IScriptFlowApi ScriptFlowApi { get; }
|
||||
|
||||
private ASTNode mainNode;
|
||||
|
||||
@@ -9,7 +9,7 @@ using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Library.Utils
|
||||
namespace Serein.NodeFlow.Tool
|
||||
{
|
||||
/// <summary>
|
||||
/// 动态编译
|
||||
@@ -22,7 +22,7 @@ namespace Serein.Library.Utils
|
||||
{
|
||||
// 默认添加当前 AppDomain 加载的所有程序集
|
||||
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));
|
||||
|
||||
|
||||
@@ -64,17 +64,28 @@ namespace Serein.Library.Utils
|
||||
public Assembly Compile(string code, string assemblyName = null)
|
||||
{
|
||||
SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(code);
|
||||
if(assemblyName is null)
|
||||
if (assemblyName is null)
|
||||
{
|
||||
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(
|
||||
assemblyName,
|
||||
new[] { syntaxTree },
|
||||
_references,
|
||||
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
|
||||
options
|
||||
|
||||
);
|
||||
|
||||
using (var ms = new MemoryStream())
|
||||
@@ -90,11 +101,27 @@ namespace Serein.Library.Utils
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
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>
|
||||
public class FlowLibrary
|
||||
{
|
||||
private readonly Assembly assembly;
|
||||
private readonly Action actionOfUnloadAssmbly;
|
||||
private readonly Assembly _assembly;
|
||||
|
||||
public FlowLibrary(Assembly assembly,
|
||||
Action actionOfUnloadAssmbly)
|
||||
|
||||
|
||||
//private readonly Action actionOfUnloadAssmbly;
|
||||
/*, Action actionOfUnloadAssmbly*/
|
||||
//this.actionOfUnloadAssmbly = actionOfUnloadAssmbly;
|
||||
|
||||
public FlowLibrary(Assembly assembly)
|
||||
{
|
||||
this.assembly = assembly;
|
||||
this.actionOfUnloadAssmbly = actionOfUnloadAssmbly;
|
||||
this._assembly = assembly;
|
||||
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>
|
||||
/// 加载程序集时创建的方法描述
|
||||
@@ -68,7 +82,7 @@ namespace Serein.NodeFlow
|
||||
DelegateDetailss.Clear();
|
||||
RegisterTypes.Clear();
|
||||
MethodDetailss.Clear();
|
||||
actionOfUnloadAssmbly?.Invoke();
|
||||
//actionOfUnloadAssmbly?.Invoke();
|
||||
|
||||
}
|
||||
|
||||
@@ -78,11 +92,12 @@ namespace Serein.NodeFlow
|
||||
/// <returns></returns>
|
||||
public NodeLibraryInfo ToInfo()
|
||||
{
|
||||
var assemblyName = _assembly.GetName().Name;
|
||||
return new NodeLibraryInfo
|
||||
{
|
||||
AssemblyName = assembly.GetName().Name,
|
||||
FileName = Path.GetFileName(assembly.Location),
|
||||
FilePath = assembly.Location,
|
||||
AssemblyName = assemblyName,
|
||||
FileName = this.FullName,
|
||||
FilePath = this.FilePath,
|
||||
};
|
||||
|
||||
|
||||
@@ -94,8 +109,9 @@ namespace Serein.NodeFlow
|
||||
/// </summary>
|
||||
/// <param name="assembly">程序集本身</param>
|
||||
/// <returns></returns>
|
||||
public bool LoadAssembly(Assembly assembly)
|
||||
public bool LoadAssembly()
|
||||
{
|
||||
Assembly assembly = this._assembly;
|
||||
#region 检查入参
|
||||
|
||||
// 加载DLL,创建 MethodDetails、实例作用对象、委托方法
|
||||
|
||||
@@ -39,7 +39,36 @@ namespace Serein.NodeFlow.Tool
|
||||
/// <returns></returns>
|
||||
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>
|
||||
@@ -206,84 +235,44 @@ namespace Serein.NodeFlow.Tool
|
||||
/// </summary>
|
||||
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
|
||||
{
|
||||
var dir = Path.GetDirectoryName(dllFilePath); // 获取目录路径
|
||||
var sereinFlowBaseLibraryPath = Path.Combine(dir, SereinBaseLibrary);
|
||||
// 每个类库下面至少需要有“Serein.Library.dll”类库依赖
|
||||
|
||||
//AssemblyLoader assemblyLoader = new AssemblyLoader(dllFilePath);
|
||||
|
||||
|
||||
var flowAlc = new FlowLibraryAssemblyContext(sereinFlowBaseLibraryPath, fileName);
|
||||
Action actionUnload = () =>
|
||||
try
|
||||
{
|
||||
flowAlc?.Unload(); // 卸载程序集
|
||||
flowAlc = null;
|
||||
GC.Collect(); // 强制触发GC确保卸载成功
|
||||
GC.WaitForPendingFinalizers();
|
||||
};
|
||||
var assembly = flowAlc.LoadFromAssemblyPath(dllFilePath); // 加载指定路径的程序集
|
||||
var assembly_result = LoadAssembly(assembly, actionUnload);
|
||||
return assembly_result;
|
||||
var assembly_result = LoadAssembly(assembly);
|
||||
return assembly_result;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return (null,[]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* 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))
|
||||
{
|
||||
actionUnload.Invoke();
|
||||
throw new Exception($"程序集[{assembly.GetName().FullName}]已经加载过!");
|
||||
}
|
||||
|
||||
FlowLibrary flowLibrary = new FlowLibrary(assembly, actionUnload);
|
||||
var loadResult = flowLibrary.LoadAssembly(assembly); // 加载程序集
|
||||
FlowLibrary flowLibrary = new FlowLibrary(assembly);
|
||||
var loadResult = flowLibrary.LoadAssembly(); // 加载程序集
|
||||
if (loadResult)
|
||||
{
|
||||
var assemblyName = assembly.GetName().Name;
|
||||
if (string.IsNullOrEmpty(assemblyName))
|
||||
{
|
||||
actionUnload.Invoke();
|
||||
throw new Exception($"程序集[{assembly.GetName().FullName}]加载失败,没有程序集名称");
|
||||
}
|
||||
_myFlowLibrarys.TryAdd(assemblyName, flowLibrary);
|
||||
@@ -296,7 +285,6 @@ namespace Serein.NodeFlow.Tool
|
||||
}
|
||||
else
|
||||
{
|
||||
actionUnload.Invoke();
|
||||
throw new Exception($"程序集[{assembly.GetName().FullName}]加载失败");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ public static class NodeMethodDetailsHelper
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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\banyunqi\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";
|
||||
string content = System.IO.File.ReadAllText(filePath); // 读取整个文件内容
|
||||
App.FlowProjectData = JsonConvert.DeserializeObject<SereinProjectData>(content);
|
||||
|
||||
@@ -46,11 +46,16 @@
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Menu DockPanel.Dock="Top" Grid.Row="0" Grid.ColumnSpan="5" Height="20">
|
||||
|
||||
<MenuItem Header="项目">
|
||||
<!--菜单项为MenuItem,文字使用属性 Header-->
|
||||
<MenuItem Header="保存项目" Click="ButtonSaveFile_Click" ></MenuItem>
|
||||
<MenuItem Header="打开本地文件" Click="ButtonOpenLocalProject_Click"></MenuItem>
|
||||
</MenuItem>
|
||||
<MenuItem Header="拓展">
|
||||
<!--菜单项为MenuItem,文字使用属性 Header-->
|
||||
<MenuItem Header="动态编译" Click="OpenDynamicCompileEdit_Click" ></MenuItem>
|
||||
</MenuItem>
|
||||
<MenuItem Header="调试">
|
||||
<MenuItem Header="运行(从起始节点)" Click="ButtonDebugRun_Click"></MenuItem>
|
||||
<MenuItem Header="运行(从选定节点)" Click="ButtonStartFlowInSelectNode_Click"></MenuItem>
|
||||
@@ -84,6 +89,7 @@
|
||||
<!--暂时隐藏基础面板 Visibility="Collapsed" -->
|
||||
<ScrollViewer Grid.Row="0" HorizontalScrollBarVisibility="Auto">
|
||||
<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:GlobalDataControl x:Name="GlobalDataControl" 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.Utils;
|
||||
using Serein.NodeFlow;
|
||||
using Serein.NodeFlow.Env;
|
||||
using Serein.NodeFlow.Tool;
|
||||
using Serein.Workbench.Extension;
|
||||
using Serein.Workbench.Node;
|
||||
@@ -12,6 +13,7 @@ using Serein.Workbench.Node.View;
|
||||
using Serein.Workbench.Node.ViewModel;
|
||||
using Serein.Workbench.Themes;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
@@ -170,6 +172,7 @@ namespace Serein.Workbench
|
||||
NodeMVVMManagement.RegisterUI(NodeControlType.ConditionRegion, typeof(ConditionRegionControl), typeof(ConditionRegionNodeControlViewModel));
|
||||
NodeMVVMManagement.RegisterUI(NodeControlType.GlobalData, typeof(GlobalDataControl), typeof(GlobalDataNodeControlViewModel));
|
||||
NodeMVVMManagement.RegisterUI(NodeControlType.Script, typeof(ScriptNodeControl), typeof(ScriptNodeControlViewModel));
|
||||
NodeMVVMManagement.RegisterUI(NodeControlType.NetScript, typeof(NetScriptNodeControl), typeof(NetScriptNodeControlViewModel));
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -398,7 +401,12 @@ namespace Serein.Workbench
|
||||
{
|
||||
NodeLibraryInfo? library = projectData.Librarys[index];
|
||||
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
|
||||
{
|
||||
@@ -432,9 +440,6 @@ namespace Serein.Workbench
|
||||
var tmpUri2 = new Uri(targetFilePath);
|
||||
var relativePath = saveProjectFileUri.MakeRelativeUri(tmpUri2).ToString(); // 转为类库的相对文件路径
|
||||
|
||||
|
||||
|
||||
|
||||
//string relativePath = System.IO.Path.GetRelativePath(savePath, targetPath);
|
||||
projectData.Librarys[index].FilePath = relativePath;
|
||||
}
|
||||
@@ -1417,6 +1422,7 @@ namespace Serein.Workbench
|
||||
Type when typeof(ExpOpNodeControl).IsAssignableFrom(droppedType) => NodeControlType.ExpOp,
|
||||
Type when typeof(GlobalDataControl).IsAssignableFrom(droppedType) => NodeControlType.GlobalData,
|
||||
Type when typeof(ScriptNodeControl).IsAssignableFrom(droppedType) => NodeControlType.Script,
|
||||
Type when typeof(NetScriptNodeControl).IsAssignableFrom(droppedType) => NodeControlType.NetScript,
|
||||
_ => NodeControlType.None,
|
||||
};
|
||||
if (nodeControlType != NodeControlType.None)
|
||||
@@ -2669,6 +2675,55 @@ namespace Serein.Workbench
|
||||
|
||||
#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 顶部菜单栏 - 远程管理
|
||||
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}"
|
||||
mc:Ignorable="d"
|
||||
MinWidth="50">
|
||||
|
||||
|
||||
<Grid Background="#FEFAF4">
|
||||
<!--<Grid.ToolTip>
|
||||
<ToolTip Background="LightYellow" Foreground="Black" Content="{Binding NodeModel.MethodDetails.MethodAnotherName, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</Grid.ToolTip>-->
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<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>
|
||||
<PackageReference Include="AvalonEdit" Version="6.3.0.90" />
|
||||
<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="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:EnumToBooleanConverter x:Key="EnumToBooleanConverter"/>
|
||||
|
||||
<local:DescriptionOrNameConverter x:Key="DescOrNameConverter"/>
|
||||
|
||||
<Style TargetType="{x:Type local:MethodDetailsControl}">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
@@ -66,7 +67,6 @@
|
||||
</Setter>
|
||||
</MultiDataTrigger>
|
||||
|
||||
|
||||
<!--显示Action节点方法入参名称-->
|
||||
<MultiDataTrigger>
|
||||
<MultiDataTrigger.Conditions>
|
||||
@@ -75,7 +75,16 @@
|
||||
<Setter Property="ContentTemplate">
|
||||
<Setter.Value>
|
||||
<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>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
@@ -89,7 +98,16 @@
|
||||
<Setter Property="ContentTemplate">
|
||||
<Setter.Value>
|
||||
<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>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
@@ -169,7 +187,7 @@
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</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>
|
||||
</DataTemplate>
|
||||
</Setter.Value>
|
||||
|
||||
@@ -9,6 +9,23 @@ using System.Windows.Input;
|
||||
|
||||
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 object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
||||
|
||||
Reference in New Issue
Block a user