From 26e88aea7730ec3e7cbf0082cd78fb4f9e478113 Mon Sep 17 00:00:00 2001 From: fengjiayi <12821976+ning_xi@user.noreply.gitee.com> Date: Mon, 17 Mar 2025 10:14:18 +0800 Subject: [PATCH] =?UTF-8?q?=E7=8E=AF=E5=A2=83=E6=8E=A5=E5=8F=A3=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E4=BA=86=E5=8A=A0=E8=BD=BD=E9=A1=B9=E7=9B=AE=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E8=B7=AF=E5=BE=84=EF=BC=8C=E6=96=B9=E4=BE=BF=E7=B1=BB?= =?UTF-8?q?=E5=BA=93=E5=9C=A8Init=E4=BA=8B=E4=BB=B6=E4=B8=AD=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E5=8A=A0=E8=BD=BD=E5=85=B7=E4=BD=93=E7=9A=84=E4=BE=9D?= =?UTF-8?q?=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Library/Api/IFlowEnvironment.cs | 8 ++ Library/FlowNode/ContainerFlowEnvironment.cs | 1 + Library/FlowNode/NodeDebugSetting.cs | 1 + Library/FlowNode/NodeModelBaseFunc.cs | 1 - Library/Serein.Library.csproj | 2 + Library/Utils/DynamicCompiler.cs | 100 ++++++++++++++++++ Library/Utils/FlowTrigger/TriggerResult.cs | 1 - .../SerinExpressionEvaluator.cs | 5 + NodeFlow/Env/FlowEnvironment.cs | 16 ++- NodeFlow/Env/FlowEnvironmentDecorator.cs | 1 + NodeFlow/Env/RemoteFlowEnvironment.cs | 4 + NodeFlow/Tool/AssemblyLoader.cs | 86 +++++++++++++++ NodeFlow/Tool/FlowLibraryManagement.cs | 20 ++-- NodeFlow/Tool/NodeMethodDetailsHelper.cs | 5 +- Workbench/MainWindow.xaml.cs | 9 +- Workbench/Node/NodeControlViewModelBase.cs | 12 ++- Workbench/Node/View/ConditionNodeControl.xaml | 2 +- .../Node/View/ConditionNodeControl.xaml.cs | 2 + .../Node/View/ConditionRegionControl.xaml.cs | 1 + Workbench/Node/View/ExpOpNodeControl.xaml | 2 +- Workbench/Node/View/ExpOpNodeControl.xaml.cs | 1 + Workbench/Node/View/GlobalDataControl.xaml | 2 +- Workbench/Node/View/GlobalDataControl.xaml.cs | 1 + Workbench/Node/View/ScriptNodeControl.xaml | 2 +- Workbench/Node/View/ScriptNodeControl.xaml.cs | 3 + Workbench/Node/View/UINodeControl.xaml.cs | 1 + .../ConditionNodeControlViewModel.cs | 1 + Workbench/Serein.WorkBench.csproj | 4 + Workbench/Themes/MethodDetailsControl.xaml | 2 +- 29 files changed, 273 insertions(+), 23 deletions(-) create mode 100644 Library/Utils/DynamicCompiler.cs create mode 100644 NodeFlow/Tool/AssemblyLoader.cs diff --git a/Library/Api/IFlowEnvironment.cs b/Library/Api/IFlowEnvironment.cs index 43e404f..6dfa618 100644 --- a/Library/Api/IFlowEnvironment.cs +++ b/Library/Api/IFlowEnvironment.cs @@ -663,6 +663,12 @@ namespace Serein.Library.Api /// string EnvName { get; } + + /// + /// 项目文件位置 + /// + string ProjectFileLocation { get; } + /// /// 是否全局中断 /// @@ -699,6 +705,7 @@ namespace Serein.Library.Api /// UIContextOperation UIContextOperation { get; } + #endregion #region 基本接口 @@ -1033,6 +1040,7 @@ namespace Serein.Library.Api /// /// 程序集的名称 bool TryUnloadLibrary(string assemblyFullName); + /// /// 运行时加载 /// diff --git a/Library/FlowNode/ContainerFlowEnvironment.cs b/Library/FlowNode/ContainerFlowEnvironment.cs index 6718e18..400aaf7 100644 --- a/Library/FlowNode/ContainerFlowEnvironment.cs +++ b/Library/FlowNode/ContainerFlowEnvironment.cs @@ -27,6 +27,7 @@ namespace Serein.Library public ISereinIOC IOC => sereinIOC; public string EnvName => throw new NotImplementedException(); + public string ProjectFileLocation => throw new NotImplementedException(); public bool IsGlobalInterrupt => throw new NotImplementedException(); diff --git a/Library/FlowNode/NodeDebugSetting.cs b/Library/FlowNode/NodeDebugSetting.cs index 87d5c4a..51aa2b9 100644 --- a/Library/FlowNode/NodeDebugSetting.cs +++ b/Library/FlowNode/NodeDebugSetting.cs @@ -75,6 +75,7 @@ namespace Serein.Library { // 设置获取中断的委托 _getInterruptTask = () => NodeModel.Env.IOC.Get().WaitTriggerAsync(NodeModel.Guid); + } else if (!state) { diff --git a/Library/FlowNode/NodeModelBaseFunc.cs b/Library/FlowNode/NodeModelBaseFunc.cs index 6e63eb2..d37ff55 100644 --- a/Library/FlowNode/NodeModelBaseFunc.cs +++ b/Library/FlowNode/NodeModelBaseFunc.cs @@ -449,7 +449,6 @@ namespace Serein.Library - /// /// 更新节点数据,并检查监视表达式是否生效 /// diff --git a/Library/Serein.Library.csproj b/Library/Serein.Library.csproj index 5a6d76e..32f6161 100644 --- a/Library/Serein.Library.csproj +++ b/Library/Serein.Library.csproj @@ -38,6 +38,8 @@ + + diff --git a/Library/Utils/DynamicCompiler.cs b/Library/Utils/DynamicCompiler.cs new file mode 100644 index 0000000..c835194 --- /dev/null +++ b/Library/Utils/DynamicCompiler.cs @@ -0,0 +1,100 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Emit; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace Serein.Library.Utils +{ + /// + /// 动态编译 + /// + public class DynamicCompiler + { + private readonly HashSet _references = new HashSet(); + + public DynamicCompiler() + { + // 默认添加当前 AppDomain 加载的所有程序集 + var defaultReferences = AppDomain.CurrentDomain.GetAssemblies() + .Where(a => !string.IsNullOrEmpty(a.Location)) // a.IsDynamic 动态程序集 + .Select(a => MetadataReference.CreateFromFile(a.Location)); + + + //AddReference(this.GetType()); + _references.UnionWith(defaultReferences); + } + + /// + /// 添加依赖程序集(通过类型) + /// + /// 类型所在的程序集 + public void AddReference(Type type) + { + var assemblyLocation = type.Assembly.Location; + if (!string.IsNullOrEmpty(assemblyLocation)) + { + _references.Add(MetadataReference.CreateFromFile(assemblyLocation)); + } + } + + /// + /// 添加依赖程序集(通过文件路径) + /// + /// 程序集文件路径 + public void AddReference(string assemblyPath) + { + if (File.Exists(assemblyPath)) + { + _references.Add(MetadataReference.CreateFromFile(assemblyPath)); + } + } + + /// + /// 编译 C# 代码并返回程序集 + /// + /// C# 代码文本 + /// 程序集名称(可选) + /// 成功返回 Assembly,失败返回 null + public Assembly Compile(string code, string assemblyName = null) + { + SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(code); + if(assemblyName is null) + { + assemblyName = Path.GetRandomFileName(); // 生成随机程序集名称 + + } + + CSharpCompilation compilation = CSharpCompilation.Create( + assemblyName, + new[] { syntaxTree }, + _references, + new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary) + ); + + using (var ms = new MemoryStream()) + { + EmitResult result = compilation.Emit(ms); + + if (!result.Success) + { + Console.WriteLine("编译失败:"); + foreach (var diagnostic in result.Diagnostics) + { + Console.WriteLine(diagnostic.ToString()); + } + return null; + } + + ms.Seek(0, SeekOrigin.Begin); + return Assembly.Load(ms.ToArray()); + } + + } + } +} diff --git a/Library/Utils/FlowTrigger/TriggerResult.cs b/Library/Utils/FlowTrigger/TriggerResult.cs index 30c8a57..ff3b851 100644 --- a/Library/Utils/FlowTrigger/TriggerResult.cs +++ b/Library/Utils/FlowTrigger/TriggerResult.cs @@ -75,7 +75,6 @@ namespace Serein.Library.Utils /// /// 使用 ObjectPool 来复用 TriggerResult 对象 /// - // 示例 TriggerResult 对象池 public class TriggerResultPool { private readonly ConcurrentExpandingObjectPool> _objectPool; diff --git a/Library/Utils/SereinExpression/SerinExpressionEvaluator.cs b/Library/Utils/SereinExpression/SerinExpressionEvaluator.cs index af35c07..916ffc9 100644 --- a/Library/Utils/SereinExpression/SerinExpressionEvaluator.cs +++ b/Library/Utils/SereinExpression/SerinExpressionEvaluator.cs @@ -54,6 +54,11 @@ namespace Serein.Library.Utils.SereinExpression /// public static object Evaluate(string expression, object targetObJ, out bool isChange) { + if (expression.Equals("@get", StringComparison.OrdinalIgnoreCase)) + { + isChange = false; + return targetObJ; + } //if (expression is null || targetObJ is null) //{ // throw new Exception("表达式条件expression is null、 targetObJ is null"); diff --git a/NodeFlow/Env/FlowEnvironment.cs b/NodeFlow/Env/FlowEnvironment.cs index c2c7b78..abfd5d6 100644 --- a/NodeFlow/Env/FlowEnvironment.cs +++ b/NodeFlow/Env/FlowEnvironment.cs @@ -231,6 +231,12 @@ namespace Serein.NodeFlow.Env /// public string EnvName { get; set; } = SpaceName; + + /// + /// 本地加载的项目文件路径 + /// + public string ProjectFileLocation { get; set; } = string.Empty; + /// /// 是否全局中断 /// @@ -526,6 +532,7 @@ namespace Serein.NodeFlow.Env /// public void LoadProject(FlowEnvInfo flowEnvInfo, string filePath) { + this.ProjectFileLocation = filePath; var projectData = flowEnvInfo.Project; // 加载项目配置文件 var dllPaths = projectData.Librarys.Select(it => it.FilePath).ToList(); @@ -542,8 +549,8 @@ namespace Serein.NodeFlow.Env _ = Task.Run( async () => { - await LoadNodeInfosAsync(projectData.Nodes.ToList()); - await SetStartNodeAsync(projectData.StartNode); + await LoadNodeInfosAsync(projectData.Nodes.ToList()); // 加载节点信息 + await SetStartNodeAsync(projectData.StartNode); // 设置起始节点 }); } @@ -651,7 +658,7 @@ namespace Serein.NodeFlow.Env public bool TryUnloadLibrary(string assemblyName) { // 获取与此程序集相关的节点 - var groupedNodes = NodeModels.Values.Where(node => node.MethodDetails.AssemblyName.Equals(assemblyName)).ToArray(); + var groupedNodes = NodeModels.Values.Where(node => !string.IsNullOrWhiteSpace(node.MethodDetails.AssemblyName) && node.MethodDetails.AssemblyName.Equals(assemblyName)).ToArray(); if (groupedNodes.Length == 0) { var isPass = FlowLibraryManagement.UnloadLibrary(assemblyName); @@ -1411,6 +1418,7 @@ namespace Serein.NodeFlow.Env /// public bool LoadNativeLibraryOfRuning(string file) { + return NativeDllHelper.LoadDll(file); } @@ -1421,7 +1429,7 @@ namespace Serein.NodeFlow.Env /// 是否递归加载 public void LoadAllNativeLibraryOfRuning(string path, bool isRecurrence = true) { - NativeDllHelper.LoadAllDll(path, isRecurrence); + NativeDllHelper.LoadAllDll(path); } #endregion diff --git a/NodeFlow/Env/FlowEnvironmentDecorator.cs b/NodeFlow/Env/FlowEnvironmentDecorator.cs index 9dfcaa3..2597bd1 100644 --- a/NodeFlow/Env/FlowEnvironmentDecorator.cs +++ b/NodeFlow/Env/FlowEnvironmentDecorator.cs @@ -87,6 +87,7 @@ namespace Serein.NodeFlow.Env public string EnvName => currentFlowEnvironment.EnvName; + public string ProjectFileLocation => currentFlowEnvironment.EnvName; public bool IsGlobalInterrupt => currentFlowEnvironment.IsGlobalInterrupt; diff --git a/NodeFlow/Env/RemoteFlowEnvironment.cs b/NodeFlow/Env/RemoteFlowEnvironment.cs index 2ae6593..f4a2f48 100644 --- a/NodeFlow/Env/RemoteFlowEnvironment.cs +++ b/NodeFlow/Env/RemoteFlowEnvironment.cs @@ -65,6 +65,10 @@ namespace Serein.NodeFlow.Env public string EnvName => FlowEnvironment.SpaceName; + /// + /// 远程项目的网络位置(WebSocket + IP + 端口 : 远程主机的文件路径) + /// + public string ProjectFileLocation { get; set; } = string.Empty; public bool IsGlobalInterrupt => false; public bool IsControlRemoteEnv => true; diff --git a/NodeFlow/Tool/AssemblyLoader.cs b/NodeFlow/Tool/AssemblyLoader.cs new file mode 100644 index 0000000..6e68057 --- /dev/null +++ b/NodeFlow/Tool/AssemblyLoader.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.Loader; +using System.Text; +using System.Threading.Tasks; + +namespace Serein.NodeFlow.Tool +{ + /// + /// 程序集加载器 + /// + public class AssemblyLoader + { + private string _basePath; + private AssemblyLoadContext context; + private Dictionary dicTypes = new Dictionary(); + + public AssemblyLoader(string basePath) + { + _basePath = basePath; + } + + public Type Load(string dllFileName, string typeName) + { + context = new AssemblyLoadContext(dllFileName); + context.Resolving += Context_Resolving; + //需要绝对路径 + string path = Path.Combine(_basePath, dllFileName); + if (File.Exists(path)) + { + try + { + using (var stream = File.OpenRead(path)) + { + Assembly assembly = context.LoadFromStream(stream); + Type type = assembly.GetType(typeName); + dicTypes.Add(typeName, type); + return type; + } + } + catch (Exception ex) + { + Console.WriteLine($"加载节点{dllFileName}-{typeName}发生异常:{ex.Message},{ex.StackTrace}"); + } + + } + else + { + Console.WriteLine($"节点动态库{dllFileName}不存在:{path}"); + } + return null; + } + + /// + /// 加载依赖文件 + /// + /// + /// + /// + private Assembly Context_Resolving(AssemblyLoadContext context, AssemblyName assemblyName) + { + string expectedPath = Path.Combine(_basePath, assemblyName.Name + ".dll"); ; + if (File.Exists(expectedPath)) + { + try + { + using (var stream = File.OpenRead(expectedPath)) + { + return context.LoadFromStream(stream); + } + } + catch (Exception ex) + { + Console.WriteLine($"加载节点{expectedPath}发生异常:{ex.Message},{ex.StackTrace}"); + } + } + else + { + Console.WriteLine($"依赖文件不存在:{expectedPath}"); + } + return null; + } + } +} diff --git a/NodeFlow/Tool/FlowLibraryManagement.cs b/NodeFlow/Tool/FlowLibraryManagement.cs index 6326c9d..ab3cc66 100644 --- a/NodeFlow/Tool/FlowLibraryManagement.cs +++ b/NodeFlow/Tool/FlowLibraryManagement.cs @@ -220,6 +220,10 @@ namespace Serein.NodeFlow.Tool 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 = () => { @@ -312,7 +316,7 @@ namespace Serein.NodeFlow.Tool /// /// 创建新的加载上下文 /// - /// 类库主 + /// 类库路径 /// public FlowLibraryAssemblyContext(string sereinFlowLibraryPath, string name) : base(name, isCollectible: true) { @@ -350,15 +354,15 @@ namespace Serein.NodeFlow.Tool //return null; // 如果没有找到,返回 null } } - public static class PluginAssemblyContextExtensions - { + //public static class PluginAssemblyContextExtensions + //{ - public static Assembly FromAssemblyPath(this AssemblyLoadContext context, string path) - { + // public static Assembly FromAssemblyPath(this AssemblyLoadContext context, string path) + // { - return context.LoadFromAssemblyPath(path); + // return context.LoadFromAssemblyPath(path); - } + // } - } + //} } diff --git a/NodeFlow/Tool/NodeMethodDetailsHelper.cs b/NodeFlow/Tool/NodeMethodDetailsHelper.cs index bd16930..63b0dbd 100644 --- a/NodeFlow/Tool/NodeMethodDetailsHelper.cs +++ b/NodeFlow/Tool/NodeMethodDetailsHelper.cs @@ -172,11 +172,12 @@ public static class NodeMethodDetailsHelper if (method == null) return string.Empty; string methodName = method.Name; - string returnType = method.ReturnType.Name; + //string returnType = method.ReturnType.Name; string parameters = string.Join(", ", method.GetParameters() .Select(p => $"{p.ParameterType.Name} {p.Name}")); - return $"{methodName}({parameters}) : {returnType}"; + return $"{methodName}({parameters})"; + //return $"{methodName}({parameters}) : {returnType}"; } public static bool IsGenericTask(Type returnType, out Type? taskResult) { diff --git a/Workbench/MainWindow.xaml.cs b/Workbench/MainWindow.xaml.cs index fe6ba11..4aa9323 100644 --- a/Workbench/MainWindow.xaml.cs +++ b/Workbench/MainWindow.xaml.cs @@ -1372,7 +1372,14 @@ namespace Serein.Workbench { // 创建一个 DataObject 用于拖拽操作,并设置拖拽效果 var dragData = new DataObject(MouseNodeType.CreateBaseNodeInCanvas, control.GetType()); - DragDrop.DoDragDrop(control, dragData, DragDropEffects.Move); + try + { + DragDrop.DoDragDrop(control, dragData, DragDropEffects.Move); + } + catch (Exception ex) + { + SereinEnv.WriteLine(ex); + } } } diff --git a/Workbench/Node/NodeControlViewModelBase.cs b/Workbench/Node/NodeControlViewModelBase.cs index ed58ff9..f2b891d 100644 --- a/Workbench/Node/NodeControlViewModelBase.cs +++ b/Workbench/Node/NodeControlViewModelBase.cs @@ -9,6 +9,7 @@ namespace Serein.Workbench.Node.ViewModel { public abstract class NodeControlViewModelBase { + ///// ///// 对应的节点实体类 ///// @@ -22,6 +23,8 @@ namespace Serein.Workbench.Node.ViewModel private bool isInterrupt; + private bool isReadonlyOnView = true; + ///// ///// 控制中断状态的视觉效果 ///// @@ -34,7 +37,14 @@ namespace Serein.Workbench.Node.ViewModel OnPropertyChanged(); } } - + /// + /// 工作台预览基本节点时,避免其中的文本框响应拖拽事件导致卡死 + /// + public bool IsEnabledOnView { get => isReadonlyOnView; set + { + OnPropertyChanged(); isReadonlyOnView = value; + } + } public event PropertyChangedEventHandler? PropertyChanged; diff --git a/Workbench/Node/View/ConditionNodeControl.xaml b/Workbench/Node/View/ConditionNodeControl.xaml index f6f8c07..ec950e3 100644 --- a/Workbench/Node/View/ConditionNodeControl.xaml +++ b/Workbench/Node/View/ConditionNodeControl.xaml @@ -91,7 +91,7 @@ - diff --git a/Workbench/Node/View/ConditionNodeControl.xaml.cs b/Workbench/Node/View/ConditionNodeControl.xaml.cs index f1ce898..eeb295a 100644 --- a/Workbench/Node/View/ConditionNodeControl.xaml.cs +++ b/Workbench/Node/View/ConditionNodeControl.xaml.cs @@ -12,7 +12,9 @@ namespace Serein.Workbench.Node.View { // 窗体初始化需要 base.ViewModel = new ConditionNodeControlViewModel (new SingleConditionNode(null)); + base.ViewModel.IsEnabledOnView = false; DataContext = ViewModel; + InitializeComponent(); } diff --git a/Workbench/Node/View/ConditionRegionControl.xaml.cs b/Workbench/Node/View/ConditionRegionControl.xaml.cs index d598733..3fda7e3 100644 --- a/Workbench/Node/View/ConditionRegionControl.xaml.cs +++ b/Workbench/Node/View/ConditionRegionControl.xaml.cs @@ -13,6 +13,7 @@ namespace Serein.Workbench.Node.View public ConditionRegionControl() : base() { + base.ViewModel.IsEnabledOnView = false; InitializeComponent(); } diff --git a/Workbench/Node/View/ExpOpNodeControl.xaml b/Workbench/Node/View/ExpOpNodeControl.xaml index 54f3794..81c8d8d 100644 --- a/Workbench/Node/View/ExpOpNodeControl.xaml +++ b/Workbench/Node/View/ExpOpNodeControl.xaml @@ -39,7 +39,7 @@ - + diff --git a/Workbench/Node/View/ExpOpNodeControl.xaml.cs b/Workbench/Node/View/ExpOpNodeControl.xaml.cs index 6b0f814..f46b4a5 100644 --- a/Workbench/Node/View/ExpOpNodeControl.xaml.cs +++ b/Workbench/Node/View/ExpOpNodeControl.xaml.cs @@ -12,6 +12,7 @@ namespace Serein.Workbench.Node.View { // 窗体初始化需要 ViewModel = new ExpOpNodeControlViewModel(new SingleExpOpNode(null)); + base.ViewModel.IsEnabledOnView = false; DataContext = ViewModel; InitializeComponent(); } diff --git a/Workbench/Node/View/GlobalDataControl.xaml b/Workbench/Node/View/GlobalDataControl.xaml index 56b23c3..481dacb 100644 --- a/Workbench/Node/View/GlobalDataControl.xaml +++ b/Workbench/Node/View/GlobalDataControl.xaml @@ -54,7 +54,7 @@ - diff --git a/Workbench/Node/View/GlobalDataControl.xaml.cs b/Workbench/Node/View/GlobalDataControl.xaml.cs index 0d79af3..08f4abf 100644 --- a/Workbench/Node/View/GlobalDataControl.xaml.cs +++ b/Workbench/Node/View/GlobalDataControl.xaml.cs @@ -12,6 +12,7 @@ namespace Serein.Workbench.Node.View { // 窗体初始化需要 base.ViewModel = new GlobalDataNodeControlViewModel(new SingleGlobalDataNode(null)); + base.ViewModel.IsEnabledOnView = false; DataContext = ViewModel; InitializeComponent(); } diff --git a/Workbench/Node/View/ScriptNodeControl.xaml b/Workbench/Node/View/ScriptNodeControl.xaml index b7d0808..ed26c9f 100644 --- a/Workbench/Node/View/ScriptNodeControl.xaml +++ b/Workbench/Node/View/ScriptNodeControl.xaml @@ -59,7 +59,7 @@ - + diff --git a/Workbench/Node/View/ScriptNodeControl.xaml.cs b/Workbench/Node/View/ScriptNodeControl.xaml.cs index 7a3f1d0..d066bd2 100644 --- a/Workbench/Node/View/ScriptNodeControl.xaml.cs +++ b/Workbench/Node/View/ScriptNodeControl.xaml.cs @@ -29,6 +29,9 @@ namespace Serein.Workbench.Node.View public ScriptNodeControl() { + base.ViewModel = new ScriptNodeControlViewModel(null); + base.ViewModel.IsEnabledOnView = false; + base.DataContext = viewModel; InitializeComponent(); } public ScriptNodeControl(ScriptNodeControlViewModel viewModel) : base(viewModel) diff --git a/Workbench/Node/View/UINodeControl.xaml.cs b/Workbench/Node/View/UINodeControl.xaml.cs index 1ffd067..5ba5aa5 100644 --- a/Workbench/Node/View/UINodeControl.xaml.cs +++ b/Workbench/Node/View/UINodeControl.xaml.cs @@ -24,6 +24,7 @@ namespace Serein.Workbench.Node.View { public UINodeControl() { + base.ViewModel.IsEnabledOnView = true; InitializeComponent(); } diff --git a/Workbench/Node/ViewModel/ConditionNodeControlViewModel.cs b/Workbench/Node/ViewModel/ConditionNodeControlViewModel.cs index 81ab99d..90bec05 100644 --- a/Workbench/Node/ViewModel/ConditionNodeControlViewModel.cs +++ b/Workbench/Node/ViewModel/ConditionNodeControlViewModel.cs @@ -8,6 +8,7 @@ namespace Serein.Workbench.Node.ViewModel /// public class ConditionNodeControlViewModel : NodeControlViewModelBase { + public new SingleConditionNode NodeModel { get; } /// diff --git a/Workbench/Serein.WorkBench.csproj b/Workbench/Serein.WorkBench.csproj index 7423f23..e4bc66e 100644 --- a/Workbench/Serein.WorkBench.csproj +++ b/Workbench/Serein.WorkBench.csproj @@ -57,9 +57,13 @@ + + + + diff --git a/Workbench/Themes/MethodDetailsControl.xaml b/Workbench/Themes/MethodDetailsControl.xaml index 9fda70f..2be2f67 100644 --- a/Workbench/Themes/MethodDetailsControl.xaml +++ b/Workbench/Themes/MethodDetailsControl.xaml @@ -169,7 +169,7 @@ - +