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