重新设计了项目的保存文件结构

This commit is contained in:
fengjiayi
2025-03-18 11:52:54 +08:00
parent 1db8a44135
commit fffb22b3a8
24 changed files with 831 additions and 109 deletions

View File

@@ -124,6 +124,11 @@ namespace Serein.Library
/// </summary> /// </summary>
[Description("base")] [Description("base")]
Script, Script,
/// <summary>
/// C#脚本节点
/// </summary>
[Description("base")]
NetScript,
} }
} }

View File

@@ -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;

View File

@@ -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
{ {

View File

@@ -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>

View File

@@ -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(); // 获取环境中所有节点的方法信息

View File

@@ -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)

View 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;
//}
}
}
}

View File

@@ -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;

View File

@@ -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()
{
}
} }
} }

View File

@@ -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、实例作用对象、委托方法

View File

@@ -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}]加载失败");
} }
} }

View File

@@ -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);
} }

View File

@@ -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);

View File

@@ -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"/>

View File

@@ -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)
{ {

View 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>

View 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 => [];
}
}

View File

@@ -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="*"/>

View 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; }
}
}

View File

@@ -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" />-->

View 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>

View 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;
}
}
}
}

View File

@@ -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>

View File

@@ -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)