mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-02 15:50:47 +08:00
环境接口新增了加载项目文件路径,方便类库在Init事件中自动加载具体的依赖
This commit is contained in:
@@ -663,6 +663,12 @@ namespace Serein.Library.Api
|
||||
/// </summary>
|
||||
string EnvName { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 项目文件位置
|
||||
/// </summary>
|
||||
string ProjectFileLocation { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否全局中断
|
||||
/// </summary>
|
||||
@@ -699,6 +705,7 @@ namespace Serein.Library.Api
|
||||
/// </summary>
|
||||
UIContextOperation UIContextOperation { get; }
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region 基本接口
|
||||
@@ -1033,6 +1040,7 @@ namespace Serein.Library.Api
|
||||
/// </summary>
|
||||
/// <param name="assemblyFullName">程序集的名称</param>
|
||||
bool TryUnloadLibrary(string assemblyFullName);
|
||||
|
||||
/// <summary>
|
||||
/// 运行时加载
|
||||
/// </summary>
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -75,6 +75,7 @@ namespace Serein.Library
|
||||
{
|
||||
// 设置获取中断的委托
|
||||
_getInterruptTask = () => NodeModel.Env.IOC.Get<FlowInterruptTool>().WaitTriggerAsync(NodeModel.Guid);
|
||||
|
||||
}
|
||||
else if (!state)
|
||||
{
|
||||
|
||||
@@ -449,7 +449,6 @@ namespace Serein.Library
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 更新节点数据,并检查监视表达式是否生效
|
||||
/// </summary>
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.13.0" />
|
||||
|
||||
<PackageReference Include="Microsoft.Extensions.ObjectPool" Version="9.0.0" />
|
||||
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
|
||||
100
Library/Utils/DynamicCompiler.cs
Normal file
100
Library/Utils/DynamicCompiler.cs
Normal file
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// 动态编译
|
||||
/// </summary>
|
||||
public class DynamicCompiler
|
||||
{
|
||||
private readonly HashSet<MetadataReference> _references = new HashSet<MetadataReference>();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加依赖程序集(通过类型)
|
||||
/// </summary>
|
||||
/// <param name="type">类型所在的程序集</param>
|
||||
public void AddReference(Type type)
|
||||
{
|
||||
var assemblyLocation = type.Assembly.Location;
|
||||
if (!string.IsNullOrEmpty(assemblyLocation))
|
||||
{
|
||||
_references.Add(MetadataReference.CreateFromFile(assemblyLocation));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加依赖程序集(通过文件路径)
|
||||
/// </summary>
|
||||
/// <param name="assemblyPath">程序集文件路径</param>
|
||||
public void AddReference(string assemblyPath)
|
||||
{
|
||||
if (File.Exists(assemblyPath))
|
||||
{
|
||||
_references.Add(MetadataReference.CreateFromFile(assemblyPath));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 编译 C# 代码并返回程序集
|
||||
/// </summary>
|
||||
/// <param name="code">C# 代码文本</param>
|
||||
/// <param name="assemblyName">程序集名称(可选)</param>
|
||||
/// <returns>成功返回 Assembly,失败返回 null</returns>
|
||||
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());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -75,7 +75,6 @@ namespace Serein.Library.Utils
|
||||
/// <summary>
|
||||
/// 使用 ObjectPool 来复用 TriggerResult 对象
|
||||
/// </summary>
|
||||
// 示例 TriggerResult 对象池
|
||||
public class TriggerResultPool<TResult>
|
||||
{
|
||||
private readonly ConcurrentExpandingObjectPool<TriggerResult<TResult>> _objectPool;
|
||||
|
||||
@@ -54,6 +54,11 @@ namespace Serein.Library.Utils.SereinExpression
|
||||
/// <exception cref="NotSupportedException"></exception>
|
||||
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");
|
||||
|
||||
@@ -231,6 +231,12 @@ namespace Serein.NodeFlow.Env
|
||||
/// </summary>
|
||||
public string EnvName { get; set; } = SpaceName;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 本地加载的项目文件路径
|
||||
/// </summary>
|
||||
public string ProjectFileLocation { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 是否全局中断
|
||||
/// </summary>
|
||||
@@ -526,6 +532,7 @@ namespace Serein.NodeFlow.Env
|
||||
/// <param name="filePath"></param>
|
||||
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
|
||||
/// <returns></returns>
|
||||
public bool LoadNativeLibraryOfRuning(string file)
|
||||
{
|
||||
|
||||
return NativeDllHelper.LoadDll(file);
|
||||
}
|
||||
|
||||
@@ -1421,7 +1429,7 @@ namespace Serein.NodeFlow.Env
|
||||
/// <param name="isRecurrence">是否递归加载</param>
|
||||
public void LoadAllNativeLibraryOfRuning(string path, bool isRecurrence = true)
|
||||
{
|
||||
NativeDllHelper.LoadAllDll(path, isRecurrence);
|
||||
NativeDllHelper.LoadAllDll(path);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -87,6 +87,7 @@ namespace Serein.NodeFlow.Env
|
||||
|
||||
|
||||
public string EnvName => currentFlowEnvironment.EnvName;
|
||||
public string ProjectFileLocation => currentFlowEnvironment.EnvName;
|
||||
|
||||
public bool IsGlobalInterrupt => currentFlowEnvironment.IsGlobalInterrupt;
|
||||
|
||||
|
||||
@@ -65,6 +65,10 @@ namespace Serein.NodeFlow.Env
|
||||
|
||||
public string EnvName => FlowEnvironment.SpaceName;
|
||||
|
||||
/// <summary>
|
||||
/// 远程项目的网络位置(WebSocket + IP + 端口 : 远程主机的文件路径)
|
||||
/// </summary>
|
||||
public string ProjectFileLocation { get; set; } = string.Empty;
|
||||
public bool IsGlobalInterrupt => false;
|
||||
|
||||
public bool IsControlRemoteEnv => true;
|
||||
|
||||
86
NodeFlow/Tool/AssemblyLoader.cs
Normal file
86
NodeFlow/Tool/AssemblyLoader.cs
Normal file
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// 程序集加载器
|
||||
/// </summary>
|
||||
public class AssemblyLoader
|
||||
{
|
||||
private string _basePath;
|
||||
private AssemblyLoadContext context;
|
||||
private Dictionary<string, Type> dicTypes = new Dictionary<string, Type>();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载依赖文件
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="assemblyName"></param>
|
||||
/// <returns></returns>
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
/// <summary>
|
||||
/// 创建新的加载上下文
|
||||
/// </summary>
|
||||
/// <param name="sereinFlowLibraryPath">类库主</param>
|
||||
/// <param name="sereinFlowLibraryPath">类库路径</param>
|
||||
/// <param name="name"></param>
|
||||
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);
|
||||
|
||||
}
|
||||
// }
|
||||
|
||||
}
|
||||
//}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace Serein.Workbench.Node.ViewModel
|
||||
{
|
||||
public abstract class NodeControlViewModelBase
|
||||
{
|
||||
|
||||
///// <summary>
|
||||
///// 对应的节点实体类
|
||||
///// </summary>
|
||||
@@ -22,6 +23,8 @@ namespace Serein.Workbench.Node.ViewModel
|
||||
|
||||
|
||||
private bool isInterrupt;
|
||||
private bool isReadonlyOnView = true;
|
||||
|
||||
///// <summary>
|
||||
///// 控制中断状态的视觉效果
|
||||
///// </summary>
|
||||
@@ -34,7 +37,14 @@ namespace Serein.Workbench.Node.ViewModel
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 工作台预览基本节点时,避免其中的文本框响应拖拽事件导致卡死
|
||||
/// </summary>
|
||||
public bool IsEnabledOnView { get => isReadonlyOnView; set
|
||||
{
|
||||
OnPropertyChanged(); isReadonlyOnView = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBox Grid.Column="0" Background="#FEFAF4" MinWidth="100" Text="{Binding NodeModel.Expression, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
<TextBox IsEnabled="{Binding IsEnabledOnView}" Grid.Column="0" Background="#FEFAF4" MinWidth="100" Text="{Binding NodeModel.Expression, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Center"/>
|
||||
|
||||
<local:ResultJunctionControl Grid.Column="1" MyNode="{Binding NodeModel}" x:Name="ResultJunctionControl" HorizontalAlignment="Right"/>
|
||||
|
||||
@@ -12,7 +12,9 @@ namespace Serein.Workbench.Node.View
|
||||
{
|
||||
// 窗体初始化需要
|
||||
base.ViewModel = new ConditionNodeControlViewModel (new SingleConditionNode(null));
|
||||
base.ViewModel.IsEnabledOnView = false;
|
||||
DataContext = ViewModel;
|
||||
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace Serein.Workbench.Node.View
|
||||
|
||||
public ConditionRegionControl() : base()
|
||||
{
|
||||
base.ViewModel.IsEnabledOnView = false;
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
<ColumnDefinition Width="auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<local:ArgJunctionControl Grid.Column="0" x:Name="ArgJunctionControl" ArgIndex="0" MyNode="{Binding NodeModel}" />
|
||||
<TextBox Grid.Column="1" Text="{Binding NodeModel.Expression, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Stretch"></TextBox>
|
||||
<TextBox Grid.Column="1" IsEnabled="{Binding IsEnabledOnView}" Text="{Binding NodeModel.Expression, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Stretch"></TextBox>
|
||||
<local:ResultJunctionControl Grid.Column="2" MyNode="{Binding NodeModel}" x:Name="ResultJunctionControl" HorizontalAlignment="Right"/>
|
||||
</Grid>
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace Serein.Workbench.Node.View
|
||||
{
|
||||
// 窗体初始化需要
|
||||
ViewModel = new ExpOpNodeControlViewModel(new SingleExpOpNode(null));
|
||||
base.ViewModel.IsEnabledOnView = false;
|
||||
DataContext = ViewModel;
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
|
||||
<StackPanel Grid.Row="0" Grid.Column="0" Orientation="Horizontal">
|
||||
<TextBlock Text="全局数据名称" Margin="2" HorizontalAlignment="Stretch" VerticalAlignment="Center"/>
|
||||
<TextBox MinWidth="50" Margin="2" Text="{Binding NodeModel.KeyName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
<TextBox IsEnabled="{Binding IsEnabledOnView}" MinWidth="50" Margin="2" Text="{Binding NodeModel.KeyName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Center">
|
||||
</TextBox>
|
||||
<Button Content="EXP" Command="{Binding CommandCopyDataExp}" Height="17.2"></Button>
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace Serein.Workbench.Node.View
|
||||
{
|
||||
// 窗体初始化需要
|
||||
base.ViewModel = new GlobalDataNodeControlViewModel(new SingleGlobalDataNode(null));
|
||||
base.ViewModel.IsEnabledOnView = false;
|
||||
DataContext = ViewModel;
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
<!--<Button Content="刷新 " Command="{Binding CommandCopyDataExp}" Height="17.2" Margin="2,0,0,0"></Button>-->
|
||||
</StackPanel>
|
||||
<themes:MethodDetailsControl Grid.Row="1" x:Name="MethodDetailsControl" MethodDetails="{Binding NodeModel.MethodDetails}"/>
|
||||
<TextBox Grid.Row="2" MinHeight="20" MinWidth="100" MaxWidth="270" TextWrapping="Wrap" AcceptsReturn="True" Text="{Binding Script}"></TextBox>
|
||||
<TextBox Grid.Row="2" MinHeight="20" MinWidth="100" MaxWidth="270" TextWrapping="Wrap" AcceptsReturn="True" IsEnabled="{Binding IsEnabledOnView}" Text="{Binding Script}"></TextBox>
|
||||
<Grid Grid.Row="3" >
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="50"/>
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -24,6 +24,7 @@ namespace Serein.Workbench.Node.View
|
||||
{
|
||||
public UINodeControl()
|
||||
{
|
||||
base.ViewModel.IsEnabledOnView = true;
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace Serein.Workbench.Node.ViewModel
|
||||
/// </summary>
|
||||
public class ConditionNodeControlViewModel : NodeControlViewModelBase
|
||||
{
|
||||
|
||||
public new SingleConditionNode NodeModel { get; }
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -57,9 +57,13 @@
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
|
||||
|
||||
<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" />-->
|
||||
<!--<PackageReference Include="ZXing.Net.Bindings.ImageSharp" Version="0.16.15" />-->
|
||||
|
||||
@@ -169,7 +169,7 @@
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBox Grid.Column="0" MinWidth="50" Text="{Binding DataValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
<TextBox Grid.Column="0" MinWidth="50" Text="{Binding DataValue, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</Setter.Value>
|
||||
|
||||
Reference in New Issue
Block a user