mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-12 04:29:25 +08:00
尝试使用源生成器规范NodeModel代码逻辑
This commit is contained in:
@@ -1,9 +1,7 @@
|
||||
using Newtonsoft.Json;
|
||||
using Serein.Library.Entity;
|
||||
using Serein.NodeFlow;
|
||||
using Serein.NodeFlow.Tool;
|
||||
using System.Diagnostics;
|
||||
using Serein.Library;
|
||||
using System.Windows;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace Serein.Workbench
|
||||
{
|
||||
@@ -20,6 +18,9 @@ namespace Serein.Workbench
|
||||
public App()
|
||||
{
|
||||
// TestExp();
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
protected override void OnExit(ExitEventArgs e)
|
||||
@@ -32,9 +33,11 @@ namespace Serein.Workbench
|
||||
window.Close();
|
||||
}
|
||||
}
|
||||
|
||||
private void Application_Startup(object sender, StartupEventArgs e)
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() => { });
|
||||
|
||||
|
||||
// 检查是否传入了参数
|
||||
if (e.Args.Length == 1)
|
||||
{
|
||||
@@ -63,7 +66,7 @@ namespace Serein.Workbench
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
else if(1== 1)
|
||||
else if(1 == 1)
|
||||
{
|
||||
//string filePath = @"F:\临时\project\new project.dnf";
|
||||
|
||||
|
||||
@@ -49,12 +49,12 @@ namespace Serein.Workbench
|
||||
|
||||
// 异步写入日志到文件
|
||||
// Task.Run(() => File.AppendAllText("log.txt", text));
|
||||
|
||||
FlushLog();
|
||||
// 如果日志达到阈值,立即刷新
|
||||
if (logBuffer.Length > flushThreshold)
|
||||
{
|
||||
FlushLog();
|
||||
}
|
||||
//if (logBuffer.Length > flushThreshold)
|
||||
//{
|
||||
// FlushLog();
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +75,11 @@ namespace Serein.Workbench
|
||||
: logBuffer.ToString();
|
||||
logBuffer.Remove(0, logContent.Length); // 清空已更新的部分
|
||||
|
||||
LogTextBox.AppendText(logContent);
|
||||
LogTextBox.Dispatcher.Invoke(() =>
|
||||
{
|
||||
LogTextBox.AppendText(logContent);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// 不必每次都修剪日志,当行数超过限制20%时再修剪
|
||||
|
||||
@@ -1,35 +1,22 @@
|
||||
using Microsoft.Win32;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Serein.Library;
|
||||
using Serein.Library.Api;
|
||||
using Serein.Library.Entity;
|
||||
using Serein.Library.Enums;
|
||||
using Serein.Library.Utils;
|
||||
using Serein.NodeFlow;
|
||||
using Serein.NodeFlow.Base;
|
||||
using Serein.NodeFlow.Model;
|
||||
using Serein.Library.Utils.SereinExpression;
|
||||
using Serein.NodeFlow.Tool;
|
||||
using Serein.NodeFlow.Tool.SereinExpression;
|
||||
using Serein.Workbench.Node;
|
||||
using Serein.Workbench.Node.View;
|
||||
using Serein.Workbench.Node.ViewModel;
|
||||
using Serein.Workbench.Themes;
|
||||
using Serein.Workbench.tool;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Text.Json;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Interop;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Animation;
|
||||
using System.Windows.Media.Media3D;
|
||||
using System.Windows.Shapes;
|
||||
using System.Windows.Threading;
|
||||
using System.Xml.Linq;
|
||||
using DataObject = System.Windows.DataObject;
|
||||
|
||||
namespace Serein.Workbench
|
||||
@@ -50,7 +37,6 @@ namespace Serein.Workbench
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Interaction logic for MainWindow.xaml,第一次用git,不太懂
|
||||
@@ -60,12 +46,12 @@ namespace Serein.Workbench
|
||||
/// <summary>
|
||||
/// 全局捕获Console输出事件,打印在这个窗体里面
|
||||
/// </summary>
|
||||
private readonly LogWindow logWindow;
|
||||
private readonly LogWindow LogOutWindow = new LogWindow();
|
||||
|
||||
/// <summary>
|
||||
/// 流程运行环境
|
||||
/// 流程接口
|
||||
/// </summary>
|
||||
private IFlowEnvironment FlowEnvironment { get; }
|
||||
private IFlowEnvironment EnvDecorator { get; }
|
||||
private MainWindowViewModel ViewModel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -154,18 +140,20 @@ namespace Serein.Workbench
|
||||
private readonly TranslateTransform translateTransform;
|
||||
#endregion
|
||||
|
||||
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
logWindow = InitConsoleOut(); // 重定向 Console 输出
|
||||
|
||||
ViewModel = new MainWindowViewModel(this);
|
||||
FlowEnvironment = ViewModel.FlowEnvironment;
|
||||
ViewObjectViewer.FlowEnvironment = FlowEnvironment;
|
||||
IOCObjectViewer.FlowEnvironment = FlowEnvironment;
|
||||
EnvDecorator = ViewModel.FlowEnvironment;
|
||||
ViewObjectViewer.FlowEnvironment = EnvDecorator;
|
||||
IOCObjectViewer.FlowEnvironment = EnvDecorator;
|
||||
|
||||
|
||||
//this.FlowEnvironment.SetConsoleOut((msg) => LogOutWindow.AppendText(msg), () => LogOutWindow.Clear()); // 设置输出
|
||||
InitFlowEnvironmentEvent(); // 配置环境事件
|
||||
|
||||
|
||||
canvasTransformGroup = new TransformGroup();
|
||||
scaleTransform = new ScaleTransform();
|
||||
translateTransform = new TranslateTransform();
|
||||
@@ -178,65 +166,91 @@ namespace Serein.Workbench
|
||||
|
||||
if (App.FlowProjectData is not null)
|
||||
{
|
||||
FlowEnvironment.LoadProject(App.FlowProjectData, App.FileDataPath); // 加载项目
|
||||
EnvDecorator.LoadProject(new FlowEnvInfo { Project = App.FlowProjectData }, App.FileDataPath); // 加载项目
|
||||
}
|
||||
|
||||
|
||||
IOCObjectViewer.SelectObj += ViewObjectViewer.LoadObjectInformation;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化环境事件
|
||||
/// </summary>
|
||||
private void InitFlowEnvironmentEvent()
|
||||
{
|
||||
FlowEnvironment.OnDllLoad += FlowEnvironment_DllLoadEvent;
|
||||
// FlowEnvironment.OnLoadNode += FlowEnvironment_NodeLoadEvent;
|
||||
FlowEnvironment.OnProjectLoaded += FlowEnvironment_OnProjectLoaded;
|
||||
FlowEnvironment.OnStartNodeChange += FlowEnvironment_StartNodeChangeEvent;
|
||||
FlowEnvironment.OnNodeConnectChange += FlowEnvironment_NodeConnectChangeEvemt;
|
||||
FlowEnvironment.OnNodeCreate += FlowEnvironment_NodeCreateEvent;
|
||||
FlowEnvironment.OnNodeRemote += FlowEnvironment_NodeRemoteEvent;
|
||||
FlowEnvironment.OnFlowRunComplete += FlowEnvironment_OnFlowRunComplete;
|
||||
|
||||
// 获取实现类的类型
|
||||
var implementationType = EnvDecorator.CurrentEnv.GetType().Name;
|
||||
EnvDecorator.OnDllLoad += FlowEnvironment_DllLoadEvent;
|
||||
EnvDecorator.OnProjectLoaded += FlowEnvironment_OnProjectLoaded;
|
||||
EnvDecorator.OnStartNodeChange += FlowEnvironment_StartNodeChangeEvent;
|
||||
EnvDecorator.OnNodeConnectChange += FlowEnvironment_NodeConnectChangeEvemt;
|
||||
EnvDecorator.OnNodeCreate += FlowEnvironment_NodeCreateEvent;
|
||||
EnvDecorator.OnNodeRemote += FlowEnvironment_NodeRemoteEvent;
|
||||
EnvDecorator.OnFlowRunComplete += FlowEnvironment_OnFlowRunComplete;
|
||||
|
||||
|
||||
FlowEnvironment.OnMonitorObjectChange += FlowEnvironment_OnMonitorObjectChange;
|
||||
FlowEnvironment.OnNodeInterruptStateChange += FlowEnvironment_OnNodeInterruptStateChange;
|
||||
FlowEnvironment.OnInterruptTrigger += FlowEnvironment_OnInterruptTrigger;
|
||||
|
||||
FlowEnvironment.OnIOCMembersChanged += FlowEnvironment_OnIOCMembersChanged;
|
||||
|
||||
FlowEnvironment.OnNodeLocated += FlowEnvironment_OnNodeLocate;
|
||||
FlowEnvironment.OnNodeMoved += FlowEnvironment_OnNodeMoved;
|
||||
EnvDecorator.OnMonitorObjectChange += FlowEnvironment_OnMonitorObjectChange;
|
||||
EnvDecorator.OnNodeInterruptStateChange += FlowEnvironment_OnNodeInterruptStateChange;
|
||||
EnvDecorator.OnInterruptTrigger += FlowEnvironment_OnInterruptTrigger;
|
||||
|
||||
EnvDecorator.OnIOCMembersChanged += FlowEnvironment_OnIOCMembersChanged;
|
||||
|
||||
EnvDecorator.OnNodeLocated += FlowEnvironment_OnNodeLocate;
|
||||
EnvDecorator.OnNodeMoved += FlowEnvironment_OnNodeMoved;
|
||||
|
||||
EnvDecorator.OnEnvOut += FlowEnvironment_OnEnvOut;
|
||||
this.EnvDecorator.SetConsoleOut(); // 设置输出
|
||||
}
|
||||
|
||||
|
||||
|
||||
private LogWindow InitConsoleOut()
|
||||
/// <summary>
|
||||
/// 移除环境事件
|
||||
/// </summary>
|
||||
private void ResetFlowEnvironmentEvent()
|
||||
{
|
||||
var logWindow = new LogWindow();
|
||||
//logWindow.Show();
|
||||
// 重定向 Console 输出
|
||||
var logTextWriter = new LogTextWriter(msg => logWindow.AppendText(msg), () => logWindow.Clear()); ;
|
||||
Console.SetOut(logTextWriter);
|
||||
return logWindow;
|
||||
EnvDecorator.OnDllLoad -= FlowEnvironment_DllLoadEvent;
|
||||
EnvDecorator.OnProjectLoaded -= FlowEnvironment_OnProjectLoaded;
|
||||
EnvDecorator.OnStartNodeChange -= FlowEnvironment_StartNodeChangeEvent;
|
||||
EnvDecorator.OnNodeConnectChange -= FlowEnvironment_NodeConnectChangeEvemt;
|
||||
EnvDecorator.OnNodeCreate -= FlowEnvironment_NodeCreateEvent;
|
||||
EnvDecorator.OnNodeRemote -= FlowEnvironment_NodeRemoteEvent;
|
||||
EnvDecorator.OnFlowRunComplete -= FlowEnvironment_OnFlowRunComplete;
|
||||
|
||||
|
||||
EnvDecorator.OnMonitorObjectChange -= FlowEnvironment_OnMonitorObjectChange;
|
||||
EnvDecorator.OnNodeInterruptStateChange -= FlowEnvironment_OnNodeInterruptStateChange;
|
||||
EnvDecorator.OnInterruptTrigger -= FlowEnvironment_OnInterruptTrigger;
|
||||
|
||||
EnvDecorator.OnIOCMembersChanged -= FlowEnvironment_OnIOCMembersChanged;
|
||||
|
||||
EnvDecorator.OnNodeLocated -= FlowEnvironment_OnNodeLocate;
|
||||
EnvDecorator.OnNodeMoved -= FlowEnvironment_OnNodeMoved;
|
||||
|
||||
EnvDecorator.OnEnvOut -= FlowEnvironment_OnEnvOut;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#region 窗体加载方法
|
||||
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
}
|
||||
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
|
||||
{
|
||||
logWindow.Close();
|
||||
LogOutWindow.Close();
|
||||
System.Windows.Application.Current.Shutdown();
|
||||
}
|
||||
private void Window_ContentRendered(object sender, EventArgs e)
|
||||
{
|
||||
Console.WriteLine("load project...");
|
||||
var project = App.FlowProjectData;
|
||||
if (project is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
InitializeCanvas(project.Basic.Canvas.Width, project.Basic.Canvas.Lenght);// 设置画布大小
|
||||
InitializeCanvas(project.Basic.Canvas.Width, project.Basic.Canvas.Height);// 设置画布大小
|
||||
foreach (var connection in Connections)
|
||||
{
|
||||
connection.Refresh();
|
||||
@@ -262,6 +276,15 @@ namespace Serein.Workbench
|
||||
|
||||
#region 运行环境事件
|
||||
|
||||
/// <summary>
|
||||
/// 环境内容输出
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
private void FlowEnvironment_OnEnvOut(string value)
|
||||
{
|
||||
LogOutWindow.AppendText(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载完成
|
||||
/// </summary>
|
||||
@@ -278,7 +301,10 @@ namespace Serein.Workbench
|
||||
private void FlowEnvironment_OnFlowRunComplete(FlowEventArgs eventArgs)
|
||||
{
|
||||
Console.WriteLine("-------运行完成---------\r\n");
|
||||
IOCObjectViewer.ClearObjItem();
|
||||
this.Dispatcher.Invoke(() =>
|
||||
{
|
||||
IOCObjectViewer.ClearObjItem();
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -294,20 +320,25 @@ namespace Serein.Workbench
|
||||
|
||||
foreach (var methodDetailsInfo in methodDetailss)
|
||||
{
|
||||
switch (methodDetailsInfo.NodeType)
|
||||
if(!EnumHelper.TryConvertEnum<Library.NodeType>(methodDetailsInfo.NodeType, out var nodeType))
|
||||
{
|
||||
case Library.Enums.NodeType.Action:
|
||||
continue;
|
||||
}
|
||||
switch (nodeType)
|
||||
{
|
||||
case Library.NodeType.Action:
|
||||
dllControl.AddAction(methodDetailsInfo); // 添加动作类型到控件
|
||||
break;
|
||||
case Library.Enums.NodeType.Flipflop:
|
||||
case Library.NodeType.Flipflop:
|
||||
dllControl.AddFlipflop(methodDetailsInfo); // 添加触发器方法到控件
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
var menu = new ContextMenu();
|
||||
menu.Items.Add(CreateMenuItem("卸载", (s,e) =>
|
||||
{
|
||||
if (this.FlowEnvironment.RemoteDll(nodeLibrary.Assembly.FullName))
|
||||
if (this.EnvDecorator.RemoteDll(nodeLibrary.FullName))
|
||||
{
|
||||
DllStackPanel.Children.Remove(dllControl);
|
||||
}
|
||||
@@ -360,6 +391,10 @@ namespace Serein.Workbench
|
||||
ConfigureLineContextMenu(connection); // 设置连接右键事件
|
||||
Connections.Add(connection);
|
||||
EndConnection();
|
||||
connection.Refresh();
|
||||
//UpdateConnections(fromNode);
|
||||
// connection.ArrowPath?.InvalidateVisual();
|
||||
// connection.BezierPath?.InvalidateVisual();
|
||||
};
|
||||
|
||||
|
||||
@@ -415,18 +450,20 @@ namespace Serein.Workbench
|
||||
}
|
||||
}
|
||||
#region 节点树视图
|
||||
if (nodeControl is FlipflopNodeControl flipflopControl) // 判断是否为触发器
|
||||
{
|
||||
var node = flipflopControl?.ViewModel?.Node;
|
||||
if (node is not null)
|
||||
{
|
||||
NodeTreeViewer.RemoteGlobalFlipFlop(node); // 从全局触发器树树视图中移除
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
this.Dispatcher.Invoke(() =>
|
||||
{
|
||||
if (nodeControl is FlipflopNodeControl flipflopControl) // 判断是否为触发器
|
||||
{
|
||||
var node = flipflopControl?.ViewModel?.Node;
|
||||
if (node is not null)
|
||||
{
|
||||
NodeTreeViewer.RemoteGlobalFlipFlop(node); // 从全局触发器树树视图中移除
|
||||
}
|
||||
}
|
||||
|
||||
FlowChartCanvas.Children.Remove(nodeControl);
|
||||
NodeControls.Remove(nodeControl.ViewModel.Node.Guid);
|
||||
});
|
||||
@@ -447,7 +484,7 @@ namespace Serein.Workbench
|
||||
}
|
||||
|
||||
// MethodDetails methodDetailss = eventArgs.MethodDetailss;
|
||||
Position position = eventArgs.Position;
|
||||
PositionOfUI position = eventArgs.Position;
|
||||
|
||||
// 创建对应控件
|
||||
NodeControlBase? nodeControl = nodeModelBase.ControlType switch
|
||||
@@ -487,7 +524,7 @@ namespace Serein.Workbench
|
||||
var node = nodeControl?.ViewModel?.Node;
|
||||
if(node is not null)
|
||||
{
|
||||
NodeTreeViewer.AddGlobalFlipFlop(FlowEnvironment, node); // 新增的触发器节点添加到全局触发器
|
||||
NodeTreeViewer.AddGlobalFlipFlop(EnvDecorator, node); // 新增的触发器节点添加到全局触发器
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
@@ -520,7 +557,7 @@ namespace Serein.Workbench
|
||||
var node = newStartNodeControl?.ViewModel?.Node;
|
||||
if (node is not null)
|
||||
{
|
||||
NodeTreeViewer.LoadNodeTreeOfStartNode(FlowEnvironment, node);
|
||||
NodeTreeViewer.LoadNodeTreeOfStartNode(EnvDecorator, node);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -541,7 +578,7 @@ namespace Serein.Workbench
|
||||
};
|
||||
|
||||
//NodeControlBase nodeControl = GuidToControl(nodeGuid);
|
||||
ViewObjectViewer.Dispatcher.BeginInvoke(() => {
|
||||
ViewObjectViewer.Dispatcher.Invoke(() => {
|
||||
if (ViewObjectViewer.MonitorObj is null) // 如果没有加载过对象
|
||||
{
|
||||
ViewObjectViewer.LoadObjectInformation(monitorKey, eventArgs.NewData); // 加载对象 ViewObjectViewerControl.MonitorType.Obj
|
||||
@@ -566,36 +603,39 @@ namespace Serein.Workbench
|
||||
/// 节点中断状态改变。
|
||||
/// </summary>
|
||||
/// <param name="eventArgs"></param>
|
||||
private void FlowEnvironment_OnNodeInterruptStateChange(NodeInterruptStateChangeEventArgs eventArgs)
|
||||
private void FlowEnvironment_OnNodeInterruptStateChange(NodeInterruptStateChangeEventArgs eventArgs)
|
||||
{
|
||||
string nodeGuid = eventArgs.NodeGuid;
|
||||
if (!TryGetControl(nodeGuid, out var nodeControl)) return;
|
||||
|
||||
if (eventArgs.Class == InterruptClass.None)
|
||||
this.Dispatcher.Invoke(() =>
|
||||
{
|
||||
nodeControl.ViewModel.IsInterrupt = false;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
nodeControl.ViewModel.IsInterrupt = true;
|
||||
}
|
||||
|
||||
foreach (var menuItem in nodeControl.ContextMenu.Items)
|
||||
{
|
||||
if (menuItem is MenuItem menu)
|
||||
if (eventArgs.Class == InterruptClass.None)
|
||||
{
|
||||
if ("取消中断".Equals(menu.Header))
|
||||
{
|
||||
menu.Header = "在此中断";
|
||||
}
|
||||
else if ("在此中断".Equals(menu.Header))
|
||||
{
|
||||
menu.Header = "取消中断";
|
||||
}
|
||||
nodeControl.ViewModel.IsInterrupt = false;
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
nodeControl.ViewModel.IsInterrupt = true;
|
||||
}
|
||||
|
||||
foreach (var menuItem in nodeControl.ContextMenu.Items)
|
||||
{
|
||||
if (menuItem is MenuItem menu)
|
||||
{
|
||||
if ("取消中断".Equals(menu.Header))
|
||||
{
|
||||
menu.Header = "在此中断";
|
||||
}
|
||||
else if ("在此中断".Equals(menu.Header))
|
||||
{
|
||||
menu.Header = "取消中断";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@@ -625,7 +665,10 @@ namespace Serein.Workbench
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
private void FlowEnvironment_OnIOCMembersChanged(IOCMembersChangedEventArgs eventArgs)
|
||||
{
|
||||
IOCObjectViewer.AddDependenciesInstance(eventArgs.Key, eventArgs.Instance);
|
||||
this.Dispatcher.Invoke(() =>
|
||||
{
|
||||
IOCObjectViewer.AddDependenciesInstance(eventArgs.Key, eventArgs.Instance);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -635,52 +678,56 @@ namespace Serein.Workbench
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
private void FlowEnvironment_OnNodeLocate(NodeLocatedEventArgs eventArgs)
|
||||
{
|
||||
if (!TryGetControl(eventArgs.NodeGuid, out var nodeControl)) return;
|
||||
//scaleTransform.ScaleX = 1;
|
||||
//scaleTransform.ScaleY = 1;
|
||||
// 获取控件在 FlowChartCanvas 上的相对位置
|
||||
Rect controlBounds = VisualTreeHelper.GetDescendantBounds(nodeControl);
|
||||
Point controlPosition = nodeControl.TransformToAncestor(FlowChartCanvas).Transform(new Point(0, 0));
|
||||
this.Dispatcher.Invoke(() =>
|
||||
{
|
||||
if (!TryGetControl(eventArgs.NodeGuid, out var nodeControl)) return;
|
||||
//scaleTransform.ScaleX = 1;
|
||||
//scaleTransform.ScaleY = 1;
|
||||
// 获取控件在 FlowChartCanvas 上的相对位置
|
||||
Rect controlBounds = VisualTreeHelper.GetDescendantBounds(nodeControl);
|
||||
Point controlPosition = nodeControl.TransformToAncestor(FlowChartCanvas).Transform(new Point(0, 0));
|
||||
|
||||
// 获取控件在画布上的中心点
|
||||
double controlCenterX = controlPosition.X + controlBounds.Width / 2;
|
||||
double controlCenterY = controlPosition.Y + controlBounds.Height / 2;
|
||||
// 获取控件在画布上的中心点
|
||||
double controlCenterX = controlPosition.X + controlBounds.Width / 2;
|
||||
double controlCenterY = controlPosition.Y + controlBounds.Height / 2;
|
||||
|
||||
// 考虑缩放因素计算目标位置的中心点
|
||||
double scaledCenterX = controlCenterX * scaleTransform.ScaleX;
|
||||
double scaledCenterY = controlCenterY * scaleTransform.ScaleY;
|
||||
|
||||
|
||||
//// 计算画布的可视区域大小
|
||||
//double visibleAreaLeft = scaledCenterX;
|
||||
//double visibleAreaTop = scaledCenterY;
|
||||
//double visibleAreaRight = scaledCenterX + FlowChartStackGrid.ActualWidth;
|
||||
//double visibleAreaBottom = scaledCenterY + FlowChartStackGrid.ActualHeight;
|
||||
//// 检查控件中心点是否在可视区域内
|
||||
//bool isInView = scaledCenterX >= visibleAreaLeft && scaledCenterX <= visibleAreaRight &&
|
||||
// scaledCenterY >= visibleAreaTop && scaledCenterY <= visibleAreaBottom;
|
||||
|
||||
//Console.WriteLine($"isInView :{isInView}");
|
||||
|
||||
//if (!isInView)
|
||||
//{
|
||||
//}
|
||||
// 计算平移偏移量,使得控件在可视区域的中心
|
||||
double translateX = scaledCenterX - FlowChartStackGrid.ActualWidth / 2;
|
||||
double translateY = scaledCenterY - FlowChartStackGrid.ActualHeight / 2;
|
||||
|
||||
var translate = this.translateTransform;
|
||||
// 应用平移变换
|
||||
translate.X = 0;
|
||||
translate.Y = 0;
|
||||
translate.X -= translateX;
|
||||
translate.Y -= translateY;
|
||||
|
||||
// 设置RenderTransform以实现移动效果
|
||||
TranslateTransform translateTransform = new TranslateTransform();
|
||||
nodeControl.RenderTransform = translateTransform;
|
||||
ElasticAnimation(nodeControl, translateTransform, 4, 1, 0.5);
|
||||
|
||||
});
|
||||
|
||||
// 考虑缩放因素计算目标位置的中心点
|
||||
double scaledCenterX = controlCenterX * scaleTransform.ScaleX;
|
||||
double scaledCenterY = controlCenterY * scaleTransform.ScaleY;
|
||||
|
||||
|
||||
//// 计算画布的可视区域大小
|
||||
//double visibleAreaLeft = scaledCenterX;
|
||||
//double visibleAreaTop = scaledCenterY;
|
||||
//double visibleAreaRight = scaledCenterX + FlowChartStackGrid.ActualWidth;
|
||||
//double visibleAreaBottom = scaledCenterY + FlowChartStackGrid.ActualHeight;
|
||||
//// 检查控件中心点是否在可视区域内
|
||||
//bool isInView = scaledCenterX >= visibleAreaLeft && scaledCenterX <= visibleAreaRight &&
|
||||
// scaledCenterY >= visibleAreaTop && scaledCenterY <= visibleAreaBottom;
|
||||
|
||||
//Console.WriteLine($"isInView :{isInView}");
|
||||
|
||||
//if (!isInView)
|
||||
//{
|
||||
//}
|
||||
// 计算平移偏移量,使得控件在可视区域的中心
|
||||
double translateX = scaledCenterX - FlowChartStackGrid.ActualWidth / 2;
|
||||
double translateY = scaledCenterY - FlowChartStackGrid.ActualHeight / 2;
|
||||
|
||||
var translate = this.translateTransform;
|
||||
// 应用平移变换
|
||||
translate.X = 0;
|
||||
translate.Y = 0;
|
||||
translate.X -= translateX;
|
||||
translate.Y -= translateY;
|
||||
|
||||
// 设置RenderTransform以实现移动效果
|
||||
TranslateTransform translateTransform = new TranslateTransform();
|
||||
nodeControl.RenderTransform = translateTransform;
|
||||
ElasticAnimation(nodeControl, translateTransform, 4,1,0.5);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -716,6 +763,11 @@ namespace Serein.Workbench
|
||||
nodeControl.RenderTransform = null; // 或者重新设置为默认值
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 节点移动
|
||||
/// </summary>
|
||||
/// <param name="eventArgs"></param>
|
||||
private void FlowEnvironment_OnNodeMoved(NodeMovedEventArgs eventArgs)
|
||||
{
|
||||
if (!TryGetControl(eventArgs.NodeGuid, out var nodeControl)) return;
|
||||
@@ -723,16 +775,23 @@ namespace Serein.Workbench
|
||||
var newLeft = eventArgs.X;
|
||||
var newTop = eventArgs.Y;
|
||||
|
||||
// 限制控件不超出FlowChartCanvas的边界
|
||||
if (newLeft >= 0 && newLeft + nodeControl.ActualWidth <= FlowChartCanvas.ActualWidth)
|
||||
{
|
||||
Canvas.SetLeft(nodeControl, newLeft);
|
||||
}
|
||||
if (newTop >= 0 && newTop + nodeControl.ActualHeight <= FlowChartCanvas.ActualHeight)
|
||||
{
|
||||
Canvas.SetTop(nodeControl, newTop);
|
||||
}
|
||||
this.Dispatcher.Invoke(() => {
|
||||
// 限制控件不超出FlowChartCanvas的边界
|
||||
if (newLeft >= 0 && newLeft + nodeControl.ActualWidth <= FlowChartCanvas.ActualWidth)
|
||||
{
|
||||
Canvas.SetLeft(nodeControl, newLeft);
|
||||
|
||||
}
|
||||
if (newTop >= 0 && newTop + nodeControl.ActualHeight <= FlowChartCanvas.ActualHeight)
|
||||
{
|
||||
Canvas.SetTop(nodeControl, newTop);
|
||||
|
||||
|
||||
}
|
||||
UpdateConnections(nodeControl);
|
||||
});
|
||||
|
||||
|
||||
//Canvas.SetLeft(nodeControl,);
|
||||
//Canvas.SetTop(nodeControl, );
|
||||
}
|
||||
@@ -773,27 +832,28 @@ namespace Serein.Workbench
|
||||
/// <param name="methodDetailss"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
private NodeControlBase? CreateNodeControlOfNodeInfo(NodeInfo nodeInfo, MethodDetails methodDetailss)
|
||||
{
|
||||
// 创建控件实例
|
||||
NodeControlBase nodeControl = nodeInfo.Type switch
|
||||
{
|
||||
$"{NodeStaticConfig.NodeSpaceName}.{nameof(SingleActionNode)}" =>
|
||||
CreateNodeControl<SingleActionNode, ActionNodeControl, ActionNodeControlViewModel>(methodDetailss),// 动作节点控件
|
||||
$"{NodeStaticConfig.NodeSpaceName}.{nameof(SingleFlipflopNode)}" =>
|
||||
CreateNodeControl<SingleFlipflopNode, FlipflopNodeControl, FlipflopNodeControlViewModel>(methodDetailss), // 触发器节点控件
|
||||
//private NodeControlBase? CreateNodeControlOfNodeInfo(NodeInfo nodeInfo, MethodDetails methodDetailss)
|
||||
//{
|
||||
// // 创建控件实例
|
||||
// NodeControlBase nodeControl = nodeInfo.Type switch
|
||||
// {
|
||||
// $"{NodeStaticConfig.NodeSpaceName}.{nameof(SingleActionNode)}" =>
|
||||
// CreateNodeControl<SingleActionNode, ActionNodeControl, ActionNodeControlViewModel>(methodDetailss),// 动作节点控件
|
||||
// $"{NodeStaticConfig.NodeSpaceName}.{nameof(SingleFlipflopNode)}" =>
|
||||
// CreateNodeControl<SingleFlipflopNode, FlipflopNodeControl, FlipflopNodeControlViewModel>(methodDetailss), // 触发器节点控件
|
||||
|
||||
$"{NodeStaticConfig.NodeSpaceName}.{nameof(SingleConditionNode)}" =>
|
||||
CreateNodeControl<SingleConditionNode, ConditionNodeControl, ConditionNodeControlViewModel>(), // 条件表达式控件
|
||||
$"{NodeStaticConfig.NodeSpaceName}.{nameof(SingleExpOpNode)}" =>
|
||||
CreateNodeControl<SingleExpOpNode, ExpOpNodeControl, ExpOpNodeViewModel>(), // 操作表达式控件
|
||||
// $"{NodeStaticConfig.NodeSpaceName}.{nameof(SingleConditionNode)}" =>
|
||||
// CreateNodeControl<SingleConditionNode, ConditionNodeControl, ConditionNodeControlViewModel>(), // 条件表达式控件
|
||||
// $"{NodeStaticConfig.NodeSpaceName}.{nameof(SingleExpOpNode)}" =>
|
||||
// CreateNodeControl<SingleExpOpNode, ExpOpNodeControl, ExpOpNodeViewModel>(), // 操作表达式控件
|
||||
|
||||
// $"{NodeStaticConfig.NodeSpaceName}.{nameof(CompositeConditionNode)}" =>
|
||||
// CreateNodeControl<CompositeConditionNode, ConditionRegionControl, ConditionRegionNodeControlViewModel>(), // 条件区域控件
|
||||
// _ => throw new NotImplementedException($"非预期的节点类型{nodeInfo.Type}"),
|
||||
// };
|
||||
// return nodeControl;
|
||||
//}
|
||||
|
||||
$"{NodeStaticConfig.NodeSpaceName}.{nameof(CompositeConditionNode)}" =>
|
||||
CreateNodeControl<CompositeConditionNode, ConditionRegionControl, ConditionRegionNodeControlViewModel>(), // 条件区域控件
|
||||
_ => throw new NotImplementedException($"非预期的节点类型{nodeInfo.Type}"),
|
||||
};
|
||||
return nodeControl;
|
||||
}
|
||||
/// <summary>
|
||||
/// 加载文件时,添加节点到区域中
|
||||
/// </summary>
|
||||
@@ -908,13 +968,13 @@ namespace Serein.Workbench
|
||||
{
|
||||
if (menuItem.Header.ToString() == "启动触发器")
|
||||
{
|
||||
FlowEnvironment.ActivateFlipflopNode(nodeGuid);
|
||||
EnvDecorator.ActivateFlipflopNode(nodeGuid);
|
||||
|
||||
menuItem.Header = "终结触发器";
|
||||
}
|
||||
else
|
||||
{
|
||||
FlowEnvironment.TerminateFlipflopNode(nodeGuid);
|
||||
EnvDecorator.TerminateFlipflopNode(nodeGuid);
|
||||
menuItem.Header = "启动触发器";
|
||||
|
||||
}
|
||||
@@ -934,19 +994,19 @@ namespace Serein.Workbench
|
||||
|
||||
#region 右键菜单功能 - 中断
|
||||
|
||||
contextMenu.Items.Add(CreateMenuItem("在此中断", (s, e) =>
|
||||
contextMenu.Items.Add(CreateMenuItem("在此中断", async (s, e) =>
|
||||
{
|
||||
if ((s is MenuItem menuItem) && menuItem is not null)
|
||||
{
|
||||
if (nodeControl?.ViewModel?.Node?.DebugSetting?.InterruptClass == InterruptClass.None)
|
||||
{
|
||||
FlowEnvironment.SetNodeInterrupt(nodeGuid, InterruptClass.Branch);
|
||||
await EnvDecorator.SetNodeInterruptAsync(nodeGuid, InterruptClass.Branch);
|
||||
|
||||
menuItem.Header = "取消中断";
|
||||
}
|
||||
else
|
||||
{
|
||||
FlowEnvironment.SetNodeInterrupt(nodeGuid, InterruptClass.None);
|
||||
await EnvDecorator.SetNodeInterruptAsync(nodeGuid, InterruptClass.None);
|
||||
menuItem.Header = "在此中断";
|
||||
|
||||
}
|
||||
@@ -956,8 +1016,8 @@ namespace Serein.Workbench
|
||||
#endregion
|
||||
|
||||
|
||||
contextMenu.Items.Add(CreateMenuItem("设为起点", (s, e) => FlowEnvironment.SetStartNode(nodeGuid)));
|
||||
contextMenu.Items.Add(CreateMenuItem("删除", (s, e) => FlowEnvironment.RemoveNode(nodeGuid)));
|
||||
contextMenu.Items.Add(CreateMenuItem("设为起点", (s, e) => EnvDecorator.SetStartNode(nodeGuid)));
|
||||
contextMenu.Items.Add(CreateMenuItem("删除", (s, e) => EnvDecorator.RemoveNode(nodeGuid)));
|
||||
|
||||
contextMenu.Items.Add(CreateMenuItem("添加 真分支", (s, e) => StartConnection(nodeControl, ConnectionType.IsSucceed)));
|
||||
contextMenu.Items.Add(CreateMenuItem("添加 假分支", (s, e) => StartConnection(nodeControl, ConnectionType.IsFail)));
|
||||
@@ -1034,7 +1094,7 @@ namespace Serein.Workbench
|
||||
// 获取起始节点与终止节点,消除映射关系
|
||||
var fromNodeGuid = connectionToRemove.Start.ViewModel.Node.Guid;
|
||||
var toNodeGuid = connectionToRemove.End.ViewModel.Node.Guid;
|
||||
FlowEnvironment.RemoveConnect(fromNodeGuid, toNodeGuid, connection.Type);
|
||||
EnvDecorator.RemoveConnect(fromNodeGuid, toNodeGuid, connection.Type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1089,7 +1149,7 @@ namespace Serein.Workbench
|
||||
{
|
||||
if (file.EndsWith(".dll"))
|
||||
{
|
||||
FlowEnvironment.LoadDll(file);
|
||||
EnvDecorator.LoadDll(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1189,16 +1249,15 @@ namespace Serein.Workbench
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void FlowChartCanvas_Drop(object sender, DragEventArgs e)
|
||||
private async void FlowChartCanvas_Drop(object sender, DragEventArgs e)
|
||||
{
|
||||
var canvasDropPosition = e.GetPosition(FlowChartCanvas); // 更新画布落点
|
||||
Position position = new Position(canvasDropPosition.X, canvasDropPosition.Y);
|
||||
PositionOfUI position = new PositionOfUI(canvasDropPosition.X, canvasDropPosition.Y);
|
||||
if (e.Data.GetDataPresent(MouseNodeType.CreateDllNodeInCanvas))
|
||||
{
|
||||
if (e.Data.GetData(MouseNodeType.CreateDllNodeInCanvas) is MoveNodeData nodeData)
|
||||
{
|
||||
// 创建DLL文件的节点对象
|
||||
FlowEnvironment.CreateNode(nodeData.NodeControlType, position, nodeData.MethodDetailsInfo);
|
||||
await EnvDecorator.CreateNodeAsync(nodeData.NodeControlType, position, nodeData.MethodDetailsInfo); // 创建DLL文件的节点对象
|
||||
}
|
||||
}
|
||||
else if (e.Data.GetDataPresent(MouseNodeType.CreateBaseNodeInCanvas))
|
||||
@@ -1214,8 +1273,7 @@ namespace Serein.Workbench
|
||||
};
|
||||
if(nodeControlType != NodeControlType.None)
|
||||
{
|
||||
// 创建基础节点对象
|
||||
FlowEnvironment.CreateNode(nodeControlType, position);
|
||||
await EnvDecorator.CreateNodeAsync(nodeControlType, position); // 创建基础节点对象
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1228,7 +1286,7 @@ namespace Serein.Workbench
|
||||
/// <param name="nodeControl"></param>
|
||||
/// <param name="position"></param>
|
||||
/// <returns></returns>
|
||||
private bool TryPlaceNodeInRegion(NodeControlBase nodeControl, Position position)
|
||||
private bool TryPlaceNodeInRegion(NodeControlBase nodeControl, PositionOfUI position)
|
||||
{
|
||||
var point = new Point(position.X, position.Y);
|
||||
HitTestResult hitTestResult = VisualTreeHelper.HitTest(FlowChartCanvas, point);
|
||||
@@ -1337,7 +1395,7 @@ namespace Serein.Workbench
|
||||
var newLeft = oldLeft + deltaX;
|
||||
var newTop = oldTop + deltaY;
|
||||
|
||||
this.FlowEnvironment.MoveNode(nodeControlMain.ViewModel.Node.Guid, newLeft, newTop); // 移动节点
|
||||
this.EnvDecorator.MoveNode(nodeControlMain.ViewModel.Node.Guid, newLeft, newTop); // 移动节点
|
||||
|
||||
// 计算控件实际移动的距离
|
||||
var actualDeltaX = newLeft - oldLeft;
|
||||
@@ -1350,7 +1408,7 @@ namespace Serein.Workbench
|
||||
{
|
||||
var otherNewLeft = Canvas.GetLeft(nodeControl) + actualDeltaX;
|
||||
var otherNewTop = Canvas.GetTop(nodeControl) + actualDeltaY;
|
||||
this.FlowEnvironment.MoveNode(nodeControl.ViewModel.Node.Guid, otherNewLeft, otherNewTop); // 移动节点
|
||||
this.EnvDecorator.MoveNode(nodeControl.ViewModel.Node.Guid, otherNewLeft, otherNewTop); // 移动节点
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1370,7 +1428,7 @@ namespace Serein.Workbench
|
||||
double deltaY = currentPosition.Y - startControlDragPoint.Y; // 计算Y轴方向的偏移量
|
||||
double newLeft = Canvas.GetLeft(nodeControl) + deltaX; // 新的左边距
|
||||
double newTop = Canvas.GetTop(nodeControl) + deltaY; // 新的上边距
|
||||
this.FlowEnvironment.MoveNode(nodeControl.ViewModel.Node.Guid, newLeft, newTop); // 移动节点
|
||||
this.EnvDecorator.MoveNode(nodeControl.ViewModel.Node.Guid, newLeft, newTop); // 移动节点
|
||||
UpdateConnections(nodeControl);
|
||||
}
|
||||
startControlDragPoint = currentPosition; // 更新起始点位置
|
||||
@@ -1399,7 +1457,7 @@ namespace Serein.Workbench
|
||||
{
|
||||
if (ViewObjectViewer.MonitorObj is null)
|
||||
{
|
||||
FlowEnvironment.SetMonitorObjState(key, true); // 通知环境,该节点的数据更新后需要传到UI
|
||||
EnvDecorator.SetMonitorObjState(key, true); // 通知环境,该节点的数据更新后需要传到UI
|
||||
return;
|
||||
}
|
||||
if (instance is null)
|
||||
@@ -1413,8 +1471,8 @@ namespace Serein.Workbench
|
||||
}
|
||||
else
|
||||
{
|
||||
FlowEnvironment.SetMonitorObjState(ViewObjectViewer.MonitorKey,false); // 取消对旧节点的监视
|
||||
FlowEnvironment.SetMonitorObjState(key, true); // 通知环境,该节点的数据更新后需要传到UI
|
||||
EnvDecorator.SetMonitorObjState(ViewObjectViewer.MonitorKey,false); // 取消对旧节点的监视
|
||||
EnvDecorator.SetMonitorObjState(key, true); // 通知环境,该节点的数据更新后需要传到UI
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1441,7 +1499,7 @@ namespace Serein.Workbench
|
||||
{
|
||||
return;
|
||||
}
|
||||
FlowEnvironment.ConnectNode(formNodeGuid, toNodeGuid, currentConnectionType);
|
||||
EnvDecorator.ConnectNodeAsync(formNodeGuid, toNodeGuid, currentConnectionType);
|
||||
|
||||
}
|
||||
/*else if (IsConnecting)
|
||||
@@ -1859,7 +1917,7 @@ namespace Serein.Workbench
|
||||
var guid = node?.ViewModel?.Node?.Guid;
|
||||
if (!string.IsNullOrEmpty(guid))
|
||||
{
|
||||
FlowEnvironment.RemoveNode(guid);
|
||||
EnvDecorator.RemoveNode(guid);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2231,38 +2289,38 @@ namespace Serein.Workbench
|
||||
}
|
||||
}
|
||||
|
||||
private static TControl CreateNodeControl<TNode, TControl, TViewModel>(MethodDetails? methodDetails = null)
|
||||
where TNode : NodeModelBase
|
||||
where TControl : NodeControlBase
|
||||
where TViewModel : NodeControlViewModelBase
|
||||
{
|
||||
//private static TControl CreateNodeControl<TNode, TControl, TViewModel>(MethodDetails? methodDetails = null)
|
||||
// where TNode : NodeModelBase
|
||||
// where TControl : NodeControlBase
|
||||
// where TViewModel : NodeControlViewModelBase
|
||||
//{
|
||||
|
||||
var nodeObj = Activator.CreateInstance(typeof(TNode));
|
||||
var nodeBase = nodeObj as NodeModelBase ?? throw new Exception("无法创建节点控件");
|
||||
// var nodeObj = Activator.CreateInstance(typeof(TNode));
|
||||
// var nodeBase = nodeObj as NodeModelBase ?? throw new Exception("无法创建节点控件");
|
||||
|
||||
|
||||
if (string.IsNullOrEmpty(nodeBase.Guid))
|
||||
{
|
||||
nodeBase.Guid = Guid.NewGuid().ToString();
|
||||
}
|
||||
if (methodDetails != null)
|
||||
{
|
||||
var md = methodDetails.Clone();
|
||||
nodeBase.DisplayName = md.MethodTips;
|
||||
nodeBase.MethodDetails = md;
|
||||
}
|
||||
// if (string.IsNullOrEmpty(nodeBase.Guid))
|
||||
// {
|
||||
// nodeBase.Guid = Guid.NewGuid().ToString();
|
||||
// }
|
||||
// if (methodDetails != null)
|
||||
// {
|
||||
// var md = methodDetails.Clone(nodeBase); // 首先创建属于节点的方法信息,然后创建属于节点的参数信息
|
||||
// nodeBase.DisplayName = md.MethodTips;
|
||||
// nodeBase.MethodDetails = md;
|
||||
// }
|
||||
|
||||
var viewModel = Activator.CreateInstance(typeof(TViewModel), [nodeObj]);
|
||||
var controlObj = Activator.CreateInstance(typeof(TControl), [viewModel]);
|
||||
if (controlObj is TControl control)
|
||||
{
|
||||
return control;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("无法创建节点控件");
|
||||
}
|
||||
}
|
||||
// var viewModel = Activator.CreateInstance(typeof(TViewModel), [nodeObj]);
|
||||
// var controlObj = Activator.CreateInstance(typeof(TControl), [viewModel]);
|
||||
// if (controlObj is TControl control)
|
||||
// {
|
||||
// return control;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// throw new Exception("无法创建节点控件");
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
/// <summary>
|
||||
@@ -2315,7 +2373,7 @@ namespace Serein.Workbench
|
||||
}
|
||||
if (count == 0)
|
||||
{
|
||||
NodeTreeViewer.AddGlobalFlipFlop(FlowEnvironment, nodeModel); // 添加到全局触发器树树视图
|
||||
NodeTreeViewer.AddGlobalFlipFlop(EnvDecorator, nodeModel); // 添加到全局触发器树树视图
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2338,14 +2396,30 @@ namespace Serein.Workbench
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private async void ButtonDebugRun_Click(object sender, RoutedEventArgs e)
|
||||
private void ButtonDebugRun_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
logWindow?.Show();
|
||||
LogOutWindow?.Show();
|
||||
|
||||
// await FlowEnvironment.StartAsync(); // 快
|
||||
|
||||
await Task.Run(FlowEnvironment.StartAsync); // 上下文多次切换的场景中慢了1/10,定时器精度丢失
|
||||
//await Task.Factory.StartNew(FlowEnvironment.StartAsync); // 慢了1/5,定时器精度丢失
|
||||
|
||||
#if WINDOWS
|
||||
//Dispatcher uiDispatcher = Application.Current.MainWindow.Dispatcher;
|
||||
//SynchronizationContext? uiContext = SynchronizationContext.Current;
|
||||
//EnvDecorator.IOC.CustomRegisterInstance(typeof(SynchronizationContextk).FullName, uiContext, false);
|
||||
#endif
|
||||
|
||||
// 获取主线程的 SynchronizationContext
|
||||
Action<SynchronizationContext, Action> uiInvoke = (uiContext, action) => uiContext?.Post(state => action?.Invoke(), null);
|
||||
|
||||
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
await EnvDecorator.StartAsync();
|
||||
});
|
||||
|
||||
// await EnvDecorator.StartAsync();
|
||||
//await Task.Factory.StartNew(FlowEnvironment.StartAsync);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -2355,7 +2429,7 @@ namespace Serein.Workbench
|
||||
/// <param name="e"></param>
|
||||
private void ButtonDebugFlipflopNode_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
FlowEnvironment?.ExitFlow(); // 在运行平台上点击了退出
|
||||
EnvDecorator?.ExitFlow(); // 在运行平台上点击了退出
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -2375,7 +2449,7 @@ namespace Serein.Workbench
|
||||
}
|
||||
else
|
||||
{
|
||||
await this.FlowEnvironment.StartAsyncInSelectNode(selectNodeControls[0].ViewModel.Node.Guid);
|
||||
await this.EnvDecorator.StartAsyncInSelectNode(selectNodeControls[0].ViewModel.Node.Guid);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2393,16 +2467,16 @@ namespace Serein.Workbench
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void ButtonSaveFile_Click(object sender, RoutedEventArgs e)
|
||||
private async void ButtonSaveFile_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var projectData = FlowEnvironment.GetProjectInfo();
|
||||
var projectData = await EnvDecorator.GetProjectInfoAsync();
|
||||
|
||||
projectData.Basic = new Basic
|
||||
{
|
||||
Canvas = new FlowCanvas
|
||||
{
|
||||
Lenght = FlowChartCanvas.Width,
|
||||
Width = FlowChartCanvas.Height,
|
||||
Height = FlowChartCanvas.Height,
|
||||
Width = FlowChartCanvas.Width,
|
||||
ViewX = translateTransform.X,
|
||||
ViewY = translateTransform.Y,
|
||||
ScaleX = scaleTransform.ScaleX,
|
||||
@@ -2411,15 +2485,14 @@ namespace Serein.Workbench
|
||||
Versions = "1",
|
||||
};
|
||||
|
||||
foreach (var node in projectData.Nodes)
|
||||
{
|
||||
|
||||
if (NodeControls.TryGetValue(node.Guid, out var nodeControl))
|
||||
{
|
||||
Point positionRelativeToParent = nodeControl.TranslatePoint(new Point(0, 0), FlowChartCanvas);
|
||||
node.Position = new Position(positionRelativeToParent.X, positionRelativeToParent.Y);
|
||||
}
|
||||
}
|
||||
//foreach (var node in projectData.Nodes)
|
||||
//{
|
||||
// if (NodeControls.TryGetValue(node.Guid, out var nodeControl))
|
||||
// {
|
||||
// Point positionRelativeToParent = nodeControl.TranslatePoint(new Point(0, 0), FlowChartCanvas);
|
||||
// node.Position = new PositionOfUI(positionRelativeToParent.X, positionRelativeToParent.Y);
|
||||
// }
|
||||
//}
|
||||
if (!SaveContentToFile(out string savePath, out Action<string, string>? savaProjectFile))
|
||||
{
|
||||
Console.WriteLine("保存项目DLL时返回了意外的文件保存路径");
|
||||
@@ -2435,22 +2508,25 @@ namespace Serein.Workbench
|
||||
Console.WriteLine(savePath);
|
||||
for (int index = 0; index < projectData.Librarys.Length; index++)
|
||||
{
|
||||
Library.Entity.Library? library = projectData.Librarys[index];
|
||||
Library.Library? library = projectData.Librarys[index];
|
||||
try
|
||||
{
|
||||
string targetPath = System.IO.Path.Combine(librarySavePath, System.IO.Path.GetFileName(library.Path));
|
||||
string targetPath = System.IO.Path.Combine(librarySavePath, library.FileName); // 目标文件夹
|
||||
//Console.WriteLine("targetPath:" + targetPath);
|
||||
|
||||
string sourceFile = new Uri(library.Path).LocalPath;
|
||||
#if WINDOWS
|
||||
//library.Path
|
||||
string sourceFile = library.FilePath; // 源文件夹
|
||||
//Console.WriteLine("sourceFile:" + sourceFile);
|
||||
|
||||
#else
|
||||
string sourceFile = new Uri(library.Path).LocalPath;
|
||||
#endif
|
||||
// 复制文件到目标目录
|
||||
File.Copy(sourceFile, targetPath, true);
|
||||
|
||||
// 获取相对路径
|
||||
string relativePath = System.IO.Path.GetRelativePath(savePath, targetPath);
|
||||
//Console.WriteLine("Relative Path: " + relativePath);
|
||||
projectData.Librarys[index].Path = relativePath;
|
||||
projectData.Librarys[index].FilePath = relativePath;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -2499,7 +2575,7 @@ namespace Serein.Workbench
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region 顶部菜单栏 - 视图管理
|
||||
/// <summary>
|
||||
@@ -2516,7 +2592,7 @@ namespace Serein.Workbench
|
||||
}
|
||||
private void ButtonOpenConsoleOutWindow_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
logWindow?.Show();
|
||||
LogOutWindow?.Show();
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -2524,8 +2600,9 @@ namespace Serein.Workbench
|
||||
#region 顶部菜单栏 - 远程管理
|
||||
private async void ButtonStartRemoteServer_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
await this.FlowEnvironment.StartRemoteServerAsync();
|
||||
await this.EnvDecorator.StartRemoteServerAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 连接远程运行环境
|
||||
/// </summary>
|
||||
@@ -2533,9 +2610,17 @@ namespace Serein.Workbench
|
||||
/// <param name="e"></param>
|
||||
private void ButtonConnectionRemoteEnv_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var windowEnvRemoteLoginView = new WindowEnvRemoteLoginView((addres, port, token) =>
|
||||
var windowEnvRemoteLoginView = new WindowEnvRemoteLoginView(async (addres, port, token) =>
|
||||
{
|
||||
this.FlowEnvironment.LoadRemoteProject(addres, port, token);
|
||||
ResetFlowEnvironmentEvent();// 移除事件
|
||||
(var isConnect, RemoteEnvControl remoteEnvControl) = await this.EnvDecorator.ConnectRemoteEnv(addres, port, token);
|
||||
InitFlowEnvironmentEvent(); // 重新添加时间(如果没有连接成功,那么依然是原本的环境)
|
||||
if (isConnect)
|
||||
{
|
||||
// 连接成功,加载远程项目
|
||||
var flowEnvInfo = await EnvDecorator.GetEnvInfoAsync();
|
||||
EnvDecorator.LoadProject(flowEnvInfo, string.Empty);// 加载远程环境的项目
|
||||
}
|
||||
});
|
||||
windowEnvRemoteLoginView.Show();
|
||||
|
||||
@@ -2628,7 +2713,7 @@ namespace Serein.Workbench
|
||||
/// <param name="e"></param>
|
||||
private void UnloadAllButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
FlowEnvironment.ClearAll();
|
||||
EnvDecorator.ClearAll();
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,17 +1,6 @@
|
||||
using Serein.Library.Api;
|
||||
using Serein.Library.Attributes;
|
||||
using Serein.Library.Entity;
|
||||
using Serein.Library.Utils;
|
||||
using Serein.NodeFlow;
|
||||
using Serein.NodeFlow.Tool;
|
||||
using Serein.Workbench.Node.View;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Serein.NodeFlow.Env;
|
||||
using System.Windows;
|
||||
|
||||
namespace Serein.Workbench
|
||||
@@ -34,8 +23,25 @@ namespace Serein.Workbench
|
||||
/// <param name="window"></param>
|
||||
public MainWindowViewModel(MainWindow window)
|
||||
{
|
||||
FlowEnvironment = new FlowEnvironment();
|
||||
this.window = window;
|
||||
UIContextOperation? uIContextOperation = null;
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
SynchronizationContext? uiContext = SynchronizationContext.Current; // 在UI线程上获取UI线程上下文信息
|
||||
if (uiContext != null)
|
||||
{
|
||||
uIContextOperation = new UIContextOperation(uiContext); // 封装一个调用UI线程的工具类
|
||||
}
|
||||
});
|
||||
|
||||
if (uIContextOperation is null)
|
||||
{
|
||||
throw new Exception("无法封装 UIContextOperation ");
|
||||
}
|
||||
else
|
||||
{
|
||||
FlowEnvironment = new FlowEnvironmentDecorator(uIContextOperation);
|
||||
this.window = window;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
using Serein.Library.Entity;
|
||||
using Serein.NodeFlow.Base;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.ComponentModel;
|
||||
using Serein.Library;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Workbench.Node.ViewModel
|
||||
{
|
||||
@@ -38,7 +32,9 @@ namespace Serein.Workbench.Node.ViewModel
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 使节点获得中断能力(以及是否启用节点)
|
||||
/// </summary>
|
||||
public NodeDebugSetting DebugSetting
|
||||
{
|
||||
get => Node.DebugSetting;
|
||||
@@ -47,11 +43,14 @@ namespace Serein.Workbench.Node.ViewModel
|
||||
if (value != null)
|
||||
{
|
||||
Node.DebugSetting = value;
|
||||
OnPropertyChanged(/*nameof(DebugSetting)*/);
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使节点能够表达方法信息
|
||||
/// </summary>
|
||||
public MethodDetails MethodDetails
|
||||
{
|
||||
get => Node.MethodDetails;
|
||||
@@ -60,63 +59,49 @@ namespace Serein.Workbench.Node.ViewModel
|
||||
if(value != null)
|
||||
{
|
||||
Node.MethodDetails = value;
|
||||
OnPropertyChanged(/*nameof(MethodDetails)*/);
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool isInterrupt;
|
||||
/// <summary>
|
||||
/// 控制中断状态的视觉效果
|
||||
/// </summary>
|
||||
public bool IsInterrupt
|
||||
{
|
||||
get => isInterrupt;
|
||||
set
|
||||
{
|
||||
isInterrupt = value;
|
||||
OnPropertyChanged(/*nameof(IsInterrupt)*/);
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//public bool IsInterrupt
|
||||
//{
|
||||
// get => Node.DebugSetting.IsInterrupt;
|
||||
// set
|
||||
// {
|
||||
// if (value)
|
||||
// {
|
||||
// Node.Interrupt();
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// Node.CancelInterrupt();
|
||||
// }
|
||||
// OnPropertyChanged(nameof(IsInterrupt));
|
||||
// }
|
||||
//}
|
||||
|
||||
//public bool IsProtectionParameter
|
||||
//{
|
||||
// get => MethodDetails.IsProtectionParameter;
|
||||
// set
|
||||
// {
|
||||
// MethodDetails.IsProtectionParameter = value;
|
||||
// OnPropertyChanged(nameof(IsInterrupt));
|
||||
// }
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="propertyName"></param>
|
||||
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public void Selected()
|
||||
{
|
||||
IsSelect = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public void CancelSelect()
|
||||
{
|
||||
IsSelect = false;
|
||||
|
||||
@@ -7,7 +7,10 @@
|
||||
xmlns:vm="clr-namespace:Serein.Workbench.Node.ViewModel"
|
||||
xmlns:Converters="clr-namespace:Serein.Workbench.Tool.Converters"
|
||||
xmlns:themes="clr-namespace:Serein.Workbench.Themes"
|
||||
d:DataContext="{d:DesignInstance vm:ActionNodeControlViewModel}"
|
||||
mc:Ignorable="d"
|
||||
MaxWidth="300">
|
||||
<!--d:DataContext="{d:DesignData vm:ActionNodeControlViewModel}"-->
|
||||
<UserControl.Resources>
|
||||
<!--<BooleanToVisibilityConverter x:Key="BoolToVisConverter" />-->
|
||||
<Converters:InvertableBooleanToVisibilityConverter x:Key="InvertedBoolConverter"/>
|
||||
@@ -15,63 +18,63 @@
|
||||
|
||||
<Border BorderBrush="#8DE9FD" BorderThickness="1">
|
||||
|
||||
|
||||
<Grid>
|
||||
<Grid.ToolTip>
|
||||
<ToolTip Background="LightYellow" Foreground="#071042" Content="{Binding MethodDetails.MethodName, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</Grid.ToolTip>
|
||||
|
||||
<Border>
|
||||
<Border.Style>
|
||||
<Style TargetType="Border">
|
||||
<!-- 默认无边框 -->
|
||||
<Setter Property="BorderBrush" Value="Transparent" />
|
||||
<Setter Property="BorderThickness" Value="0" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsInterrupt}" Value="True">
|
||||
<Setter Property="BorderBrush" Value="Red" />
|
||||
<Setter Property="BorderThickness" Value="2" />
|
||||
<Setter Property="Background" Value="#80000000" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Border.Style>
|
||||
<Grid>
|
||||
<Grid.ToolTip>
|
||||
<ToolTip Background="LightYellow" Foreground="#071042" Content="{Binding MethodDetails.MethodTips, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</Grid.ToolTip>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Border>
|
||||
<Border.Style>
|
||||
<Style TargetType="Border">
|
||||
<!-- 默认无边框 -->
|
||||
<Setter Property="BorderBrush" Value="Transparent" />
|
||||
<Setter Property="BorderThickness" Value="0" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsInterrupt}" Value="True">
|
||||
<Setter Property="BorderBrush" Value="Red" />
|
||||
<Setter Property="BorderThickness" Value="2" />
|
||||
<Setter Property="Background" Value="#80000000" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Border.Style>
|
||||
|
||||
<StackPanel Grid.Row="0" Orientation="Horizontal" Background="#8DE9FD">
|
||||
<CheckBox IsChecked="{Binding DebugSetting.IsEnable, Mode=TwoWay}" VerticalContentAlignment="Center"/>
|
||||
<CheckBox IsChecked="{Binding MethodDetails.IsProtectionParameter, Mode=TwoWay}" VerticalContentAlignment="Center"/>
|
||||
<TextBlock Text="{Binding MethodDetails.MethodTips}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
<themes:MethodDetailsControl Grid.Row="1" MethodDetails="{Binding MethodDetails}"/>
|
||||
<!-- ParameterProtectionMask 参数保护 -->
|
||||
<!--取反 Visibility="{Binding DebugSetting.IsEnable, Converter={StaticResource InvertedBoolConverter}, ConverterParameter=Inverted}"-->
|
||||
<Border Grid.Row="1" x:Name="ParameterProtectionMask" Background="LightBlue" Opacity="0.5" BorderBrush="#0A4651" BorderThickness="0"
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<StackPanel Grid.Row="0" Orientation="Horizontal" Background="#8DE9FD">
|
||||
<CheckBox IsChecked="{Binding DebugSetting.IsEnable, Mode=TwoWay}" VerticalContentAlignment="Center"/>
|
||||
<CheckBox IsChecked="{Binding MethodDetails.IsProtectionParameter, Mode=TwoWay}" VerticalContentAlignment="Center"/>
|
||||
<TextBlock Text="{Binding MethodDetails.MethodTips}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
<themes:MethodDetailsControl Grid.Row="1" MethodDetails="{Binding MethodDetails}"/>
|
||||
<!-- ParameterProtectionMask 参数保护 -->
|
||||
<!--取反 Visibility="{Binding DebugSetting.IsEnable, Converter={StaticResource InvertedBoolConverter}, ConverterParameter=Inverted}"-->
|
||||
<Border Grid.Row="1" x:Name="ParameterProtectionMask" Background="LightBlue" Opacity="0.5" BorderBrush="#0A4651" BorderThickness="0"
|
||||
Visibility="{Binding MethodDetails.IsProtectionParameter, Converter={StaticResource InvertedBoolConverter},ConverterParameter=Normal}" />
|
||||
<Grid Grid.Row="2" Background="#D5F0FC" >
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="50"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Border Grid.Column="0" BorderThickness="1">
|
||||
<TextBlock Text="result" HorizontalAlignment="Center" VerticalAlignment="Center" />
|
||||
</Border>
|
||||
<Border Grid.Column="1" BorderThickness="1">
|
||||
<TextBlock Text="{Binding MethodDetails.ReturnType}" HorizontalAlignment="Left" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
<Grid Grid.Row="2" Background="#D5F0FC" >
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="50"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Border Grid.Column="0" BorderThickness="1">
|
||||
<TextBlock Text="result" HorizontalAlignment="Center" VerticalAlignment="Center" />
|
||||
</Border>
|
||||
<Border Grid.Column="1" BorderThickness="1">
|
||||
<TextBlock Text="{Binding MethodDetails.ReturnType}" HorizontalAlignment="Left" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
</Border>
|
||||
|
||||
<!--Visibility="{Binding IsEnable, Converter={StaticResource BoolToVisConverter}, ConverterParameter=False}"-->
|
||||
</Grid>
|
||||
|
||||
</Border>
|
||||
|
||||
<!--Visibility="{Binding IsEnable, Converter={StaticResource BoolToVisConverter}, ConverterParameter=False}"-->
|
||||
|
||||
|
||||
</Grid>
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
using Serein.NodeFlow;
|
||||
using Serein.NodeFlow.Model;
|
||||
using Serein.Workbench.Node.View;
|
||||
using Serein.Library;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace Serein.Workbench.Node.View
|
||||
@@ -111,7 +108,7 @@ namespace Serein.Workbench.Node.View
|
||||
{
|
||||
MoveNodeData moveNodeData = new MoveNodeData
|
||||
{
|
||||
NodeControlType = Library.Enums.NodeControlType.ConditionRegion
|
||||
NodeControlType = Library.NodeControlType.ConditionRegion
|
||||
};
|
||||
|
||||
// 创建一个 DataObject 用于拖拽操作,并设置拖拽效果
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
xmlns:local="clr-namespace:Serein.Workbench.Node.View"
|
||||
xmlns:vm="clr-namespace:Serein.Workbench.Node.ViewModel"
|
||||
xmlns:themes="clr-namespace:Serein.Workbench.Themes"
|
||||
d:DataContext="{d:DesignInstance vm:ConditionNodeControlViewModel}"
|
||||
mc:Ignorable="d"
|
||||
MaxWidth="300">
|
||||
|
||||
<UserControl.Resources>
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Serein.Workbench.Node.View
|
||||
public ConditionNodeControl() : base()
|
||||
{
|
||||
// 窗体初始化需要
|
||||
ViewModel = new ConditionNodeControlViewModel (new SingleConditionNode());
|
||||
ViewModel = new ConditionNodeControlViewModel (new SingleConditionNode(null));
|
||||
DataContext = ViewModel;
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
@@ -3,7 +3,10 @@
|
||||
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:local="clr-namespace:Serein.Workbench.Node.View"
|
||||
xmlns:vm="clr-namespace:Serein.Workbench.Node.ViewModel"
|
||||
d:DataContext="{d:DesignInstance vm:ConditionRegionNodeControlViewModel}"
|
||||
mc:Ignorable="d"
|
||||
MaxWidth="300">
|
||||
<Grid>
|
||||
<Border BorderBrush="Black" BorderThickness="1" Padding="10">
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
using Serein.Library.Api;
|
||||
using Serein.Library.Entity;
|
||||
using Serein.Library.Enums;
|
||||
using Serein.NodeFlow;
|
||||
using System.Reflection;
|
||||
using Serein.Library;
|
||||
using Serein.Library.Utils;
|
||||
using System.Windows;
|
||||
using System.Windows.Automation;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
|
||||
@@ -30,7 +26,7 @@ namespace Serein.Workbench.Node.View
|
||||
public DllControl(NodeLibrary nodeLibrary)
|
||||
{
|
||||
this.nodeLibrary = nodeLibrary;
|
||||
Header = "DLL name : " + nodeLibrary.Assembly.GetName().Name;
|
||||
Header = "DLL name : " + nodeLibrary.FullName;
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
@@ -127,9 +123,15 @@ namespace Serein.Workbench.Node.View
|
||||
|
||||
if (sender is TextBlock typeText && typeText.Tag is MethodDetailsInfo mdInfo)
|
||||
{
|
||||
if (!EnumHelper.TryConvertEnum<Library.NodeType>(mdInfo.NodeType, out var nodeType))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MoveNodeData moveNodeData = new MoveNodeData
|
||||
{
|
||||
NodeControlType = mdInfo.NodeType switch
|
||||
|
||||
NodeControlType = nodeType switch
|
||||
{
|
||||
NodeType.Action => NodeControlType.Action,
|
||||
NodeType.Flipflop => NodeControlType.Flipflop,
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
<local:NodeControlBase x:Class="Serein.Workbench.Node.View.ExpOpNodeControl"
|
||||
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="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"
|
||||
d:DataContext="{d:DesignInstance vm:ExpOpNodeViewModel}"
|
||||
mc:Ignorable="d"
|
||||
MaxWidth="300">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Serein.Workbench.Node.View
|
||||
public ExpOpNodeControl() : base()
|
||||
{
|
||||
// 窗体初始化需要
|
||||
ViewModel = new ExpOpNodeViewModel(new SingleExpOpNode());
|
||||
ViewModel = new ExpOpNodeViewModel(new SingleExpOpNode(null));
|
||||
DataContext = ViewModel;
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
@@ -2,13 +2,14 @@
|
||||
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:Converters="clr-namespace:Serein.Workbench.Tool.Converters"
|
||||
xmlns:Converters="clr-namespace:Serein.Workbench.Tool.Converters"
|
||||
xmlns:local="clr-namespace:Serein.Workbench.Node.View"
|
||||
xmlns:vm="clr-namespace:Serein.Workbench.Node.ViewModel"
|
||||
xmlns:themes="clr-namespace:Serein.Workbench.Themes"
|
||||
MaxWidth="300">
|
||||
d:DataContext="{d:DesignInstance vm:FlipflopNodeControlViewModel}"
|
||||
mc:Ignorable="d"
|
||||
MaxWidth="300">
|
||||
|
||||
<UserControl.Resources>
|
||||
<vm:TypeToStringConverter x:Key="TypeToStringConverter"/>
|
||||
@@ -33,7 +34,7 @@
|
||||
<StackPanel Grid.Row="0" Orientation="Horizontal" Background="#FCB334">
|
||||
<CheckBox IsChecked="{Binding DebugSetting.IsEnable, Mode=TwoWay}" VerticalContentAlignment="Center"/>
|
||||
<CheckBox IsChecked="{Binding MethodDetails.IsProtectionParameter, Mode=TwoWay}" VerticalContentAlignment="Center"/>
|
||||
|
||||
|
||||
<TextBlock Text="{Binding MethodDetails.MethodTips, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
<themes:MethodDetailsControl Grid.Row="1" MethodDetails="{Binding MethodDetails}" />
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
using Serein.Library.Api;
|
||||
using Serein.Library.Entity;
|
||||
using Serein.NodeFlow.Base;
|
||||
using Serein.Workbench.Node.ViewModel;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
<BaseOutputPath>D:\Project\C#\DynamicControl\SereinFlow\.Output</BaseOutputPath>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<!--<IsRoslynComponent>true</IsRoslynComponent>-->
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:Serein.Workbench.Themes"
|
||||
xmlns:sys="clr-namespace:System;assembly=mscorlib">
|
||||
xmlns:sys="clr-namespace:System;assembly=mscorlib"
|
||||
>
|
||||
|
||||
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
@@ -12,7 +13,7 @@
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type local:MethodDetailsControl}">
|
||||
|
||||
<!--根据方法入参数量生成相应的控件-->
|
||||
<ItemsControl ItemsSource="{Binding MethodDetails.ParameterDetailss, RelativeSource={RelativeSource TemplatedParent}}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
@@ -21,6 +22,7 @@
|
||||
<Style TargetType="ContentControl">
|
||||
<Style.Triggers>
|
||||
<MultiDataTrigger>
|
||||
<!--无须指定参数-->
|
||||
<MultiDataTrigger.Conditions>
|
||||
<Condition Binding="{Binding IsExplicitData}" Value="false" />
|
||||
</MultiDataTrigger.Conditions>
|
||||
@@ -43,7 +45,8 @@
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</MultiDataTrigger>
|
||||
|
||||
|
||||
<!--指定参数:选项类型-->
|
||||
<MultiDataTrigger>
|
||||
<MultiDataTrigger.Conditions>
|
||||
<Condition Binding="{Binding IsExplicitData}" Value="true" />
|
||||
@@ -71,13 +74,11 @@
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</MultiDataTrigger>
|
||||
|
||||
<!--指定参数:文本类型(可输入)-->
|
||||
<MultiDataTrigger>
|
||||
<MultiDataTrigger.Conditions>
|
||||
<Condition Binding="{Binding IsExplicitData}" Value="true" />
|
||||
<Condition Binding="{Binding ExplicitTypeName}" Value="Value" />
|
||||
<!--<Condition Binding="{Binding ExplicitTypeName}" Value="{x:Type sys:String}" />
|
||||
<Condition Binding="{Binding ExplicitTypeName}" Value="{x:Type sys:Double}" />-->
|
||||
</MultiDataTrigger.Conditions>
|
||||
<Setter Property="ContentTemplate">
|
||||
<Setter.Value>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Serein.Library.Entity;
|
||||
using Serein.NodeFlow;
|
||||
using Serein.Library;
|
||||
using System.Collections;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
@@ -37,6 +36,9 @@ namespace Serein.Workbench.Themes
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 方法参数控件
|
||||
/// </summary>
|
||||
public partial class MethodDetailsControl : UserControl//,ItemsControl
|
||||
{
|
||||
static MethodDetailsControl()
|
||||
|
||||
@@ -1,25 +1,7 @@
|
||||
using Serein.Library.Api;
|
||||
using Serein.Library.Enums;
|
||||
using Serein.NodeFlow;
|
||||
using Serein.NodeFlow.Base;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Serein.Library;
|
||||
using Serein.Library.Api;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
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;
|
||||
using System.Xml.Linq;
|
||||
using static Serein.Workbench.Themes.TypeViewerWindow;
|
||||
|
||||
namespace Serein.Workbench.Themes
|
||||
{
|
||||
|
||||
@@ -1,19 +1,6 @@
|
||||
using Serein.Library.Api;
|
||||
using Serein.NodeFlow.Base;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using Serein.Library;
|
||||
using Serein.Library.Api;
|
||||
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.Themes
|
||||
{
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Serein.Library.Api;
|
||||
using Serein.NodeFlow.Base;
|
||||
using Serein.NodeFlow.Tool.SereinExpression;
|
||||
using Serein.Library.Utils.SereinExpression;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
@@ -131,9 +130,9 @@ namespace Serein.Workbench.Themes
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void UpMonitorExpressionButton_Click(object sender, RoutedEventArgs e)
|
||||
private async void UpMonitorExpressionButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (FlowEnvironment is not null && FlowEnvironment.AddInterruptExpression(monitorKey, MonitorExpression)) // 对象预览器尝试添加中断表达式
|
||||
if (FlowEnvironment is not null && await FlowEnvironment.AddInterruptExpressionAsync(monitorKey, MonitorExpression)) // 对象预览器尝试添加中断表达式
|
||||
{
|
||||
if (string.IsNullOrEmpty(MonitorExpression))
|
||||
{
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<ColumnDefinition Width="auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Text="地址" HorizontalAlignment="Center"></TextBlock>
|
||||
<TextBox x:Name="TextBlockAddres" Grid.Row="0" Grid.Column="1" Text="192.168.1.100"></TextBox>
|
||||
<TextBox x:Name="TextBlockAddres" Grid.Row="0" Grid.Column="1" Text="127.0.0.1"></TextBox>
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" Text="端口" HorizontalAlignment="Center"></TextBlock>
|
||||
<TextBox x:Name="TextBlockPort" Grid.Row="1" Grid.Column="1" Text="7525"></TextBox>
|
||||
<TextBlock Grid.Row="2" Grid.Column="0" Text="密码" HorizontalAlignment="Center"></TextBlock>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Serein.Library.Enums;
|
||||
using Serein.Library;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading.Channels;
|
||||
|
||||
namespace Serein.Workbench.tool
|
||||
{
|
||||
/// <summary>
|
||||
/// 可以捕获类库输出的打印输出
|
||||
/// </summary>
|
||||
public class LogTextWriter : TextWriter
|
||||
{
|
||||
private readonly Action<string> logAction; // 更新日志UI的委托
|
||||
private readonly StringWriter stringWriter = new(); // 缓存日志内容
|
||||
private readonly Channel<string> logChannel = Channel.CreateUnbounded<string>(); // 日志管道
|
||||
private readonly Action clearTextBoxAction; // 清空日志UI的委托
|
||||
private int writeCount = 0; // 写入计数器
|
||||
private const int maxWrites = 500; // 写入最大计数
|
||||
|
||||
public LogTextWriter(Action<string> logAction, Action clearTextBoxAction)
|
||||
{
|
||||
this.logAction = logAction;
|
||||
this.clearTextBoxAction = clearTextBoxAction;
|
||||
|
||||
// 异步启动日志处理任务,不阻塞主线程
|
||||
Task.Run(ProcessLogQueueAsync);
|
||||
}
|
||||
|
||||
public override Encoding Encoding => Encoding.UTF8;
|
||||
|
||||
public override void Write(char value)
|
||||
{
|
||||
stringWriter.Write(value);
|
||||
if (value == '\n')
|
||||
{
|
||||
EnqueueLog();
|
||||
}
|
||||
}
|
||||
|
||||
public override void Write(string? value)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value)) return;
|
||||
stringWriter.Write(value);
|
||||
if (value.Contains('\n'))
|
||||
{
|
||||
EnqueueLog();
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteLine(string? value)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value)) return;
|
||||
stringWriter.WriteLine(value);
|
||||
EnqueueLog();
|
||||
}
|
||||
|
||||
// 将日志加入通道
|
||||
private void EnqueueLog()
|
||||
{
|
||||
var log = stringWriter.ToString();
|
||||
stringWriter.GetStringBuilder().Clear();
|
||||
|
||||
if (!logChannel.Writer.TryWrite(log))
|
||||
{
|
||||
// 如果写入失败(不太可能),则直接丢弃日志或处理
|
||||
}
|
||||
}
|
||||
|
||||
// 异步处理日志队列
|
||||
private async Task ProcessLogQueueAsync()
|
||||
{
|
||||
await foreach (var log in logChannel.Reader.ReadAllAsync()) // 异步读取日志通道
|
||||
{
|
||||
logAction?.Invoke(log); // 执行日志写入到UI的委托
|
||||
|
||||
writeCount++;
|
||||
if (writeCount >= maxWrites)
|
||||
{
|
||||
clearTextBoxAction?.Invoke(); // 清空文本框
|
||||
writeCount = 0; // 重置计数器
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user