2024-08-06 16:09:46 +08:00
|
|
|
|
using Microsoft.Win32;
|
|
|
|
|
|
using Newtonsoft.Json.Linq;
|
2024-09-15 12:15:32 +08:00
|
|
|
|
using Serein.Library.Api;
|
|
|
|
|
|
using Serein.Library.Entity;
|
|
|
|
|
|
using Serein.Library.Enums;
|
2024-09-12 20:32:54 +08:00
|
|
|
|
using Serein.Library.Utils;
|
2024-08-06 16:09:46 +08:00
|
|
|
|
using Serein.NodeFlow;
|
2024-09-15 12:15:32 +08:00
|
|
|
|
using Serein.NodeFlow.Base;
|
2024-08-06 16:09:46 +08:00
|
|
|
|
using Serein.NodeFlow.Model;
|
2024-09-18 16:45:41 +08:00
|
|
|
|
using Serein.WorkBench.Node;
|
2024-08-05 10:11:58 +08:00
|
|
|
|
using Serein.WorkBench.Node.View;
|
2024-09-12 20:32:54 +08:00
|
|
|
|
using Serein.WorkBench.Node.ViewModel;
|
2024-08-05 10:11:58 +08:00
|
|
|
|
using Serein.WorkBench.Themes;
|
|
|
|
|
|
using Serein.WorkBench.tool;
|
|
|
|
|
|
using System.IO;
|
|
|
|
|
|
using System.Reflection;
|
|
|
|
|
|
using System.Windows;
|
|
|
|
|
|
using System.Windows.Controls;
|
2024-09-10 11:05:48 +08:00
|
|
|
|
using System.Windows.Controls.Primitives;
|
2024-08-05 10:11:58 +08:00
|
|
|
|
using System.Windows.Input;
|
2024-09-15 12:15:32 +08:00
|
|
|
|
using System.Windows.Interop;
|
2024-08-05 10:11:58 +08:00
|
|
|
|
using System.Windows.Media;
|
|
|
|
|
|
using System.Windows.Media.Animation;
|
|
|
|
|
|
using System.Windows.Shapes;
|
2024-09-17 14:20:27 +08:00
|
|
|
|
using System.Windows.Threading;
|
2024-09-07 15:56:34 +08:00
|
|
|
|
using DataObject = System.Windows.DataObject;
|
2024-08-05 10:11:58 +08:00
|
|
|
|
|
|
|
|
|
|
namespace Serein.WorkBench
|
|
|
|
|
|
{
|
2024-09-06 09:13:13 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 拖拽创建节点类型
|
|
|
|
|
|
/// </summary>
|
2024-08-05 10:11:58 +08:00
|
|
|
|
public static class MouseNodeType
|
|
|
|
|
|
{
|
2024-09-15 12:15:32 +08:00
|
|
|
|
public static string CreateDllNodeInCanvas { get; } = nameof(CreateDllNodeInCanvas);
|
|
|
|
|
|
public static string CreateBaseNodeInCanvas { get; } = nameof(CreateBaseNodeInCanvas);
|
|
|
|
|
|
//public static string RegionType { get; } = nameof(RegionType);
|
|
|
|
|
|
//public static string BaseNodeType { get; } = nameof(BaseNodeType);
|
|
|
|
|
|
//public static string DllNodeType { get; } = nameof(DllNodeType);
|
2024-08-05 10:11:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-09-15 12:15:32 +08:00
|
|
|
|
|
2024-08-05 10:11:58 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Interaction logic for MainWindow.xaml,第一次用git,不太懂
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public partial class MainWindow : Window
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 全局捕获Console输出事件,打印在这个窗体里面
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private readonly LogWindow logWindow;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2024-09-16 21:38:34 +08:00
|
|
|
|
/// 流程运行环境
|
2024-08-05 10:11:58 +08:00
|
|
|
|
/// </summary>
|
2024-09-16 21:38:34 +08:00
|
|
|
|
private IFlowEnvironment FlowEnvironment { get; }
|
|
|
|
|
|
private MainWindowViewModel ViewModel { get; set; }
|
2024-09-09 16:42:01 +08:00
|
|
|
|
|
2024-08-05 10:11:58 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 存储所有与节点有关的控件
|
|
|
|
|
|
/// </summary>
|
2024-09-16 21:38:34 +08:00
|
|
|
|
private Dictionary<string, NodeControlBase> NodeControls { get; } = [];
|
2024-08-05 10:11:58 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 存储所有的连接
|
|
|
|
|
|
/// </summary>
|
2024-09-16 21:38:34 +08:00
|
|
|
|
private List<Connection> Connections { get; } = [];
|
2024-09-15 12:15:32 +08:00
|
|
|
|
|
2024-09-12 20:32:54 +08:00
|
|
|
|
#region 与画布相关的字段
|
2024-09-18 16:45:41 +08:00
|
|
|
|
|
2024-09-12 20:32:54 +08:00
|
|
|
|
/// <summary>
|
2024-09-18 16:45:41 +08:00
|
|
|
|
/// 标记是否正在尝试选取控件
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private bool IsSelectControl;
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 标记是否正在进行连接操作
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private bool IsConnecting;
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 标记是否正在拖动控件
|
2024-09-12 20:32:54 +08:00
|
|
|
|
/// </summary>
|
2024-09-18 16:45:41 +08:00
|
|
|
|
private bool IsControlDragging;
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 标记是否正在拖动画布
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private bool IsCanvasDragging;
|
2024-09-12 20:32:54 +08:00
|
|
|
|
|
2024-09-16 21:38:34 +08:00
|
|
|
|
/// <summary>
|
2024-09-18 16:45:41 +08:00
|
|
|
|
/// 当前选取的控件
|
2024-09-16 21:38:34 +08:00
|
|
|
|
/// </summary>
|
2024-09-18 16:45:41 +08:00
|
|
|
|
private readonly List<NodeControlBase> selectNodeControls = [];
|
2024-09-16 21:38:34 +08:00
|
|
|
|
|
2024-08-05 10:11:58 +08:00
|
|
|
|
/// <summary>
|
2024-09-20 10:50:32 +08:00
|
|
|
|
/// 记录开始拖动节点控件时的鼠标位置
|
2024-08-05 10:11:58 +08:00
|
|
|
|
/// </summary>
|
2024-09-20 10:50:32 +08:00
|
|
|
|
private Point startControlDragPoint;
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 记录移动画布开始时的鼠标位置
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private Point startCanvasDragPoint;
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 记录开始选取节点控件时的鼠标位置
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private Point startSelectControolPoint;
|
2024-09-18 16:45:41 +08:00
|
|
|
|
|
2024-08-05 10:11:58 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 记录开始连接的文本块
|
|
|
|
|
|
/// </summary>
|
2024-09-15 12:15:32 +08:00
|
|
|
|
private NodeControlBase? startConnectNodeControl;
|
2024-08-05 10:11:58 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 当前正在绘制的连接线
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private Line? currentLine;
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 当前正在绘制的真假分支属性
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private ConnectionType currentConnectionType;
|
2024-09-18 16:45:41 +08:00
|
|
|
|
|
|
|
|
|
|
|
2024-09-09 16:42:01 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 组合变换容器
|
|
|
|
|
|
/// </summary>
|
2024-09-07 16:14:59 +08:00
|
|
|
|
private TransformGroup canvasTransformGroup;
|
2024-09-09 16:42:01 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 缩放画布
|
|
|
|
|
|
/// </summary>
|
2024-09-07 16:14:59 +08:00
|
|
|
|
private ScaleTransform scaleTransform;
|
2024-09-09 16:42:01 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 平移画布
|
|
|
|
|
|
/// </summary>
|
2024-09-15 12:15:32 +08:00
|
|
|
|
private TranslateTransform translateTransform;
|
2024-09-12 20:32:54 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
2024-08-05 10:11:58 +08:00
|
|
|
|
public MainWindow()
|
|
|
|
|
|
{
|
2024-09-16 21:38:34 +08:00
|
|
|
|
ViewModel = new MainWindowViewModel(this);
|
|
|
|
|
|
FlowEnvironment = ViewModel.FlowEnvironment;
|
2024-09-17 14:20:27 +08:00
|
|
|
|
InitFlowEvent();
|
2024-09-15 12:15:32 +08:00
|
|
|
|
|
2024-09-16 21:38:34 +08:00
|
|
|
|
InitializeComponent();
|
2024-08-05 10:11:58 +08:00
|
|
|
|
logWindow = new LogWindow();
|
|
|
|
|
|
logWindow.Show();
|
|
|
|
|
|
// 重定向 Console 输出
|
2024-09-20 10:50:32 +08:00
|
|
|
|
var logTextWriter = new LogTextWriter(WriteLog,() => logWindow.Clear());;
|
2024-08-05 10:11:58 +08:00
|
|
|
|
Console.SetOut(logTextWriter);
|
2024-09-20 10:50:32 +08:00
|
|
|
|
|
|
|
|
|
|
|
2024-09-15 12:15:32 +08:00
|
|
|
|
InitUI();
|
2024-09-17 14:20:27 +08:00
|
|
|
|
|
|
|
|
|
|
var project = App.FData;
|
|
|
|
|
|
if (project == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
InitializeCanvas(project.Basic.Canvas.Width, project.Basic.Canvas.Lenght);// 设置画布大小
|
|
|
|
|
|
FlowEnvironment.LoadProject(project, App.FileDataPath); // 加载项目
|
2024-09-15 12:15:32 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void InitFlowEvent()
|
|
|
|
|
|
{
|
|
|
|
|
|
FlowEnvironment.OnDllLoad += FlowEnvironment_DllLoadEvent;
|
2024-09-17 14:20:27 +08:00
|
|
|
|
// FlowEnvironment.OnLoadNode += FlowEnvironment_NodeLoadEvent;
|
|
|
|
|
|
FlowEnvironment.OnProjectLoaded += FlowEnvironment_OnProjectLoaded;
|
2024-09-15 12:15:32 +08:00
|
|
|
|
FlowEnvironment.OnStartNodeChange += FlowEnvironment_StartNodeChangeEvent;
|
|
|
|
|
|
FlowEnvironment.OnNodeConnectChange += FlowEnvironment_NodeConnectChangeEvemt;
|
|
|
|
|
|
FlowEnvironment.OnNodeCreate += FlowEnvironment_NodeCreateEvent;
|
|
|
|
|
|
FlowEnvironment.OnNodeRemote += FlowEnvironment_NodeRemoteEvent;
|
|
|
|
|
|
FlowEnvironment.OnFlowRunComplete += FlowEnvironment_OnFlowRunComplete;
|
2024-09-07 15:56:34 +08:00
|
|
|
|
|
2024-09-10 11:49:56 +08:00
|
|
|
|
}
|
2024-09-07 16:14:59 +08:00
|
|
|
|
|
2024-09-15 12:15:32 +08:00
|
|
|
|
private void InitUI()
|
2024-09-10 11:49:56 +08:00
|
|
|
|
{
|
2024-09-09 16:42:01 +08:00
|
|
|
|
canvasTransformGroup = new TransformGroup();
|
|
|
|
|
|
scaleTransform = new ScaleTransform();
|
|
|
|
|
|
translateTransform = new TranslateTransform();
|
2024-09-07 16:14:59 +08:00
|
|
|
|
|
2024-09-09 16:42:01 +08:00
|
|
|
|
canvasTransformGroup.Children.Add(scaleTransform);
|
|
|
|
|
|
canvasTransformGroup.Children.Add(translateTransform);
|
2024-09-07 16:14:59 +08:00
|
|
|
|
|
2024-09-09 16:42:01 +08:00
|
|
|
|
FlowChartCanvas.RenderTransform = canvasTransformGroup;
|
2024-09-18 16:45:41 +08:00
|
|
|
|
//FlowChartCanvas.RenderTransformOrigin = new Point(0.5, 0.5);
|
2024-08-05 10:11:58 +08:00
|
|
|
|
}
|
2024-09-18 16:45:41 +08:00
|
|
|
|
|
2024-09-17 14:20:27 +08:00
|
|
|
|
#region Main窗体加载方法
|
|
|
|
|
|
private void Window_Loaded(object sender, RoutedEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
}
|
2024-08-05 10:11:58 +08:00
|
|
|
|
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
logWindow.Close();
|
|
|
|
|
|
System.Windows.Application.Current.Shutdown();
|
|
|
|
|
|
}
|
2024-09-17 14:20:27 +08:00
|
|
|
|
private void Window_ContentRendered(object sender, EventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var connection in Connections)
|
|
|
|
|
|
{
|
|
|
|
|
|
connection.Refresh();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
#endregion
|
2024-08-05 10:11:58 +08:00
|
|
|
|
public void WriteLog(string message)
|
|
|
|
|
|
{
|
|
|
|
|
|
logWindow.AppendText(message);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-09-15 12:15:32 +08:00
|
|
|
|
#region 运行环境事件
|
2024-09-17 14:20:27 +08:00
|
|
|
|
private void FlowEnvironment_OnProjectLoaded(ProjectLoadedEventArgs eventArgs)
|
|
|
|
|
|
{
|
|
|
|
|
|
//foreach(var connection in Connections)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// connection.Refresh();
|
|
|
|
|
|
//}
|
2024-09-20 10:50:32 +08:00
|
|
|
|
//Console.WriteLine((FlowChartStackPanel.ActualWidth, FlowChartStackPanel.ActualHeight));
|
2024-09-17 14:20:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-09-15 12:15:32 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 运行完成
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="eventArgs"></param>
|
|
|
|
|
|
/// <exception cref="NotImplementedException"></exception>
|
|
|
|
|
|
private void FlowEnvironment_OnFlowRunComplete(FlowEventArgs eventArgs)
|
2024-08-05 10:11:58 +08:00
|
|
|
|
{
|
2024-09-15 12:15:32 +08:00
|
|
|
|
WriteLog("-------运行完成---------\r\n");
|
2024-08-05 10:11:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2024-09-15 12:15:32 +08:00
|
|
|
|
/// 加载了DLL文件,dll内容
|
2024-08-05 10:11:58 +08:00
|
|
|
|
/// </summary>
|
2024-09-15 12:15:32 +08:00
|
|
|
|
private void FlowEnvironment_DllLoadEvent(LoadDLLEventArgs eventArgs)
|
2024-08-05 10:11:58 +08:00
|
|
|
|
{
|
2024-09-17 14:20:27 +08:00
|
|
|
|
this.Dispatcher.Invoke(() => {
|
|
|
|
|
|
Assembly assembly = eventArgs.Assembly;
|
|
|
|
|
|
List<MethodDetails> methodDetailss = eventArgs.MethodDetailss;
|
2024-09-15 12:15:32 +08:00
|
|
|
|
|
2024-09-17 14:20:27 +08:00
|
|
|
|
var dllControl = new DllControl
|
|
|
|
|
|
{
|
|
|
|
|
|
Header = "DLL name : " + assembly.GetName().Name // 设置控件标题为程序集名称
|
|
|
|
|
|
};
|
2024-09-15 12:15:32 +08:00
|
|
|
|
|
2024-09-17 14:20:27 +08:00
|
|
|
|
foreach (var methodDetails in methodDetailss)
|
2024-09-15 12:15:32 +08:00
|
|
|
|
{
|
2024-09-17 14:20:27 +08:00
|
|
|
|
switch (methodDetails.MethodDynamicType)
|
|
|
|
|
|
{
|
|
|
|
|
|
case Library.Enums.NodeType.Action:
|
|
|
|
|
|
dllControl.AddAction(methodDetails.Clone()); // 添加动作类型到控件
|
|
|
|
|
|
break;
|
|
|
|
|
|
case Library.Enums.NodeType.Flipflop:
|
|
|
|
|
|
dllControl.AddFlipflop(methodDetails.Clone()); // 添加触发器方法到控件
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
2024-09-15 12:15:32 +08:00
|
|
|
|
}
|
2024-09-17 14:20:27 +08:00
|
|
|
|
DllStackPanel.Children.Add(dllControl); // 将控件添加到界面上显示
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2024-08-05 10:11:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2024-09-15 12:15:32 +08:00
|
|
|
|
/// 运行环境成功加载了节点,需要在画布上创建节点控件
|
2024-08-05 10:11:58 +08:00
|
|
|
|
/// </summary>
|
2024-09-15 12:15:32 +08:00
|
|
|
|
/// <param name="nodeInfo"></param>
|
|
|
|
|
|
/// <param name="methodDetailss"></param>
|
2024-09-17 14:20:27 +08:00
|
|
|
|
//private void FlowEnvironment_NodeLoadEvent(LoadNodeEventArgs eventArgs)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// if (!eventArgs.IsSucceed)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// MessageBox.Show(eventArgs.ErrorTips);
|
|
|
|
|
|
// return;
|
|
|
|
|
|
// }
|
2024-08-05 10:11:58 +08:00
|
|
|
|
|
2024-09-17 14:20:27 +08:00
|
|
|
|
// NodeInfo nodeInfo = eventArgs.NodeInfo;
|
|
|
|
|
|
// MethodDetails methodDetailss = eventArgs.MethodDetailss;
|
2024-08-05 10:11:58 +08:00
|
|
|
|
|
2024-09-17 14:20:27 +08:00
|
|
|
|
// // 创建对应的实例(包含NodeModel,NodeControl,NodeControlViewModel)
|
|
|
|
|
|
// NodeControlBase? nodeControl = CreateNodeControlOfNodeInfo(nodeInfo, methodDetailss);
|
|
|
|
|
|
// if (nodeControl == null)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// WriteLog($"无法为节点类型创建节点控件: {nodeInfo.MethodName}\r\n");
|
|
|
|
|
|
// return;
|
|
|
|
|
|
// // ConfigureNodeControl(nodeInfo, nodeControl, nodeControls, regionControls);
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
// // 判断是否属于区域控件,如果是,则加载区域子项
|
|
|
|
|
|
// // if (nodeControl is ActionRegionControl || nodeControl is ConditionRegionControl)
|
|
|
|
|
|
// // {
|
|
|
|
|
|
// // AddNodeControlInRegeionControl(nodeControl, nodeInfo.ChildNodes);
|
|
|
|
|
|
// // }
|
|
|
|
|
|
|
|
|
|
|
|
// NodeControls.TryAdd(nodeInfo.Guid, nodeControl); // 存放对应的控件
|
|
|
|
|
|
// PlaceNodeOnCanvas(nodeControl, nodeInfo.Position.X, nodeInfo.Position.Y); // 配置节点,并放置在画布上
|
|
|
|
|
|
//}
|
2024-08-05 10:11:58 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2024-09-15 12:15:32 +08:00
|
|
|
|
/// 节点连接关系变更
|
2024-08-05 10:11:58 +08:00
|
|
|
|
/// </summary>
|
2024-09-15 12:15:32 +08:00
|
|
|
|
/// <param name="fromNodeGuid"></param>
|
|
|
|
|
|
/// <param name="toNodeGuid"></param>
|
|
|
|
|
|
/// <param name="connectionType"></param>
|
|
|
|
|
|
private void FlowEnvironment_NodeConnectChangeEvemt(NodeConnectChangeEventArgs eventArgs)
|
2024-08-05 10:11:58 +08:00
|
|
|
|
{
|
2024-09-17 14:20:27 +08:00
|
|
|
|
this.Dispatcher.Invoke(() =>
|
2024-09-15 12:15:32 +08:00
|
|
|
|
{
|
2024-09-17 14:20:27 +08:00
|
|
|
|
string fromNodeGuid = eventArgs.FromNodeGuid;
|
|
|
|
|
|
string toNodeGuid = eventArgs.ToNodeGuid;
|
|
|
|
|
|
if (!NodeControls.TryGetValue(fromNodeGuid, out var fromNode) || !NodeControls.TryGetValue(toNodeGuid, out var toNode))
|
2024-08-05 10:11:58 +08:00
|
|
|
|
{
|
2024-09-17 14:20:27 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
ConnectionType connectionType = eventArgs.ConnectionType;
|
|
|
|
|
|
if (eventArgs.ChangeType == NodeConnectChangeEventArgs.ConnectChangeType.Create)
|
|
|
|
|
|
{
|
|
|
|
|
|
lock (Connections)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 添加连接
|
|
|
|
|
|
var connection = new Connection
|
|
|
|
|
|
{
|
|
|
|
|
|
Start = fromNode,
|
|
|
|
|
|
End = toNode,
|
|
|
|
|
|
Type = connectionType
|
|
|
|
|
|
};
|
2024-09-15 12:15:32 +08:00
|
|
|
|
|
2024-09-17 14:20:27 +08:00
|
|
|
|
BsControl.Draw(FlowChartCanvas, connection); // 添加贝塞尔曲线显示
|
|
|
|
|
|
ConfigureLineContextMenu(connection); // 设置连接右键事件
|
|
|
|
|
|
Connections.Add(connection);
|
|
|
|
|
|
EndConnection();
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (eventArgs.ChangeType == NodeConnectChangeEventArgs.ConnectChangeType.Remote)
|
2024-09-15 12:15:32 +08:00
|
|
|
|
{
|
2024-09-17 14:20:27 +08:00
|
|
|
|
// 需要移除连接
|
|
|
|
|
|
var removeConnections = Connections.Where(c => c.Start.ViewModel.Node.Guid.Equals(fromNodeGuid)
|
|
|
|
|
|
&& c.End.ViewModel.Node.Guid.Equals(toNodeGuid))
|
|
|
|
|
|
.ToList();
|
|
|
|
|
|
foreach (var connection in removeConnections)
|
|
|
|
|
|
{
|
|
|
|
|
|
connection.RemoveFromCanvas(FlowChartCanvas);
|
|
|
|
|
|
Connections.Remove(connection);
|
|
|
|
|
|
}
|
2024-08-05 10:11:58 +08:00
|
|
|
|
}
|
2024-09-17 14:20:27 +08:00
|
|
|
|
});
|
2024-08-05 10:11:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2024-09-15 12:15:32 +08:00
|
|
|
|
/// 节点移除事件
|
2024-08-05 10:11:58 +08:00
|
|
|
|
/// </summary>
|
2024-09-15 12:15:32 +08:00
|
|
|
|
/// <param name="eventArgs"></param>
|
|
|
|
|
|
private void FlowEnvironment_NodeRemoteEvent(NodeRemoteEventArgs eventArgs)
|
2024-08-05 10:11:58 +08:00
|
|
|
|
{
|
2024-09-18 16:45:41 +08:00
|
|
|
|
var nodeGuid = eventArgs.NodeGuid;
|
|
|
|
|
|
if (!NodeControls.TryGetValue(nodeGuid, out NodeControlBase nodeControl))
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
if(nodeControl is null)
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (selectNodeControls.Count > 0)
|
2024-08-05 10:11:58 +08:00
|
|
|
|
{
|
2024-09-18 16:45:41 +08:00
|
|
|
|
if (selectNodeControls.Contains(nodeControl))
|
2024-09-17 14:20:27 +08:00
|
|
|
|
{
|
2024-09-18 16:45:41 +08:00
|
|
|
|
selectNodeControls.Remove(nodeControl);
|
2024-09-17 14:20:27 +08:00
|
|
|
|
}
|
2024-09-18 16:45:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
this.Dispatcher.Invoke(() =>
|
|
|
|
|
|
{
|
|
|
|
|
|
|
2024-09-17 14:20:27 +08:00
|
|
|
|
FlowChartCanvas.Children.Remove(nodeControl);
|
|
|
|
|
|
NodeControls.Remove(nodeControl.ViewModel.Node.Guid);
|
|
|
|
|
|
});
|
2024-08-05 10:11:58 +08:00
|
|
|
|
}
|
2024-09-15 12:15:32 +08:00
|
|
|
|
|
2024-08-05 10:11:58 +08:00
|
|
|
|
/// <summary>
|
2024-09-15 12:15:32 +08:00
|
|
|
|
/// 编辑项目时添加了节点
|
2024-08-05 10:11:58 +08:00
|
|
|
|
/// </summary>
|
2024-09-15 12:15:32 +08:00
|
|
|
|
/// <param name="nodeDataBase"></param>
|
|
|
|
|
|
/// <exception cref="NotImplementedException"></exception>
|
|
|
|
|
|
private void FlowEnvironment_NodeCreateEvent(NodeCreateEventArgs eventArgs)
|
2024-08-05 10:11:58 +08:00
|
|
|
|
{
|
2024-09-17 14:20:27 +08:00
|
|
|
|
this.Dispatcher.Invoke(() =>
|
2024-08-05 10:11:58 +08:00
|
|
|
|
{
|
2024-09-17 14:20:27 +08:00
|
|
|
|
if (eventArgs.NodeModel is not NodeModelBase nodeModelBase)
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2024-09-15 12:15:32 +08:00
|
|
|
|
|
2024-09-17 14:20:27 +08:00
|
|
|
|
// MethodDetails methodDetailss = eventArgs.MethodDetailss;
|
|
|
|
|
|
Position position = eventArgs.Position;
|
2024-09-15 12:15:32 +08:00
|
|
|
|
|
2024-09-17 14:20:27 +08:00
|
|
|
|
// 创建对应控件
|
|
|
|
|
|
NodeControlBase? nodeControl = nodeModelBase.ControlType switch
|
|
|
|
|
|
{
|
|
|
|
|
|
NodeControlType.Action => CreateNodeControl<ActionNodeControl, ActionNodeControlViewModel>(nodeModelBase), //typeof(ActionNodeControl),
|
|
|
|
|
|
NodeControlType.Flipflop => CreateNodeControl<FlipflopNodeControl, FlipflopNodeControlViewModel>(nodeModelBase),
|
|
|
|
|
|
NodeControlType.ExpCondition => CreateNodeControl<ConditionNodeControl, ConditionNodeControlViewModel>(nodeModelBase),
|
|
|
|
|
|
NodeControlType.ExpOp => CreateNodeControl<ExpOpNodeControl, ExpOpNodeViewModel>(nodeModelBase),
|
|
|
|
|
|
NodeControlType.ConditionRegion => CreateNodeControl<ConditionRegionControl, ConditionRegionNodeControlViewModel>(nodeModelBase),
|
|
|
|
|
|
_ => null,
|
|
|
|
|
|
};
|
|
|
|
|
|
if (nodeControl == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
NodeControls.TryAdd(nodeModelBase.Guid, nodeControl);
|
2024-09-15 12:15:32 +08:00
|
|
|
|
|
2024-09-17 14:20:27 +08:00
|
|
|
|
if (eventArgs.IsAddInRegion && NodeControls.TryGetValue(eventArgs.RegeionGuid, out NodeControlBase? regionControl))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (regionControl is not null)
|
|
|
|
|
|
{
|
|
|
|
|
|
TryPlaceNodeInRegion(regionControl, nodeControl);
|
|
|
|
|
|
}
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!TryPlaceNodeInRegion(nodeControl, position))
|
|
|
|
|
|
{
|
|
|
|
|
|
PlaceNodeOnCanvas(nodeControl, position.X, position.Y);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-09-15 12:15:32 +08:00
|
|
|
|
|
2024-09-17 14:20:27 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
});
|
2024-08-05 10:11:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-09-15 12:15:32 +08:00
|
|
|
|
|
2024-08-05 10:11:58 +08:00
|
|
|
|
/// <summary>
|
2024-09-15 12:15:32 +08:00
|
|
|
|
/// 设置了流程起始控件
|
2024-08-05 10:11:58 +08:00
|
|
|
|
/// </summary>
|
2024-09-15 12:15:32 +08:00
|
|
|
|
/// <param name="oldNodeGuid"></param>
|
|
|
|
|
|
/// <param name="newNodeGuid"></param>
|
|
|
|
|
|
private void FlowEnvironment_StartNodeChangeEvent(StartNodeChangeEventArgs eventArgs)
|
2024-08-05 10:11:58 +08:00
|
|
|
|
{
|
2024-09-17 14:20:27 +08:00
|
|
|
|
this.Dispatcher.Invoke(() =>
|
2024-09-15 12:15:32 +08:00
|
|
|
|
{
|
2024-09-17 14:20:27 +08:00
|
|
|
|
string oldNodeGuid = eventArgs.OldNodeGuid;
|
|
|
|
|
|
string newNodeGuid = eventArgs.NewNodeGuid;
|
|
|
|
|
|
if (!NodeControls.TryGetValue(newNodeGuid, out var newStartNodeControl))
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (newStartNodeControl == null)
|
2024-08-05 10:11:58 +08:00
|
|
|
|
{
|
2024-09-17 14:20:27 +08:00
|
|
|
|
return;
|
2024-08-05 10:11:58 +08:00
|
|
|
|
}
|
2024-09-17 14:20:27 +08:00
|
|
|
|
if (!string.IsNullOrEmpty(oldNodeGuid))
|
|
|
|
|
|
{
|
|
|
|
|
|
NodeControls.TryGetValue(oldNodeGuid, out var oldStartNodeControl);
|
|
|
|
|
|
if (oldStartNodeControl != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
oldStartNodeControl.BorderBrush = Brushes.Black;
|
|
|
|
|
|
oldStartNodeControl.BorderThickness = new Thickness(0);
|
|
|
|
|
|
}
|
2024-09-15 12:15:32 +08:00
|
|
|
|
|
2024-09-17 14:20:27 +08:00
|
|
|
|
}
|
2024-09-15 12:15:32 +08:00
|
|
|
|
|
2024-09-17 14:20:27 +08:00
|
|
|
|
newStartNodeControl.BorderBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#04FC10"));
|
|
|
|
|
|
newStartNodeControl.BorderThickness = new Thickness(2);
|
|
|
|
|
|
});
|
2024-09-15 12:15:32 +08:00
|
|
|
|
|
2024-08-05 10:11:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-09-15 12:15:32 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region 加载 DynamicNodeFlow 文件
|
2024-09-17 14:20:27 +08:00
|
|
|
|
|
2024-08-05 10:11:58 +08:00
|
|
|
|
/// <summary>
|
2024-09-15 12:15:32 +08:00
|
|
|
|
/// 运行环节加载了项目文件,需要创建节点控件
|
2024-08-05 10:11:58 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="nodeInfo"></param>
|
2024-09-15 12:15:32 +08:00
|
|
|
|
/// <param name="methodDetailss"></param>
|
2024-08-05 10:11:58 +08:00
|
|
|
|
/// <returns></returns>
|
2024-09-15 12:15:32 +08:00
|
|
|
|
/// <exception cref="NotImplementedException"></exception>
|
|
|
|
|
|
private NodeControlBase? CreateNodeControlOfNodeInfo(NodeInfo nodeInfo, MethodDetails methodDetailss)
|
2024-08-05 10:11:58 +08:00
|
|
|
|
{
|
2024-09-15 12:15:32 +08:00
|
|
|
|
// 创建控件实例
|
|
|
|
|
|
NodeControlBase nodeControl = nodeInfo.Type switch
|
2024-08-05 10:11:58 +08:00
|
|
|
|
{
|
2024-09-17 14:20:27 +08:00
|
|
|
|
$"{NodeStaticConfig.NodeSpaceName}.{nameof(SingleActionNode)}" =>
|
2024-09-15 12:15:32 +08:00
|
|
|
|
CreateNodeControl<SingleActionNode, ActionNodeControl, ActionNodeControlViewModel>(methodDetailss),// 动作节点控件
|
2024-09-17 14:20:27 +08:00
|
|
|
|
$"{NodeStaticConfig.NodeSpaceName}.{nameof(SingleFlipflopNode)}" =>
|
2024-09-15 12:15:32 +08:00
|
|
|
|
CreateNodeControl<SingleFlipflopNode, FlipflopNodeControl, FlipflopNodeControlViewModel>(methodDetailss), // 触发器节点控件
|
2024-08-05 20:32:16 +08:00
|
|
|
|
|
2024-09-17 14:20:27 +08:00
|
|
|
|
$"{NodeStaticConfig.NodeSpaceName}.{nameof(SingleConditionNode)}" =>
|
2024-09-15 12:15:32 +08:00
|
|
|
|
CreateNodeControl<SingleConditionNode, ConditionNodeControl, ConditionNodeControlViewModel>(), // 条件表达式控件
|
2024-09-17 14:20:27 +08:00
|
|
|
|
$"{NodeStaticConfig.NodeSpaceName}.{nameof(SingleExpOpNode)}" =>
|
2024-09-15 12:15:32 +08:00
|
|
|
|
CreateNodeControl<SingleExpOpNode, ExpOpNodeControl, ExpOpNodeViewModel>(), // 操作表达式控件
|
2024-08-05 20:32:16 +08:00
|
|
|
|
|
2024-09-17 14:20:27 +08:00
|
|
|
|
$"{NodeStaticConfig.NodeSpaceName}.{nameof(CompositeConditionNode)}" =>
|
2024-09-15 12:15:32 +08:00
|
|
|
|
CreateNodeControl<CompositeConditionNode, ConditionRegionControl, ConditionRegionNodeControlViewModel>(), // 条件区域控件
|
|
|
|
|
|
_ => throw new NotImplementedException($"非预期的节点类型{nodeInfo.Type}"),
|
2024-08-05 10:11:58 +08:00
|
|
|
|
};
|
2024-09-15 12:15:32 +08:00
|
|
|
|
return nodeControl;
|
|
|
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 加载文件时,添加节点到区域中
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="regionControl"></param>
|
|
|
|
|
|
/// <param name="childNodes"></param>
|
|
|
|
|
|
private void AddNodeControlInRegeionControl(NodeControlBase regionControl, NodeInfo[] childNodes)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var childNode in childNodes)
|
2024-08-05 19:43:57 +08:00
|
|
|
|
{
|
2024-09-15 12:15:32 +08:00
|
|
|
|
if (FlowEnvironment.TryGetMethodDetails(childNode.MethodName, out MethodDetails md))
|
2024-08-05 19:43:57 +08:00
|
|
|
|
{
|
2024-09-15 12:15:32 +08:00
|
|
|
|
var childNodeControl = CreateNodeControlOfNodeInfo(childNode, md);
|
|
|
|
|
|
if (childNodeControl == null)
|
2024-08-05 20:32:16 +08:00
|
|
|
|
{
|
2024-09-15 12:15:32 +08:00
|
|
|
|
WriteLog($"无法为节点类型创建节点控件: {childNode.MethodName}\r\n");
|
|
|
|
|
|
continue;
|
2024-08-05 20:32:16 +08:00
|
|
|
|
}
|
2024-09-15 12:15:32 +08:00
|
|
|
|
|
|
|
|
|
|
if (regionControl is ConditionRegionControl conditionRegion)
|
2024-08-05 20:32:16 +08:00
|
|
|
|
{
|
2024-09-15 12:15:32 +08:00
|
|
|
|
conditionRegion.AddCondition(childNodeControl);
|
2024-08-05 20:32:16 +08:00
|
|
|
|
}
|
2024-08-05 19:43:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-08-05 10:11:58 +08:00
|
|
|
|
}
|
2024-09-15 12:15:32 +08:00
|
|
|
|
|
2024-08-05 10:11:58 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region 节点控件的创建
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-09-15 12:15:32 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 创建了节点,添加到画布。配置默认事件
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="nodeControl"></param>
|
|
|
|
|
|
/// <param name="position"></param>
|
|
|
|
|
|
private void PlaceNodeOnCanvas(NodeControlBase nodeControl, double x, double y)
|
|
|
|
|
|
{
|
|
|
|
|
|
FlowChartCanvas.Dispatcher.Invoke(() =>
|
|
|
|
|
|
{
|
|
|
|
|
|
// 添加控件到画布
|
|
|
|
|
|
FlowChartCanvas.Children.Add(nodeControl);
|
|
|
|
|
|
Canvas.SetLeft(nodeControl, x);
|
|
|
|
|
|
Canvas.SetTop(nodeControl, y);
|
|
|
|
|
|
|
|
|
|
|
|
ConfigureContextMenu(nodeControl); // 配置节点右键菜单
|
|
|
|
|
|
ConfigureNodeEvents(nodeControl); // 配置节点事件
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-08-05 10:11:58 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 配置节点事件
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="nodeControl"></param>
|
|
|
|
|
|
private void ConfigureNodeEvents(NodeControlBase nodeControl)
|
|
|
|
|
|
{
|
|
|
|
|
|
nodeControl.MouseLeftButtonDown += Block_MouseLeftButtonDown;
|
|
|
|
|
|
nodeControl.MouseMove += Block_MouseMove;
|
|
|
|
|
|
nodeControl.MouseLeftButtonUp += Block_MouseLeftButtonUp;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2024-09-15 12:15:32 +08:00
|
|
|
|
/// 开始创建连接 True线 操作,设置起始块和绘制连接线。
|
2024-08-05 10:11:58 +08:00
|
|
|
|
/// </summary>
|
2024-09-15 12:15:32 +08:00
|
|
|
|
private void StartConnection(NodeControlBase startNodeControl, ConnectionType connectionType)
|
2024-08-05 10:11:58 +08:00
|
|
|
|
{
|
2024-09-15 12:15:32 +08:00
|
|
|
|
var tf = Connections.FirstOrDefault(it => it.Start == startNodeControl)?.Type;
|
|
|
|
|
|
IsConnecting = true;
|
|
|
|
|
|
currentConnectionType = connectionType;
|
|
|
|
|
|
startConnectNodeControl = startNodeControl;
|
|
|
|
|
|
|
|
|
|
|
|
// 确保起点和终点位置的正确顺序
|
|
|
|
|
|
currentLine = new Line
|
2024-08-05 10:11:58 +08:00
|
|
|
|
{
|
2024-09-15 12:15:32 +08:00
|
|
|
|
Stroke = connectionType == ConnectionType.IsSucceed ? new SolidColorBrush((Color)ColorConverter.ConvertFromString("#04FC10"))
|
|
|
|
|
|
: connectionType == ConnectionType.IsFail ? new SolidColorBrush((Color)ColorConverter.ConvertFromString("#F18905"))
|
|
|
|
|
|
: connectionType == ConnectionType.IsError ? new SolidColorBrush((Color)ColorConverter.ConvertFromString("#AB616B"))
|
|
|
|
|
|
: new SolidColorBrush((Color)ColorConverter.ConvertFromString("#4A82E4")),
|
|
|
|
|
|
StrokeDashArray = new DoubleCollection([2]),
|
|
|
|
|
|
StrokeThickness = 2,
|
|
|
|
|
|
X1 = Canvas.GetLeft(startConnectNodeControl) + startConnectNodeControl.ActualWidth / 2,
|
|
|
|
|
|
Y1 = Canvas.GetTop(startConnectNodeControl) + startConnectNodeControl.ActualHeight / 2,
|
|
|
|
|
|
X2 = Canvas.GetLeft(startConnectNodeControl) + startConnectNodeControl.ActualWidth / 2, // 初始时终点与起点重合
|
|
|
|
|
|
Y2 = Canvas.GetTop(startConnectNodeControl) + startConnectNodeControl.ActualHeight / 2,
|
|
|
|
|
|
};
|
2024-08-05 10:11:58 +08:00
|
|
|
|
|
2024-09-15 12:15:32 +08:00
|
|
|
|
FlowChartCanvas.Children.Add(currentLine);
|
|
|
|
|
|
this.KeyDown += MainWindow_KeyDown;
|
2024-08-05 10:11:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-09-18 16:45:41 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region 右键菜单事件
|
|
|
|
|
|
|
2024-09-20 10:50:32 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 配置节点右键菜单
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="nodeControl"></param>
|
|
|
|
|
|
private void ConfigureContextMenu(NodeControlBase nodeControl)
|
|
|
|
|
|
{
|
|
|
|
|
|
var contextMenu = new ContextMenu();
|
|
|
|
|
|
|
|
|
|
|
|
// var nodeModel = nodeControl.ViewModel.Node;
|
|
|
|
|
|
|
|
|
|
|
|
if (nodeControl.ViewModel.Node?.MethodDetails?.ReturnType is Type returnType && returnType != typeof(void))
|
|
|
|
|
|
{
|
|
|
|
|
|
contextMenu.Items.Add(CreateMenuItem("查看返回类型", (s, e) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
DisplayReturnTypeTreeViewer(returnType);
|
|
|
|
|
|
}));
|
|
|
|
|
|
}
|
|
|
|
|
|
var nodeGuid = nodeControl?.ViewModel?.Node?.Guid;
|
|
|
|
|
|
|
|
|
|
|
|
MenuItem? debugMenu = null;
|
|
|
|
|
|
debugMenu = CreateMenuItem("在此中断", (s, e) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
if (nodeControl!.ViewModel.DebugSetting.IsInterrupt)
|
|
|
|
|
|
{
|
|
|
|
|
|
nodeControl.ViewModel.IsInterrupt = false;
|
|
|
|
|
|
debugMenu!.Header = "在此中断";
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
nodeControl.ViewModel.IsInterrupt = true;
|
|
|
|
|
|
debugMenu!.Header = "取消中断";
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
contextMenu.Items.Add(debugMenu);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
contextMenu.Items.Add(CreateMenuItem("设为起点", (s, e) => FlowEnvironment.SetStartNode(nodeGuid)));
|
|
|
|
|
|
contextMenu.Items.Add(CreateMenuItem("删除", (s, e) => FlowEnvironment.RemoteNode(nodeGuid)));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
contextMenu.Items.Add(CreateMenuItem("添加 真分支", (s, e) => StartConnection(nodeControl, ConnectionType.IsSucceed)));
|
|
|
|
|
|
contextMenu.Items.Add(CreateMenuItem("添加 假分支", (s, e) => StartConnection(nodeControl, ConnectionType.IsFail)));
|
|
|
|
|
|
contextMenu.Items.Add(CreateMenuItem("添加 异常分支", (s, e) => StartConnection(nodeControl, ConnectionType.IsError)));
|
|
|
|
|
|
contextMenu.Items.Add(CreateMenuItem("添加 上游分支", (s, e) => StartConnection(nodeControl, ConnectionType.Upstream)));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
nodeControl.ContextMenu = contextMenu;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-08-05 10:11:58 +08:00
|
|
|
|
/// <summary>
|
2024-09-15 12:15:32 +08:00
|
|
|
|
/// 配置连接曲线的右键菜单
|
2024-08-05 10:11:58 +08:00
|
|
|
|
/// </summary>
|
2024-09-15 12:15:32 +08:00
|
|
|
|
/// <param name="line"></param>
|
|
|
|
|
|
private void ConfigureLineContextMenu(Connection connection)
|
|
|
|
|
|
{
|
|
|
|
|
|
var contextMenu = new ContextMenu();
|
|
|
|
|
|
contextMenu.Items.Add(CreateMenuItem("删除连线", (s, e) => DeleteConnection(connection)));
|
|
|
|
|
|
connection.ArrowPath.ContextMenu = contextMenu;
|
|
|
|
|
|
connection.BezierPath.ContextMenu = contextMenu;
|
|
|
|
|
|
}
|
2024-09-20 10:50:32 +08:00
|
|
|
|
|
2024-08-05 10:11:58 +08:00
|
|
|
|
/// <summary>
|
2024-09-15 12:15:32 +08:00
|
|
|
|
/// 删除该连线
|
2024-08-05 10:11:58 +08:00
|
|
|
|
/// </summary>
|
2024-09-15 12:15:32 +08:00
|
|
|
|
/// <param name="line"></param>
|
|
|
|
|
|
private void DeleteConnection(Connection connection)
|
2024-08-05 10:11:58 +08:00
|
|
|
|
{
|
2024-09-15 12:15:32 +08:00
|
|
|
|
var connectionToRemove = connection;
|
|
|
|
|
|
if (connectionToRemove == null)
|
2024-08-05 10:11:58 +08:00
|
|
|
|
{
|
2024-09-15 12:15:32 +08:00
|
|
|
|
return;
|
2024-08-05 10:11:58 +08:00
|
|
|
|
}
|
2024-09-15 12:15:32 +08:00
|
|
|
|
// 获取起始节点与终止节点,消除映射关系
|
|
|
|
|
|
var fromNodeGuid = connectionToRemove.Start.ViewModel.Node.Guid;
|
|
|
|
|
|
var toNodeGuid = connectionToRemove.End.ViewModel.Node.Guid;
|
|
|
|
|
|
FlowEnvironment.RemoteConnect(fromNodeGuid, toNodeGuid, connection.Type);
|
2024-08-05 10:11:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2024-09-15 12:15:32 +08:00
|
|
|
|
/// 查看返回类型(树形结构展开类型的成员)
|
2024-08-05 10:11:58 +08:00
|
|
|
|
/// </summary>
|
2024-09-15 12:15:32 +08:00
|
|
|
|
/// <param name="type"></param>
|
|
|
|
|
|
private void DisplayReturnTypeTreeViewer(Type type)
|
2024-08-05 10:11:58 +08:00
|
|
|
|
{
|
2024-09-15 12:15:32 +08:00
|
|
|
|
try
|
2024-08-05 10:11:58 +08:00
|
|
|
|
{
|
2024-09-15 12:15:32 +08:00
|
|
|
|
var typeViewerWindow = new TypeViewerWindow
|
|
|
|
|
|
{
|
|
|
|
|
|
Type = type,
|
|
|
|
|
|
};
|
|
|
|
|
|
typeViewerWindow.LoadTypeInformation();
|
|
|
|
|
|
typeViewerWindow.Show();
|
2024-08-05 10:11:58 +08:00
|
|
|
|
}
|
2024-09-15 12:15:32 +08:00
|
|
|
|
catch (Exception ex)
|
2024-08-05 10:11:58 +08:00
|
|
|
|
{
|
2024-09-15 12:15:32 +08:00
|
|
|
|
Console.WriteLine(ex);
|
2024-08-05 10:11:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
2024-09-15 12:15:32 +08:00
|
|
|
|
#region 拖拽DLL文件到左侧功能区,加载相关节点清单
|
2024-08-05 10:11:58 +08:00
|
|
|
|
/// <summary>
|
2024-09-15 12:15:32 +08:00
|
|
|
|
/// 当拖动文件到窗口时触发,加载DLL文件
|
2024-08-05 10:11:58 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="sender"></param>
|
|
|
|
|
|
/// <param name="e"></param>
|
2024-09-15 12:15:32 +08:00
|
|
|
|
private void Window_Drop(object sender, DragEventArgs e)
|
2024-08-05 10:11:58 +08:00
|
|
|
|
{
|
2024-09-15 12:15:32 +08:00
|
|
|
|
if (e.Data.GetDataPresent(DataFormats.FileDrop))
|
2024-08-05 10:11:58 +08:00
|
|
|
|
{
|
2024-09-15 12:15:32 +08:00
|
|
|
|
string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
|
|
|
|
|
|
foreach (string file in files)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (file.EndsWith(".dll"))
|
|
|
|
|
|
{
|
|
|
|
|
|
FlowEnvironment.LoadDll(file);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-08-05 10:11:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-09-15 12:15:32 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 当拖动文件经过窗口时触发,设置拖放效果为复制
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="sender"></param>
|
|
|
|
|
|
/// <param name="e"></param>
|
|
|
|
|
|
private void Window_DragOver(object sender, DragEventArgs e)
|
2024-08-05 10:11:58 +08:00
|
|
|
|
{
|
2024-09-15 12:15:32 +08:00
|
|
|
|
e.Effects = DragDropEffects.Copy;
|
|
|
|
|
|
e.Handled = true;
|
2024-08-05 10:11:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-09-15 12:15:32 +08:00
|
|
|
|
#endregion
|
2024-08-05 10:11:58 +08:00
|
|
|
|
|
2024-09-15 12:15:32 +08:00
|
|
|
|
#region 与流程图相关的拖拽操作
|
2024-08-05 10:11:58 +08:00
|
|
|
|
|
2024-09-18 16:45:41 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 鼠标在画布移动。
|
|
|
|
|
|
/// 选择控件状态下,调整选择框大小
|
|
|
|
|
|
/// 连接状态下,实时更新连接线的终点位置。
|
|
|
|
|
|
/// 移动画布状态下,移动画布。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void FlowChartCanvas_MouseMove(object sender, MouseEventArgs e)
|
|
|
|
|
|
{
|
2024-09-20 10:50:32 +08:00
|
|
|
|
|
2024-09-18 16:45:41 +08:00
|
|
|
|
if (IsConnecting) // 正在连接节点
|
|
|
|
|
|
{
|
|
|
|
|
|
Point position = e.GetPosition(FlowChartCanvas);
|
|
|
|
|
|
if (currentLine == null || startConnectNodeControl == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
currentLine.X1 = Canvas.GetLeft(startConnectNodeControl) + startConnectNodeControl.ActualWidth / 2;
|
|
|
|
|
|
currentLine.Y1 = Canvas.GetTop(startConnectNodeControl) + startConnectNodeControl.ActualHeight / 2;
|
|
|
|
|
|
currentLine.X2 = position.X;
|
|
|
|
|
|
currentLine.Y2 = position.Y;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (IsCanvasDragging) // 正在移动画布
|
|
|
|
|
|
{
|
|
|
|
|
|
Point currentMousePosition = e.GetPosition(this);
|
2024-09-20 10:50:32 +08:00
|
|
|
|
double deltaX = currentMousePosition.X - startCanvasDragPoint.X;
|
|
|
|
|
|
double deltaY = currentMousePosition.Y - startCanvasDragPoint.Y;
|
2024-09-18 16:45:41 +08:00
|
|
|
|
|
|
|
|
|
|
translateTransform.X += deltaX;
|
|
|
|
|
|
translateTransform.Y += deltaY;
|
|
|
|
|
|
|
2024-09-20 10:50:32 +08:00
|
|
|
|
startCanvasDragPoint = currentMousePosition;
|
2024-09-18 16:45:41 +08:00
|
|
|
|
|
|
|
|
|
|
foreach (var line in Connections)
|
|
|
|
|
|
{
|
|
|
|
|
|
line.Refresh();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-09-20 10:50:32 +08:00
|
|
|
|
if (IsSelectControl && e.LeftButton == MouseButtonState.Pressed) // 正在选取节点
|
|
|
|
|
|
{
|
|
|
|
|
|
// 获取当前鼠标位置
|
|
|
|
|
|
Point currentPoint = e.GetPosition(FlowChartCanvas);
|
|
|
|
|
|
|
|
|
|
|
|
// 更新选取矩形的位置和大小
|
|
|
|
|
|
double x = Math.Min(currentPoint.X, startSelectControolPoint.X);
|
|
|
|
|
|
double y = Math.Min(currentPoint.Y, startSelectControolPoint.Y);
|
|
|
|
|
|
double width = Math.Abs(currentPoint.X - startSelectControolPoint.X);
|
|
|
|
|
|
double height = Math.Abs(currentPoint.Y - startSelectControolPoint.Y);
|
|
|
|
|
|
/*double x = Math.Min(currentPoint.X, startControlDragPoint.X);
|
|
|
|
|
|
double y = Math.Min(currentPoint.Y, startControlDragPoint.Y);
|
|
|
|
|
|
double width = Math.Abs(currentPoint.X - startControlDragPoint.X);
|
|
|
|
|
|
double height = Math.Abs(currentPoint.Y - startControlDragPoint.Y);*/
|
|
|
|
|
|
|
|
|
|
|
|
Canvas.SetLeft(SelectionRectangle, x);
|
|
|
|
|
|
Canvas.SetTop(SelectionRectangle, y);
|
|
|
|
|
|
SelectionRectangle.Width = width;
|
|
|
|
|
|
SelectionRectangle.Height = height;
|
|
|
|
|
|
|
|
|
|
|
|
}
|
2024-09-18 16:45:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-09-15 12:15:32 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 基础节点的拖拽放置创建
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="sender"></param>
|
|
|
|
|
|
/// <param name="e"></param>
|
|
|
|
|
|
private void BaseNodeControl_PreviewMouseMove(object sender, MouseEventArgs e)
|
2024-08-05 10:11:58 +08:00
|
|
|
|
{
|
|
|
|
|
|
if (sender is UserControl control)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 创建一个 DataObject 用于拖拽操作,并设置拖拽效果
|
2024-09-15 12:15:32 +08:00
|
|
|
|
var dragData = new DataObject(MouseNodeType.CreateBaseNodeInCanvas, control.GetType());
|
2024-08-05 10:11:58 +08:00
|
|
|
|
DragDrop.DoDragDrop(control, dragData, DragDropEffects.Move);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 放置操作,根据拖放数据创建相应的控件,并处理相关操作
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="sender"></param>
|
|
|
|
|
|
/// <param name="e"></param>
|
|
|
|
|
|
private void FlowChartCanvas_Drop(object sender, DragEventArgs e)
|
|
|
|
|
|
{
|
2024-09-17 14:20:27 +08:00
|
|
|
|
var canvasDropPosition = e.GetPosition(FlowChartCanvas); // 更新画布落点
|
|
|
|
|
|
Position position = new Position(canvasDropPosition.X, canvasDropPosition.Y);
|
2024-09-15 12:15:32 +08:00
|
|
|
|
if (e.Data.GetDataPresent(MouseNodeType.CreateDllNodeInCanvas))
|
2024-08-05 10:11:58 +08:00
|
|
|
|
{
|
2024-09-15 12:15:32 +08:00
|
|
|
|
if (e.Data.GetData(MouseNodeType.CreateDllNodeInCanvas) is MoveNodeData nodeData)
|
2024-08-05 10:11:58 +08:00
|
|
|
|
{
|
2024-09-15 12:15:32 +08:00
|
|
|
|
// 创建DLL文件的节点对象
|
2024-09-17 14:20:27 +08:00
|
|
|
|
FlowEnvironment.CreateNode(nodeData.NodeControlType, position, nodeData.MethodDetails);
|
2024-08-05 10:11:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-09-15 12:15:32 +08:00
|
|
|
|
else if (e.Data.GetDataPresent(MouseNodeType.CreateBaseNodeInCanvas))
|
2024-08-05 10:11:58 +08:00
|
|
|
|
{
|
2024-09-15 12:15:32 +08:00
|
|
|
|
if (e.Data.GetData(MouseNodeType.CreateBaseNodeInCanvas) is Type droppedType)
|
2024-08-05 10:11:58 +08:00
|
|
|
|
{
|
2024-09-15 12:15:32 +08:00
|
|
|
|
NodeControlType nodeControlType = droppedType switch
|
|
|
|
|
|
{
|
|
|
|
|
|
Type when typeof(ConditionRegionControl).IsAssignableFrom(droppedType) => NodeControlType.ConditionRegion, // 条件区域
|
|
|
|
|
|
Type when typeof(ConditionNodeControl).IsAssignableFrom(droppedType) => NodeControlType.ExpCondition,
|
|
|
|
|
|
Type when typeof(ExpOpNodeControl).IsAssignableFrom(droppedType) => NodeControlType.ExpOp,
|
|
|
|
|
|
_ => NodeControlType.None,
|
|
|
|
|
|
};
|
|
|
|
|
|
if(nodeControlType != NodeControlType.None)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 创建基础节点对象
|
2024-09-17 14:20:27 +08:00
|
|
|
|
FlowEnvironment.CreateNode(nodeControlType, position);
|
2024-09-15 12:15:32 +08:00
|
|
|
|
}
|
2024-09-12 20:32:54 +08:00
|
|
|
|
}
|
2024-08-05 10:11:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
e.Handled = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 尝试将节点放置在区域中
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="nodeControl"></param>
|
|
|
|
|
|
/// <param name="dropPosition"></param>
|
|
|
|
|
|
/// <param name="e"></param>
|
|
|
|
|
|
/// <returns></returns>
|
2024-09-17 14:20:27 +08:00
|
|
|
|
private bool TryPlaceNodeInRegion(NodeControlBase nodeControl, Position position)
|
2024-08-05 10:11:58 +08:00
|
|
|
|
{
|
2024-09-17 14:20:27 +08:00
|
|
|
|
var point = new Point(position.X, position.Y);
|
|
|
|
|
|
HitTestResult hitTestResult = VisualTreeHelper.HitTest(FlowChartCanvas, point);
|
2024-08-05 10:11:58 +08:00
|
|
|
|
if (hitTestResult != null && hitTestResult.VisualHit is UIElement hitElement)
|
|
|
|
|
|
{
|
2024-09-15 12:15:32 +08:00
|
|
|
|
// 准备放置条件表达式控件
|
|
|
|
|
|
if (nodeControl.ViewModel.Node.ControlType == NodeControlType.ExpCondition)
|
2024-08-05 10:11:58 +08:00
|
|
|
|
{
|
|
|
|
|
|
ConditionRegionControl conditionRegion = GetParentOfType<ConditionRegionControl>(hitElement);
|
|
|
|
|
|
if (conditionRegion != null)
|
|
|
|
|
|
{
|
2024-09-17 14:20:27 +08:00
|
|
|
|
TryPlaceNodeInRegion(conditionRegion, nodeControl);
|
|
|
|
|
|
//// 如果存在条件区域容器
|
|
|
|
|
|
//conditionRegion.AddCondition(nodeControl);
|
2024-08-05 10:11:58 +08:00
|
|
|
|
return true;
|
|
|
|
|
|
}
|
2024-09-17 14:20:27 +08:00
|
|
|
|
|
2024-08-05 10:11:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-09-17 14:20:27 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 将节点放在目标区域中
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="regionControl">区域容器</param>
|
|
|
|
|
|
/// <param name="nodeControl">节点控件</param>
|
|
|
|
|
|
private void TryPlaceNodeInRegion(NodeControlBase regionControl, NodeControlBase nodeControl)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 准备放置条件表达式控件
|
|
|
|
|
|
if (nodeControl.ViewModel.Node.ControlType == NodeControlType.ExpCondition)
|
|
|
|
|
|
{
|
|
|
|
|
|
ConditionRegionControl conditionRegion = regionControl as ConditionRegionControl;
|
|
|
|
|
|
if (conditionRegion != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 如果存在条件区域容器
|
|
|
|
|
|
conditionRegion.AddCondition(nodeControl);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-08-05 10:11:58 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 拖动效果,根据拖放数据是否为指定类型设置拖放效果
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="sender"></param>
|
|
|
|
|
|
/// <param name="e"></param>
|
|
|
|
|
|
private void FlowChartCanvas_DragOver(object sender, DragEventArgs e)
|
|
|
|
|
|
{
|
2024-09-15 12:15:32 +08:00
|
|
|
|
if (e.Data.GetDataPresent(MouseNodeType.CreateDllNodeInCanvas)
|
|
|
|
|
|
|| e.Data.GetDataPresent(MouseNodeType.CreateBaseNodeInCanvas))
|
2024-08-05 10:11:58 +08:00
|
|
|
|
{
|
|
|
|
|
|
e.Effects = DragDropEffects.Move;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
e.Effects = DragDropEffects.None;
|
|
|
|
|
|
}
|
|
|
|
|
|
e.Handled = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 控件的鼠标左键按下事件,启动拖动操作。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void Block_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
|
|
|
|
|
{
|
2024-09-09 16:42:01 +08:00
|
|
|
|
IsControlDragging = true;
|
2024-09-20 10:50:32 +08:00
|
|
|
|
startControlDragPoint = e.GetPosition(FlowChartCanvas); // 记录鼠标按下时的位置
|
2024-08-05 10:11:58 +08:00
|
|
|
|
((UIElement)sender).CaptureMouse(); // 捕获鼠标
|
2024-09-20 10:50:32 +08:00
|
|
|
|
e.Handled = true; // 防止事件传播影响其他控件
|
2024-08-05 10:11:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 控件的鼠标移动事件,根据鼠标拖动更新控件的位置。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void Block_MouseMove(object sender, MouseEventArgs e)
|
|
|
|
|
|
{
|
2024-09-20 10:50:32 +08:00
|
|
|
|
if (IsConnecting)
|
|
|
|
|
|
return;
|
|
|
|
|
|
if (IsCanvasDragging)
|
|
|
|
|
|
return;
|
|
|
|
|
|
if (IsSelectControl)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
var IsSelect = Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift);
|
|
|
|
|
|
if (!IsSelect && IsControlDragging) // 如果正在拖动控件
|
2024-08-05 10:11:58 +08:00
|
|
|
|
{
|
|
|
|
|
|
Point currentPosition = e.GetPosition(FlowChartCanvas); // 获取当前鼠标位置
|
|
|
|
|
|
// 获取引发事件的控件
|
|
|
|
|
|
if (sender is not UserControl block)
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-09-20 10:50:32 +08:00
|
|
|
|
double deltaX = currentPosition.X - startControlDragPoint.X; // 计算X轴方向的偏移量
|
|
|
|
|
|
double deltaY = currentPosition.Y - startControlDragPoint.Y; // 计算Y轴方向的偏移量
|
2024-09-10 11:05:48 +08:00
|
|
|
|
|
2024-09-15 12:15:32 +08:00
|
|
|
|
double newLeft = Canvas.GetLeft(block) + deltaX; // 新的左边距
|
|
|
|
|
|
double newTop = Canvas.GetTop(block) + deltaY; // 新的上边距
|
2024-09-10 11:05:48 +08:00
|
|
|
|
|
2024-09-15 12:15:32 +08:00
|
|
|
|
// 限制控件不超出FlowChartCanvas的边界
|
|
|
|
|
|
if (newLeft >= 0 && newLeft + block.ActualWidth <= FlowChartCanvas.ActualWidth)
|
2024-09-09 21:06:47 +08:00
|
|
|
|
{
|
2024-09-15 12:15:32 +08:00
|
|
|
|
Canvas.SetLeft(block, newLeft);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (newTop >= 0 && newTop + block.ActualHeight <= FlowChartCanvas.ActualHeight)
|
|
|
|
|
|
{
|
|
|
|
|
|
Canvas.SetTop(block, newTop);
|
2024-09-09 21:06:47 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-09-15 12:15:32 +08:00
|
|
|
|
UpdateConnections(block);
|
|
|
|
|
|
|
2024-09-20 10:50:32 +08:00
|
|
|
|
startControlDragPoint = currentPosition; // 更新起始点位置
|
2024-09-09 21:06:47 +08:00
|
|
|
|
|
2024-09-15 12:15:32 +08:00
|
|
|
|
}
|
2024-08-05 10:11:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-09-15 12:15:32 +08:00
|
|
|
|
#region UI连接控件操作
|
|
|
|
|
|
|
2024-08-05 10:11:58 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 控件的鼠标左键松开事件,结束拖动操作,创建连线
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void Block_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
|
|
|
|
|
|
{
|
2024-09-09 16:42:01 +08:00
|
|
|
|
if (IsControlDragging)
|
2024-08-05 10:11:58 +08:00
|
|
|
|
{
|
2024-09-09 16:42:01 +08:00
|
|
|
|
IsControlDragging = false;
|
2024-08-05 10:11:58 +08:00
|
|
|
|
((UIElement)sender).ReleaseMouseCapture(); // 释放鼠标捕获
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (IsConnecting)
|
2024-09-15 12:15:32 +08:00
|
|
|
|
{
|
|
|
|
|
|
var formNodeGuid = startConnectNodeControl?.ViewModel.Node.Guid;
|
|
|
|
|
|
var toNodeGuid = (sender as NodeControlBase)?.ViewModel.Node.Guid;
|
|
|
|
|
|
if (string.IsNullOrEmpty(formNodeGuid) || string.IsNullOrEmpty(toNodeGuid))
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
FlowEnvironment.ConnectNode(formNodeGuid, toNodeGuid, currentConnectionType);
|
|
|
|
|
|
}
|
|
|
|
|
|
/*else if (IsConnecting)
|
2024-08-05 10:11:58 +08:00
|
|
|
|
{
|
|
|
|
|
|
bool isRegion = false;
|
|
|
|
|
|
NodeControlBase? targetBlock;
|
|
|
|
|
|
|
|
|
|
|
|
if (sender is ActionNodeControl)
|
|
|
|
|
|
{
|
|
|
|
|
|
targetBlock = sender as ActionNodeControl; // 动作
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (sender is ActionRegionControl)
|
|
|
|
|
|
{
|
|
|
|
|
|
targetBlock = sender as ActionRegionControl; // 组合动作
|
|
|
|
|
|
isRegion = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (sender is ConditionNodeControl)
|
|
|
|
|
|
{
|
|
|
|
|
|
targetBlock = sender as ConditionNodeControl; // 条件
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (sender is ConditionRegionControl)
|
|
|
|
|
|
{
|
|
|
|
|
|
targetBlock = sender as ConditionRegionControl; // 组合条件
|
|
|
|
|
|
isRegion = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (sender is FlipflopNodeControl)
|
|
|
|
|
|
{
|
|
|
|
|
|
targetBlock = sender as FlipflopNodeControl; // 触发器
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (sender is ExpOpNodeControl)
|
|
|
|
|
|
{
|
|
|
|
|
|
targetBlock = sender as ExpOpNodeControl; // 触发器
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
targetBlock = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (targetBlock == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (startConnectBlock != null && targetBlock != null && startConnectBlock != targetBlock)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
2024-08-07 21:17:19 +08:00
|
|
|
|
var connection = new Connection { Start = startConnectBlock, End = targetBlock, Type = currentConnectionType };
|
2024-09-15 12:15:32 +08:00
|
|
|
|
|
2024-08-05 23:04:22 +08:00
|
|
|
|
if (currentConnectionType == ConnectionType.IsSucceed)
|
2024-08-05 10:11:58 +08:00
|
|
|
|
{
|
2024-09-12 20:32:54 +08:00
|
|
|
|
startConnectBlock.ViewModel.Node.SucceedBranch.Add(targetBlock.ViewModel.Node);
|
2024-08-05 10:11:58 +08:00
|
|
|
|
}
|
2024-08-05 23:04:22 +08:00
|
|
|
|
else if (currentConnectionType == ConnectionType.IsFail)
|
2024-08-05 10:11:58 +08:00
|
|
|
|
{
|
2024-09-12 20:32:54 +08:00
|
|
|
|
startConnectBlock.ViewModel.Node.FailBranch.Add(targetBlock.ViewModel.Node);
|
2024-08-05 10:11:58 +08:00
|
|
|
|
}
|
2024-08-05 23:04:22 +08:00
|
|
|
|
else if (currentConnectionType == ConnectionType.IsError)
|
2024-08-05 10:11:58 +08:00
|
|
|
|
{
|
2024-09-12 20:32:54 +08:00
|
|
|
|
startConnectBlock.ViewModel.Node.ErrorBranch.Add(targetBlock.ViewModel.Node);
|
2024-08-05 23:04:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
else if (currentConnectionType == ConnectionType.Upstream)
|
|
|
|
|
|
{
|
2024-09-12 20:32:54 +08:00
|
|
|
|
startConnectBlock.ViewModel.Node.UpstreamBranch.Add(targetBlock.ViewModel.Node);
|
2024-08-05 10:11:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 保存连接关系
|
2024-08-08 21:39:42 +08:00
|
|
|
|
BsControl.Draw(FlowChartCanvas, connection);
|
2024-08-07 21:17:19 +08:00
|
|
|
|
ConfigureLineContextMenu(connection);
|
2024-09-15 12:15:32 +08:00
|
|
|
|
|
2024-09-12 20:32:54 +08:00
|
|
|
|
targetBlock.ViewModel.Node.PreviousNodes.Add(startConnectBlock.ViewModel.Node); // 将当前发起连接的节点,添加到被连接的节点的上一节点队列。(用于回溯)
|
2024-08-07 21:17:19 +08:00
|
|
|
|
connections.Add(connection);
|
2024-08-05 10:11:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
EndConnection();
|
2024-09-15 12:15:32 +08:00
|
|
|
|
}*/
|
2024-08-05 10:11:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 主窗口的KeyDown事件处理,用于在连接操作中按下Esc键取消连接。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void MainWindow_KeyDown(object sender, KeyEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (e.Key == Key.Escape && IsConnecting)
|
|
|
|
|
|
{
|
|
|
|
|
|
this.KeyDown -= MainWindow_KeyDown;
|
|
|
|
|
|
EndConnection();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 结束连接操作,清理状态并移除虚线。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void EndConnection()
|
|
|
|
|
|
{
|
|
|
|
|
|
IsConnecting = false;
|
2024-09-15 12:15:32 +08:00
|
|
|
|
startConnectNodeControl = null;
|
2024-08-05 10:11:58 +08:00
|
|
|
|
// 移除虚线
|
|
|
|
|
|
if (currentLine != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
FlowChartCanvas.Children.Remove(currentLine);
|
|
|
|
|
|
currentLine = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 更新与指定控件相关的所有连接的位置。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void UpdateConnections(UserControl block)
|
|
|
|
|
|
{
|
2024-09-15 12:15:32 +08:00
|
|
|
|
foreach (var connection in Connections)
|
2024-08-05 10:11:58 +08:00
|
|
|
|
{
|
|
|
|
|
|
if (connection.Start == block || connection.End == block)
|
|
|
|
|
|
{
|
2024-08-07 21:17:19 +08:00
|
|
|
|
BezierLineDrawer.UpdateBezierLine(FlowChartCanvas, connection.Start, connection.End, connection.BezierPath, connection.ArrowPath);
|
2024-08-05 10:11:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-09-15 12:15:32 +08:00
|
|
|
|
#endregion
|
2024-09-17 14:20:27 +08:00
|
|
|
|
|
2024-09-18 16:45:41 +08:00
|
|
|
|
|
2024-09-17 14:20:27 +08:00
|
|
|
|
|
2024-09-10 11:05:48 +08:00
|
|
|
|
#region 拖动画布实现缩放平移效果
|
|
|
|
|
|
private void FlowChartCanvas_MouseDown(object sender, MouseButtonEventArgs e)
|
|
|
|
|
|
{
|
2024-09-20 10:50:32 +08:00
|
|
|
|
IsCanvasDragging = true;
|
|
|
|
|
|
startCanvasDragPoint = e.GetPosition(this);
|
|
|
|
|
|
FlowChartCanvas.CaptureMouse();
|
|
|
|
|
|
e.Handled = true; // 防止事件传播影响其他控件
|
|
|
|
|
|
//if (e.MiddleButton == MouseButtonState.Pressed)
|
|
|
|
|
|
//{
|
|
|
|
|
|
|
|
|
|
|
|
//}
|
2024-09-10 11:05:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void FlowChartCanvas_MouseUp(object sender, MouseButtonEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (IsCanvasDragging)
|
|
|
|
|
|
{
|
|
|
|
|
|
IsCanvasDragging = false;
|
|
|
|
|
|
FlowChartCanvas.ReleaseMouseCapture();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 单纯缩放画布,不改变画布大小
|
|
|
|
|
|
private void FlowChartCanvas_MouseWheel(object sender, MouseWheelEventArgs e)
|
|
|
|
|
|
{
|
2024-09-20 10:50:32 +08:00
|
|
|
|
// if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
|
2024-09-10 11:05:48 +08:00
|
|
|
|
{
|
2024-09-10 11:49:56 +08:00
|
|
|
|
if (e.Delta < 0 && scaleTransform.ScaleX < 0.2) return;
|
2024-09-17 14:20:27 +08:00
|
|
|
|
if (e.Delta > 0 && scaleTransform.ScaleY > 1.5) return;
|
2024-09-18 16:45:41 +08:00
|
|
|
|
// 获取鼠标在 Canvas 内的相对位置
|
|
|
|
|
|
var mousePosition = e.GetPosition(FlowChartCanvas);
|
|
|
|
|
|
|
|
|
|
|
|
// 缩放因子,根据滚轮方向调整
|
|
|
|
|
|
double zoomFactor = e.Delta > 0 ? 0.1 : -0.1;
|
|
|
|
|
|
//double zoomFactor = e.Delta > 0 ? 1.1 : 0.9;
|
|
|
|
|
|
|
|
|
|
|
|
// 当前缩放比例
|
|
|
|
|
|
double oldScale = scaleTransform.ScaleX;
|
|
|
|
|
|
// double newScale = oldScale * zoomFactor;
|
|
|
|
|
|
double newScale = oldScale + zoomFactor;
|
|
|
|
|
|
// 更新缩放比例
|
|
|
|
|
|
scaleTransform.ScaleX = newScale;
|
|
|
|
|
|
scaleTransform.ScaleY = newScale;
|
|
|
|
|
|
|
|
|
|
|
|
// 计算缩放前后鼠标相对于 Canvas 的位置差异
|
|
|
|
|
|
// double offsetX = mousePosition.X - (mousePosition.X * zoomFactor);
|
|
|
|
|
|
// double offsetY = mousePosition.Y - (mousePosition.Y * zoomFactor);
|
|
|
|
|
|
|
|
|
|
|
|
// 更新 TranslateTransform,确保以鼠标位置为中心进行缩放
|
|
|
|
|
|
translateTransform.X -= (mousePosition.X * (newScale - oldScale));
|
|
|
|
|
|
translateTransform.Y -= (mousePosition.Y * (newScale - oldScale));
|
2024-09-10 11:05:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 设置画布宽度高度
|
|
|
|
|
|
private void InitializeCanvas(double width, double height)
|
|
|
|
|
|
{
|
|
|
|
|
|
FlowChartCanvas.Width = width;
|
|
|
|
|
|
FlowChartCanvas.Height = height;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#region 动态调整区域大小
|
2024-09-10 11:49:56 +08:00
|
|
|
|
//private void Thumb_DragDelta_TopLeft(object sender, DragDeltaEventArgs e)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// // 从左上角调整大小
|
|
|
|
|
|
// double newWidth = Math.Max(FlowChartCanvas.ActualWidth - e.HorizontalChange, 0);
|
|
|
|
|
|
// double newHeight = Math.Max(FlowChartCanvas.ActualHeight - e.VerticalChange, 0);
|
2024-09-10 11:05:48 +08:00
|
|
|
|
|
2024-09-10 11:49:56 +08:00
|
|
|
|
// FlowChartCanvas.Width = newWidth;
|
|
|
|
|
|
// FlowChartCanvas.Height = newHeight;
|
2024-09-10 11:05:48 +08:00
|
|
|
|
|
2024-09-10 11:49:56 +08:00
|
|
|
|
// Canvas.SetLeft(FlowChartCanvas, Canvas.GetLeft(FlowChartCanvas) + e.HorizontalChange);
|
|
|
|
|
|
// Canvas.SetTop(FlowChartCanvas, Canvas.GetTop(FlowChartCanvas) + e.VerticalChange);
|
|
|
|
|
|
//}
|
2024-09-10 11:05:48 +08:00
|
|
|
|
|
2024-09-10 11:49:56 +08:00
|
|
|
|
//private void Thumb_DragDelta_TopRight(object sender, DragDeltaEventArgs e)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// // 从右上角调整大小
|
|
|
|
|
|
// double newWidth = Math.Max(FlowChartCanvas.ActualWidth + e.HorizontalChange, 0);
|
|
|
|
|
|
// double newHeight = Math.Max(FlowChartCanvas.ActualHeight - e.VerticalChange, 0);
|
2024-09-10 11:05:48 +08:00
|
|
|
|
|
2024-09-10 11:49:56 +08:00
|
|
|
|
// FlowChartCanvas.Width = newWidth;
|
|
|
|
|
|
// FlowChartCanvas.Height = newHeight;
|
2024-09-10 11:05:48 +08:00
|
|
|
|
|
2024-09-10 11:49:56 +08:00
|
|
|
|
// Canvas.SetTop(FlowChartCanvas, Canvas.GetTop(FlowChartCanvas) + e.VerticalChange);
|
|
|
|
|
|
//}
|
2024-09-10 11:05:48 +08:00
|
|
|
|
|
2024-09-10 11:49:56 +08:00
|
|
|
|
//private void Thumb_DragDelta_BottomLeft(object sender, DragDeltaEventArgs e)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// // 从左下角调整大小
|
|
|
|
|
|
// double newWidth = Math.Max(FlowChartCanvas.ActualWidth - e.HorizontalChange, 0);
|
|
|
|
|
|
// double newHeight = Math.Max(FlowChartCanvas.ActualHeight + e.VerticalChange, 0);
|
2024-09-10 11:05:48 +08:00
|
|
|
|
|
2024-09-10 11:49:56 +08:00
|
|
|
|
// FlowChartCanvas.Width = newWidth;
|
|
|
|
|
|
// FlowChartCanvas.Height = newHeight;
|
2024-09-10 11:05:48 +08:00
|
|
|
|
|
2024-09-10 11:49:56 +08:00
|
|
|
|
// Canvas.SetLeft(FlowChartCanvas, Canvas.GetLeft(FlowChartCanvas) + e.HorizontalChange);
|
|
|
|
|
|
//}
|
2024-09-10 11:05:48 +08:00
|
|
|
|
|
|
|
|
|
|
private void Thumb_DragDelta_BottomRight(object sender, DragDeltaEventArgs e)
|
|
|
|
|
|
{
|
2024-09-17 14:20:27 +08:00
|
|
|
|
// 获取缩放后的水平和垂直变化
|
|
|
|
|
|
double horizontalChange = e.HorizontalChange * scaleTransform.ScaleX;
|
|
|
|
|
|
double verticalChange = e.VerticalChange * scaleTransform.ScaleY;
|
2024-09-10 11:49:56 +08:00
|
|
|
|
|
2024-09-17 14:20:27 +08:00
|
|
|
|
// 计算新的宽度和高度,确保不会小于400
|
|
|
|
|
|
double newWidth = Math.Max(FlowChartCanvas.ActualWidth + horizontalChange, 400);
|
|
|
|
|
|
double newHeight = Math.Max(FlowChartCanvas.ActualHeight + verticalChange, 400);
|
2024-09-10 11:49:56 +08:00
|
|
|
|
|
2024-09-18 16:45:41 +08:00
|
|
|
|
newHeight = newHeight < 400 ? 400 : newHeight;
|
|
|
|
|
|
newWidth = newWidth < 400 ? 400 : newWidth;
|
2024-09-10 11:05:48 +08:00
|
|
|
|
|
2024-09-18 16:45:41 +08:00
|
|
|
|
InitializeCanvas(newWidth, newHeight);
|
2024-09-17 14:20:27 +08:00
|
|
|
|
|
|
|
|
|
|
//// 从右下角调整大小
|
|
|
|
|
|
//double newWidth = Math.Max(FlowChartCanvas.ActualWidth + e.HorizontalChange * scaleTransform.ScaleX, 0);
|
|
|
|
|
|
//double newHeight = Math.Max(FlowChartCanvas.ActualHeight + e.VerticalChange * scaleTransform.ScaleY, 0);
|
|
|
|
|
|
|
|
|
|
|
|
//newWidth = newWidth < 400 ? 400 : newWidth;
|
|
|
|
|
|
//newHeight = newHeight < 400 ? 400 : newHeight;
|
|
|
|
|
|
|
|
|
|
|
|
//if (newWidth > 400 && newHeight > 400)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// FlowChartCanvas.Width = newWidth;
|
|
|
|
|
|
// FlowChartCanvas.Height = newHeight;
|
|
|
|
|
|
|
|
|
|
|
|
// double x = e.HorizontalChange > 0 ? -0.5 : 0.5;
|
|
|
|
|
|
// double y = e.VerticalChange > 0 ? -0.5 : 0.5;
|
2024-09-10 11:05:48 +08:00
|
|
|
|
|
2024-09-17 14:20:27 +08:00
|
|
|
|
// double deltaX = x * scaleTransform.ScaleX;
|
|
|
|
|
|
// double deltaY = y * scaleTransform.ScaleY;
|
|
|
|
|
|
// Test(deltaX, deltaY);
|
|
|
|
|
|
//}
|
2024-09-10 11:05:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-09-10 11:49:56 +08:00
|
|
|
|
//private void Thumb_DragDelta_Left(object sender, DragDeltaEventArgs e)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// // 从左侧调整大小
|
|
|
|
|
|
// double newWidth = Math.Max(FlowChartCanvas.ActualWidth - e.HorizontalChange, 0);
|
|
|
|
|
|
|
|
|
|
|
|
// FlowChartCanvas.Width = newWidth;
|
|
|
|
|
|
// Canvas.SetLeft(FlowChartCanvas, Canvas.GetLeft(FlowChartCanvas) + e.HorizontalChange);
|
|
|
|
|
|
//}
|
|
|
|
|
|
|
2024-09-10 11:05:48 +08:00
|
|
|
|
private void Thumb_DragDelta_Right(object sender, DragDeltaEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
//从右侧调整大小
|
2024-09-18 16:45:41 +08:00
|
|
|
|
// 获取缩放后的水平变化
|
2024-09-17 14:20:27 +08:00
|
|
|
|
double horizontalChange = e.HorizontalChange * scaleTransform.ScaleX;
|
|
|
|
|
|
|
2024-09-18 16:45:41 +08:00
|
|
|
|
// 计算新的宽度,确保不会小于400
|
2024-09-17 14:20:27 +08:00
|
|
|
|
double newWidth = Math.Max(FlowChartCanvas.ActualWidth + horizontalChange, 400);
|
2024-09-18 16:45:41 +08:00
|
|
|
|
|
|
|
|
|
|
newWidth = newWidth < 400 ? 400 : newWidth;
|
|
|
|
|
|
InitializeCanvas(newWidth, FlowChartCanvas.Height);
|
2024-09-17 14:20:27 +08:00
|
|
|
|
|
2024-09-10 11:05:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-09-10 11:49:56 +08:00
|
|
|
|
//private void Thumb_DragDelta_Top(object sender, DragDeltaEventArgs e)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// // 从顶部调整大小
|
|
|
|
|
|
// double newHeight = Math.Max(FlowChartCanvas.ActualHeight - e.VerticalChange, 0);
|
2024-09-17 14:20:27 +08:00
|
|
|
|
|
2024-09-10 11:49:56 +08:00
|
|
|
|
// FlowChartCanvas.Height = newHeight;
|
|
|
|
|
|
// Canvas.SetTop(FlowChartCanvas, Canvas.GetTop(FlowChartCanvas) + e.VerticalChange);
|
|
|
|
|
|
//}
|
2024-09-10 11:05:48 +08:00
|
|
|
|
|
|
|
|
|
|
private void Thumb_DragDelta_Bottom(object sender, DragDeltaEventArgs e)
|
|
|
|
|
|
{
|
2024-09-18 16:45:41 +08:00
|
|
|
|
// 获取缩放后的垂直变化
|
|
|
|
|
|
double verticalChange = e.VerticalChange * scaleTransform.ScaleY;
|
|
|
|
|
|
// 计算新的高度,确保不会小于400
|
|
|
|
|
|
double newHeight = Math.Max(FlowChartCanvas.ActualHeight + verticalChange, 400);
|
|
|
|
|
|
newHeight = newHeight < 400 ? 400 : newHeight;
|
|
|
|
|
|
InitializeCanvas(FlowChartCanvas.Width, newHeight);
|
|
|
|
|
|
}
|
2024-09-17 14:20:27 +08:00
|
|
|
|
|
|
|
|
|
|
|
2024-09-18 16:45:41 +08:00
|
|
|
|
private void Test(double deltaX, double deltaY)
|
|
|
|
|
|
{
|
|
|
|
|
|
//Console.WriteLine((translateTransform.X, translateTransform.Y));
|
|
|
|
|
|
//translateTransform.X += deltaX;
|
|
|
|
|
|
//translateTransform.Y += deltaY;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
#endregion
|
2024-09-17 14:20:27 +08:00
|
|
|
|
|
2024-09-18 16:45:41 +08:00
|
|
|
|
#endregion
|
2024-09-17 14:20:27 +08:00
|
|
|
|
|
2024-09-18 16:45:41 +08:00
|
|
|
|
#region 画布中框选节点控件动作
|
2024-09-17 14:20:27 +08:00
|
|
|
|
|
2024-09-18 16:45:41 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 在画布中尝试选取控件
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="sender"></param>
|
|
|
|
|
|
/// <param name="e"></param>
|
|
|
|
|
|
private void FlowChartCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
|
|
|
|
|
{
|
2024-09-20 10:50:32 +08:00
|
|
|
|
IsSelectControl = true;
|
2024-09-17 14:20:27 +08:00
|
|
|
|
|
2024-09-20 10:50:32 +08:00
|
|
|
|
// 开始选取时,记录鼠标起始点
|
|
|
|
|
|
startSelectControolPoint = e.GetPosition(FlowChartCanvas);
|
2024-09-17 14:20:27 +08:00
|
|
|
|
|
2024-09-20 10:50:32 +08:00
|
|
|
|
// 初始化选取矩形的位置和大小
|
|
|
|
|
|
Canvas.SetLeft(SelectionRectangle, startSelectControolPoint.X);
|
|
|
|
|
|
Canvas.SetTop(SelectionRectangle, startSelectControolPoint.Y);
|
|
|
|
|
|
SelectionRectangle.Width = 0;
|
|
|
|
|
|
SelectionRectangle.Height = 0;
|
2024-09-17 14:20:27 +08:00
|
|
|
|
|
2024-09-20 10:50:32 +08:00
|
|
|
|
// 显示选取矩形
|
|
|
|
|
|
SelectionRectangle.Visibility = Visibility.Visible;
|
|
|
|
|
|
SelectionRectangle.ContextMenu ??= ConfiguerSelectionRectangle();
|
2024-09-17 14:20:27 +08:00
|
|
|
|
|
2024-09-20 10:50:32 +08:00
|
|
|
|
// 捕获鼠标,以便在鼠标移动到Canvas外部时仍能处理事件
|
|
|
|
|
|
FlowChartCanvas.CaptureMouse();
|
|
|
|
|
|
|
|
|
|
|
|
//if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
|
|
|
|
|
|
//{
|
|
|
|
|
|
|
|
|
|
|
|
//}
|
|
|
|
|
|
e.Handled = true; // 防止事件传播影响其他控件
|
2024-09-18 16:45:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private ContextMenu ConfiguerSelectionRectangle()
|
|
|
|
|
|
{
|
|
|
|
|
|
var contextMenu = new ContextMenu();
|
|
|
|
|
|
contextMenu.Items.Add(CreateMenuItem("删除", (s, e) =>
|
2024-09-17 14:20:27 +08:00
|
|
|
|
{
|
2024-09-18 16:45:41 +08:00
|
|
|
|
if(selectNodeControls.Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach(var node in selectNodeControls.ToArray())
|
|
|
|
|
|
{
|
|
|
|
|
|
var guid = node?.ViewModel?.Node?.Guid;
|
|
|
|
|
|
if (!string.IsNullOrEmpty(guid))
|
|
|
|
|
|
{
|
|
|
|
|
|
FlowEnvironment.RemoteNode(guid);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
SelectionRectangle.Visibility = Visibility.Collapsed;
|
|
|
|
|
|
}));
|
|
|
|
|
|
return contextMenu;
|
|
|
|
|
|
// nodeControl.ContextMenu = contextMenu;
|
|
|
|
|
|
}
|
2024-09-17 14:20:27 +08:00
|
|
|
|
|
2024-09-18 16:45:41 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 在画布中释放鼠标按下,结束选取状态
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="sender"></param>
|
|
|
|
|
|
/// <param name="e"></param>
|
|
|
|
|
|
private void FlowChartCanvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (IsSelectControl)
|
|
|
|
|
|
{
|
|
|
|
|
|
CancelSelectNode(); // 取消之前选择的控件
|
|
|
|
|
|
IsSelectControl = false;
|
|
|
|
|
|
// 释放鼠标捕获
|
|
|
|
|
|
FlowChartCanvas.ReleaseMouseCapture();
|
2024-09-17 14:20:27 +08:00
|
|
|
|
|
2024-09-18 16:45:41 +08:00
|
|
|
|
// 隐藏选取矩形(如果需要保持选取状态显示,可以删除此行)
|
|
|
|
|
|
// SelectionRectangle.Visibility = Visibility.Collapsed;
|
2024-09-17 14:20:27 +08:00
|
|
|
|
|
2024-09-18 16:45:41 +08:00
|
|
|
|
// 处理选取区域内的元素(例如,获取选取范围内的控件)
|
|
|
|
|
|
Rect selectionArea = new Rect(Canvas.GetLeft(SelectionRectangle),
|
|
|
|
|
|
Canvas.GetTop(SelectionRectangle),
|
|
|
|
|
|
SelectionRectangle.Width,
|
|
|
|
|
|
SelectionRectangle.Height);
|
2024-09-10 11:05:48 +08:00
|
|
|
|
|
|
|
|
|
|
|
2024-09-18 16:45:41 +08:00
|
|
|
|
|
|
|
|
|
|
// 在此处处理选取的逻辑
|
|
|
|
|
|
foreach (UIElement element in FlowChartCanvas.Children)
|
|
|
|
|
|
{
|
|
|
|
|
|
Rect elementBounds = new Rect(Canvas.GetLeft(element), Canvas.GetTop(element),
|
|
|
|
|
|
element.RenderSize.Width, element.RenderSize.Height);
|
|
|
|
|
|
|
|
|
|
|
|
if (selectionArea.Contains(elementBounds))
|
|
|
|
|
|
{
|
|
|
|
|
|
// 选中元素,执行相应操作
|
|
|
|
|
|
if (element is NodeControlBase control)
|
|
|
|
|
|
{
|
|
|
|
|
|
selectNodeControls.Add(control);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
SelectedNode();// 选择之后需要执行的操作
|
|
|
|
|
|
}
|
2024-09-17 14:20:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-09-18 16:45:41 +08:00
|
|
|
|
private void SelectedNode()
|
|
|
|
|
|
{
|
|
|
|
|
|
if(selectNodeControls.Count == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
Console.WriteLine($"没有选择控件");
|
2024-09-20 10:50:32 +08:00
|
|
|
|
SelectionRectangle.Visibility = Visibility.Collapsed;
|
2024-09-18 16:45:41 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
Console.WriteLine($"一共选取了{selectNodeControls.Count}个控件");
|
|
|
|
|
|
foreach (var node in selectNodeControls)
|
|
|
|
|
|
{
|
|
|
|
|
|
node.ViewModel.Selected();
|
|
|
|
|
|
node.ViewModel.CancelSelect();
|
2024-09-20 10:50:32 +08:00
|
|
|
|
node.BorderBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#FFC700"));
|
|
|
|
|
|
node.BorderThickness = new Thickness(4);
|
2024-09-18 16:45:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
private void CancelSelectNode()
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var node in selectNodeControls)
|
|
|
|
|
|
{
|
|
|
|
|
|
node.ViewModel.CancelSelect();
|
2024-09-20 10:50:32 +08:00
|
|
|
|
node.BorderBrush = Brushes.Black;
|
|
|
|
|
|
node.BorderThickness = new Thickness(0);
|
2024-09-18 16:45:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
selectNodeControls.Clear();
|
|
|
|
|
|
}
|
2024-09-10 11:05:48 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
2024-09-20 10:50:32 +08:00
|
|
|
|
#region 窗体静态方法
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static TControl CreateNodeControl<TControl, TViewModel>(NodeModelBase model)
|
|
|
|
|
|
where TControl : NodeControlBase
|
|
|
|
|
|
where TViewModel : NodeControlViewModelBase
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
if (model == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new Exception("无法创建节点控件");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var viewModel = Activator.CreateInstance(typeof(TViewModel), [model]);
|
|
|
|
|
|
var controlObj = Activator.CreateInstance(typeof(TControl), [viewModel]);
|
|
|
|
|
|
if (controlObj is TControl control)
|
|
|
|
|
|
{
|
|
|
|
|
|
return control;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new Exception("无法创建节点控件");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
if (nodeBase == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new Exception("无法创建节点控件");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-09-18 16:45:41 +08:00
|
|
|
|
|
2024-09-20 10:50:32 +08:00
|
|
|
|
nodeBase.Guid = Guid.NewGuid().ToString();
|
2024-09-18 16:45:41 +08:00
|
|
|
|
|
2024-09-20 10:50:32 +08:00
|
|
|
|
if (methodDetails != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
var md = methodDetails.Clone();
|
|
|
|
|
|
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("无法创建节点控件");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 创建菜单子项
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="header"></param>
|
|
|
|
|
|
/// <param name="handler"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public static MenuItem CreateMenuItem(string header, RoutedEventHandler handler)
|
|
|
|
|
|
{
|
|
|
|
|
|
var menuItem = new MenuItem { Header = header };
|
|
|
|
|
|
menuItem.Click += handler;
|
|
|
|
|
|
return menuItem;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 穿透元素获取区域容器
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <typeparam name="T"></typeparam>
|
|
|
|
|
|
/// <param name="element"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
private static T GetParentOfType<T>(DependencyObject element) where T : DependencyObject
|
|
|
|
|
|
{
|
|
|
|
|
|
while (element != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (element is T)
|
|
|
|
|
|
{
|
|
|
|
|
|
return element as T;
|
|
|
|
|
|
}
|
|
|
|
|
|
element = VisualTreeHelper.GetParent(element);
|
|
|
|
|
|
}
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
2024-09-18 16:45:41 +08:00
|
|
|
|
|
2024-08-05 10:11:58 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 卸载DLL文件,清空当前项目
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="sender"></param>
|
|
|
|
|
|
/// <param name="e"></param>
|
|
|
|
|
|
private void UnloadAllButton_Click(object sender, RoutedEventArgs e)
|
|
|
|
|
|
{
|
2024-09-15 12:15:32 +08:00
|
|
|
|
FlowEnvironment.ClearAll();
|
2024-08-05 10:11:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 卸载DLL文件,清空当前项目
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="sender"></param>
|
|
|
|
|
|
/// <param name="e"></param>
|
|
|
|
|
|
private void UnloadAllAssemblies()
|
|
|
|
|
|
{
|
|
|
|
|
|
DllStackPanel.Children.Clear();
|
|
|
|
|
|
FlowChartCanvas.Children.Clear();
|
2024-09-15 12:15:32 +08:00
|
|
|
|
Connections.Clear();
|
|
|
|
|
|
NodeControls.Clear();
|
2024-08-05 10:11:58 +08:00
|
|
|
|
currentLine = null;
|
2024-09-15 12:15:32 +08:00
|
|
|
|
startConnectNodeControl = null;
|
2024-08-05 10:11:58 +08:00
|
|
|
|
MessageBox.Show("所有DLL已卸载。", "信息", MessageBoxButton.OK, MessageBoxImage.Information);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 运行测试
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="sender"></param>
|
|
|
|
|
|
/// <param name="e"></param>
|
|
|
|
|
|
private async void ButtonDebugRun_Click(object sender, RoutedEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
logWindow?.Show();
|
2024-09-20 10:50:32 +08:00
|
|
|
|
|
|
|
|
|
|
await FlowEnvironment.StartAsync(); // 快
|
|
|
|
|
|
|
|
|
|
|
|
//await Task.Run( FlowEnvironment.StartAsync); // 上下文多次切换的场景中吗慢了1/5
|
|
|
|
|
|
//await Task.Factory.StartNew(FlowEnvironment.StartAsync); // 慢了1/5
|
2024-08-05 10:11:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-09-09 16:42:01 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 退出
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="sender"></param>
|
|
|
|
|
|
/// <param name="e"></param>
|
2024-08-05 10:11:58 +08:00
|
|
|
|
private void ButtonDebugFlipflopNode_Click(object sender, RoutedEventArgs e)
|
|
|
|
|
|
{
|
2024-09-17 14:20:27 +08:00
|
|
|
|
FlowEnvironment?.Exit(); // 在运行平台上点击了退出
|
2024-08-05 10:11:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 保存为项目文件 (正在重写)
|
|
|
|
|
|
/// JsonConvert.SerializeObject 对象序列化字符串
|
|
|
|
|
|
/// JArray.FromObject 数组序列化
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="sender"></param>
|
|
|
|
|
|
/// <param name="e"></param>
|
|
|
|
|
|
private void ButtonSaveFile_Click(object sender, RoutedEventArgs e)
|
|
|
|
|
|
{
|
2024-09-15 12:15:32 +08:00
|
|
|
|
var projectData = FlowEnvironment.SaveProject();
|
|
|
|
|
|
projectData.Basic = new Basic
|
|
|
|
|
|
{
|
2024-09-17 14:20:27 +08:00
|
|
|
|
Canvas = new FlowCanvas
|
2024-09-15 12:15:32 +08:00
|
|
|
|
{
|
2024-09-17 14:20:27 +08:00
|
|
|
|
Lenght = (float)FlowChartCanvas.Width,
|
|
|
|
|
|
Width = (float)FlowChartCanvas.Height,
|
2024-09-15 12:15:32 +08:00
|
|
|
|
},
|
2024-09-17 14:20:27 +08:00
|
|
|
|
Versions = "1",
|
2024-09-15 12:15:32 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
foreach(var node in projectData.Nodes)
|
|
|
|
|
|
{
|
2024-09-17 14:20:27 +08:00
|
|
|
|
|
|
|
|
|
|
if(NodeControls.TryGetValue(node.Guid,out var nodeControl))
|
2024-09-15 12:15:32 +08:00
|
|
|
|
{
|
2024-09-17 14:20:27 +08:00
|
|
|
|
Point positionRelativeToParent = nodeControl.TranslatePoint(new Point(0, 0), FlowChartCanvas);
|
|
|
|
|
|
node.Position = new Position(positionRelativeToParent.X, positionRelativeToParent.Y);
|
|
|
|
|
|
}
|
2024-09-15 12:15:32 +08:00
|
|
|
|
}
|
2024-09-17 14:20:27 +08:00
|
|
|
|
var projectJsonData = JObject.FromObject(projectData);
|
2024-09-15 12:15:32 +08:00
|
|
|
|
var savePath = SaveContentToFile(projectJsonData.ToString());
|
|
|
|
|
|
savePath = System.IO.Path.GetDirectoryName(savePath);
|
|
|
|
|
|
|
|
|
|
|
|
// 复制dll文件
|
|
|
|
|
|
//if (string.IsNullOrEmpty(savePath))
|
|
|
|
|
|
//{
|
|
|
|
|
|
// return;
|
|
|
|
|
|
//}
|
|
|
|
|
|
//foreach (var dll in loadedAssemblies)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// try
|
|
|
|
|
|
// {
|
|
|
|
|
|
// string targetPath = System.IO.Path.Combine(savePath, System.IO.Path.GetFileName(dll.CodeBase));
|
|
|
|
|
|
// // 确保目标目录存在
|
|
|
|
|
|
// Directory.CreateDirectory(savePath);
|
|
|
|
|
|
// var sourceFile = new Uri(dll.CodeBase).LocalPath;
|
|
|
|
|
|
// // 复制文件到目标目录
|
|
|
|
|
|
// File.Copy(sourceFile, targetPath, true);
|
|
|
|
|
|
// }
|
|
|
|
|
|
// catch (Exception ex)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// WriteLog($"DLL复制失败:{dll.CodeBase} \r\n错误:{ex}\r\n");
|
|
|
|
|
|
// }
|
|
|
|
|
|
//}
|
2024-08-05 10:11:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
public static string? SaveContentToFile(string content)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 创建一个新的保存文件对话框
|
|
|
|
|
|
SaveFileDialog saveFileDialog = new()
|
|
|
|
|
|
{
|
|
|
|
|
|
Filter = "NF Files (*.dnf)|*.dnf",
|
|
|
|
|
|
DefaultExt = "nf",
|
|
|
|
|
|
FileName = "project.dnf"
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 显示保存文件对话框
|
|
|
|
|
|
bool? result = saveFileDialog.ShowDialog();
|
|
|
|
|
|
|
|
|
|
|
|
// 如果用户选择了文件并点击了保存按钮
|
|
|
|
|
|
if (result == true)
|
|
|
|
|
|
{
|
|
|
|
|
|
string filePath = saveFileDialog.FileName;
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 将文本内容写入文件
|
|
|
|
|
|
File.WriteAllText(filePath, content);
|
|
|
|
|
|
MessageBox.Show($"文本已成功保存到文件: {filePath}", "保存成功", MessageBoxButton.OK, MessageBoxImage.Information);
|
|
|
|
|
|
return filePath;
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
MessageBox.Show($"保存文件时出现错误: {ex.Message}", "保存错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
public static string GetRelativePath(string baseDirectory, string fullPath)
|
|
|
|
|
|
{
|
|
|
|
|
|
Uri baseUri = new(baseDirectory + System.IO.Path.DirectorySeparatorChar);
|
|
|
|
|
|
Uri fullUri = new(fullPath);
|
|
|
|
|
|
Uri relativeUri = baseUri.MakeRelativeUri(fullUri);
|
|
|
|
|
|
return Uri.UnescapeDataString(relativeUri.ToString().Replace('/', System.IO.Path.DirectorySeparatorChar));
|
|
|
|
|
|
}
|
2024-09-20 10:50:32 +08:00
|
|
|
|
|
|
|
|
|
|
private void Window_PreviewTextInput(object sender, TextCompositionEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void Window_PreviewKeyDown(object sender, KeyEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
//if (e.KeyStates == Keyboard.GetKeyStates(Key.D8) && Keyboard.Modifiers == ModifierKeys.Shift)
|
|
|
|
|
|
//if (Keyboard.Modifiers == ModifierKeys.Shift)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// startSelectControolPoint = e.GetPosition(FlowChartCanvas);
|
|
|
|
|
|
//}
|
|
|
|
|
|
}
|
2024-09-09 16:42:01 +08:00
|
|
|
|
}
|
2024-09-17 14:20:27 +08:00
|
|
|
|
|
2024-09-09 16:42:01 +08:00
|
|
|
|
#region 创建两个控件之间的连接关系,在UI层面上显示为 带箭头指向的贝塞尔曲线
|
2024-08-07 21:17:19 +08:00
|
|
|
|
|
|
|
|
|
|
|
2024-09-09 16:42:01 +08:00
|
|
|
|
public static class BsControl
|
|
|
|
|
|
{
|
|
|
|
|
|
public static Connection Draw(Canvas canvas, Connection connection)
|
2024-08-07 21:17:19 +08:00
|
|
|
|
{
|
2024-09-09 16:42:01 +08:00
|
|
|
|
connection.Canvas = canvas;
|
|
|
|
|
|
UpdateBezierLine(canvas, connection);
|
|
|
|
|
|
//MakeDraggable(canvas, connection, connection.Start);
|
|
|
|
|
|
//MakeDraggable(canvas, connection, connection.End);
|
|
|
|
|
|
|
|
|
|
|
|
if (connection.BezierPath == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
connection.BezierPath = new System.Windows.Shapes.Path { Stroke = BezierLineDrawer.GetStroke(connection.Type), StrokeThickness = 1 };
|
|
|
|
|
|
Canvas.SetZIndex(connection.BezierPath, -1);
|
|
|
|
|
|
canvas.Children.Add(connection.BezierPath);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (connection.ArrowPath == null)
|
2024-08-07 21:17:19 +08:00
|
|
|
|
{
|
2024-09-09 16:42:01 +08:00
|
|
|
|
connection.ArrowPath = new System.Windows.Shapes.Path { Stroke = BezierLineDrawer.GetStroke(connection.Type), Fill = BezierLineDrawer.GetStroke(connection.Type), StrokeThickness = 1 };
|
|
|
|
|
|
Canvas.SetZIndex(connection.ArrowPath, -1);
|
|
|
|
|
|
canvas.Children.Add(connection.ArrowPath);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-09-17 14:20:27 +08:00
|
|
|
|
|
2024-09-09 16:42:01 +08:00
|
|
|
|
BezierLineDrawer.UpdateBezierLine(canvas, connection.Start, connection.End, connection.BezierPath, connection.ArrowPath);
|
2024-09-17 14:20:27 +08:00
|
|
|
|
|
2024-09-09 16:42:01 +08:00
|
|
|
|
return connection;
|
|
|
|
|
|
}
|
2024-08-07 21:17:19 +08:00
|
|
|
|
|
2024-09-09 16:42:01 +08:00
|
|
|
|
private static bool isUpdating = false; // 是否正在更新线条显示
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 拖动时重新绘制
|
|
|
|
|
|
public static void UpdateBezierLine(Canvas canvas, Connection connection)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (isUpdating)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
isUpdating = true;
|
|
|
|
|
|
|
|
|
|
|
|
canvas.Dispatcher.InvokeAsync(() =>
|
|
|
|
|
|
{
|
|
|
|
|
|
if (connection != null && connection.BezierPath == null)
|
2024-08-07 21:17:19 +08:00
|
|
|
|
{
|
|
|
|
|
|
connection.BezierPath = new System.Windows.Shapes.Path { Stroke = BezierLineDrawer.GetStroke(connection.Type), StrokeThickness = 1 };
|
2024-09-09 16:42:01 +08:00
|
|
|
|
//Canvas.SetZIndex(connection.BezierPath, -1);
|
2024-08-07 21:17:19 +08:00
|
|
|
|
canvas.Children.Add(connection.BezierPath);
|
|
|
|
|
|
}
|
2024-09-09 16:42:01 +08:00
|
|
|
|
|
|
|
|
|
|
if (connection != null && connection.ArrowPath == null)
|
2024-08-07 21:17:19 +08:00
|
|
|
|
{
|
|
|
|
|
|
connection.ArrowPath = new System.Windows.Shapes.Path { Stroke = BezierLineDrawer.GetStroke(connection.Type), Fill = BezierLineDrawer.GetStroke(connection.Type), StrokeThickness = 1 };
|
2024-09-09 16:42:01 +08:00
|
|
|
|
//Canvas.SetZIndex(connection.ArrowPath, -1);
|
2024-08-07 21:17:19 +08:00
|
|
|
|
canvas.Children.Add(connection.ArrowPath);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BezierLineDrawer.UpdateBezierLine(canvas, connection.Start, connection.End, connection.BezierPath, connection.ArrowPath);
|
2024-09-09 16:42:01 +08:00
|
|
|
|
isUpdating = false;
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
2024-08-07 21:17:19 +08:00
|
|
|
|
|
2024-09-09 16:42:01 +08:00
|
|
|
|
// private static Point clickPosition; // 当前点击事件
|
|
|
|
|
|
// private static bool isDragging = false; // 是否正在移动控件
|
|
|
|
|
|
//private static void MakeDraggable(Canvas canvas, Connection connection, UIElement element)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// if (connection.IsSetEven)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// return;
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
// element.MouseLeftButtonDown += (sender, e) =>
|
|
|
|
|
|
// {
|
|
|
|
|
|
// isDragging = true;
|
|
|
|
|
|
// //clickPosition = e.GetPosition(element);
|
|
|
|
|
|
// //element.CaptureMouse();
|
|
|
|
|
|
// };
|
|
|
|
|
|
// element.MouseLeftButtonUp += (sender, e) =>
|
|
|
|
|
|
// {
|
|
|
|
|
|
// isDragging = false;
|
|
|
|
|
|
// //element.ReleaseMouseCapture();
|
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
|
|
|
|
// element.MouseMove += (sender, e) =>
|
|
|
|
|
|
// {
|
|
|
|
|
|
// if (isDragging)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// if (VisualTreeHelper.GetParent(element) is Canvas canvas)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// Point currentPosition = e.GetPosition(canvas);
|
|
|
|
|
|
// double newLeft = currentPosition.X - clickPosition.X;
|
|
|
|
|
|
// double newTop = currentPosition.Y - clickPosition.Y;
|
|
|
|
|
|
|
|
|
|
|
|
// Canvas.SetLeft(element, newLeft);
|
|
|
|
|
|
// Canvas.SetTop(element, newTop);
|
|
|
|
|
|
// UpdateBezierLine(canvas, connection);
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//}
|
|
|
|
|
|
}
|
2024-08-07 21:17:19 +08:00
|
|
|
|
|
|
|
|
|
|
|
2024-09-09 16:42:01 +08:00
|
|
|
|
public class Connection
|
|
|
|
|
|
{
|
|
|
|
|
|
public ConnectionType Type { get; set; }
|
|
|
|
|
|
public Canvas Canvas { get; set; }// 贝塞尔曲线所在画布
|
2024-08-07 21:17:19 +08:00
|
|
|
|
|
2024-09-09 16:42:01 +08:00
|
|
|
|
public System.Windows.Shapes.Path BezierPath { get; set; }// 贝塞尔曲线路径
|
|
|
|
|
|
public System.Windows.Shapes.Path ArrowPath { get; set; } // 箭头路径
|
2024-08-07 21:17:19 +08:00
|
|
|
|
|
2024-09-09 16:42:01 +08:00
|
|
|
|
public required NodeControlBase Start { get; set; } // 起始
|
|
|
|
|
|
public required NodeControlBase End { get; set; } // 结束
|
2024-08-07 21:17:19 +08:00
|
|
|
|
|
2024-09-09 16:42:01 +08:00
|
|
|
|
private Storyboard? _animationStoryboard; // 动画Storyboard
|
2024-08-07 21:17:19 +08:00
|
|
|
|
|
2024-09-09 16:42:01 +08:00
|
|
|
|
public void RemoveFromCanvas(Canvas canvas)
|
|
|
|
|
|
{
|
|
|
|
|
|
canvas.Children.Remove(BezierPath); // 移除线
|
|
|
|
|
|
canvas.Children.Remove(ArrowPath); // 移除线
|
|
|
|
|
|
_animationStoryboard?.Stop(); // 停止动画
|
2024-08-07 21:17:19 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-09-09 16:42:01 +08:00
|
|
|
|
public void Refresh()
|
2024-08-07 21:17:19 +08:00
|
|
|
|
{
|
2024-09-17 14:20:27 +08:00
|
|
|
|
// BsControl.Draw(Canvas, this);
|
|
|
|
|
|
BezierLineDrawer.UpdateBezierLine(Canvas, Start, End, BezierPath, ArrowPath);
|
2024-09-09 16:42:01 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-09-07 15:56:34 +08:00
|
|
|
|
|
2024-09-09 16:42:01 +08:00
|
|
|
|
public static class BezierLineDrawer
|
|
|
|
|
|
{
|
|
|
|
|
|
public enum Localhost
|
|
|
|
|
|
{
|
|
|
|
|
|
Left,
|
|
|
|
|
|
Right,
|
|
|
|
|
|
Top,
|
|
|
|
|
|
Bottom,
|
|
|
|
|
|
}
|
2024-08-07 21:17:19 +08:00
|
|
|
|
|
2024-09-09 16:42:01 +08:00
|
|
|
|
// 绘制曲线
|
|
|
|
|
|
public static void UpdateBezierLine(Canvas canvas,
|
|
|
|
|
|
FrameworkElement startElement,
|
|
|
|
|
|
FrameworkElement endElement,
|
|
|
|
|
|
System.Windows.Shapes.Path bezierPath,
|
|
|
|
|
|
System.Windows.Shapes.Path arrowPath)
|
|
|
|
|
|
{
|
|
|
|
|
|
Point startPoint = startElement.TranslatePoint(new Point(startElement.ActualWidth / 2, startElement.ActualHeight / 2), canvas);
|
|
|
|
|
|
Point endPoint = CalculateEndpointOutsideElement(endElement, canvas, startPoint, out Localhost localhost);
|
2024-08-07 21:17:19 +08:00
|
|
|
|
|
2024-09-09 16:42:01 +08:00
|
|
|
|
PathFigure pathFigure = new PathFigure { StartPoint = startPoint };
|
|
|
|
|
|
BezierSegment bezierSegment;
|
2024-08-07 21:17:19 +08:00
|
|
|
|
|
2024-09-09 16:42:01 +08:00
|
|
|
|
if (localhost == Localhost.Left || localhost == Localhost.Right)
|
2024-08-07 21:17:19 +08:00
|
|
|
|
{
|
2024-09-09 16:42:01 +08:00
|
|
|
|
bezierSegment = new BezierSegment
|
|
|
|
|
|
{
|
|
|
|
|
|
Point1 = new Point((startPoint.X + endPoint.X) / 2, startPoint.Y),
|
|
|
|
|
|
Point2 = new Point((startPoint.X + endPoint.X) / 2, endPoint.Y),
|
|
|
|
|
|
Point3 = endPoint,
|
|
|
|
|
|
};
|
2024-09-07 15:56:34 +08:00
|
|
|
|
}
|
2024-09-09 16:42:01 +08:00
|
|
|
|
else // if (localhost == Localhost.Top || localhost == Localhost.Bottom)
|
2024-08-07 21:17:19 +08:00
|
|
|
|
{
|
|
|
|
|
|
|
2024-09-09 16:42:01 +08:00
|
|
|
|
bezierSegment = new BezierSegment
|
2024-08-07 21:17:19 +08:00
|
|
|
|
{
|
2024-09-09 16:42:01 +08:00
|
|
|
|
Point1 = new Point(startPoint.X, (startPoint.Y + endPoint.Y) / 2),
|
|
|
|
|
|
Point2 = new Point(endPoint.X, (startPoint.Y + endPoint.Y) / 2),
|
|
|
|
|
|
Point3 = endPoint,
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
2024-08-07 21:17:19 +08:00
|
|
|
|
|
|
|
|
|
|
|
2024-09-09 16:42:01 +08:00
|
|
|
|
pathFigure.Segments.Add(bezierSegment);
|
2024-08-07 21:17:19 +08:00
|
|
|
|
|
2024-09-09 16:42:01 +08:00
|
|
|
|
PathGeometry pathGeometry = new PathGeometry();
|
|
|
|
|
|
pathGeometry.Figures.Add(pathFigure);
|
|
|
|
|
|
bezierPath.Data = pathGeometry;
|
2024-08-07 21:17:19 +08:00
|
|
|
|
|
2024-09-09 16:42:01 +08:00
|
|
|
|
Point arrowStartPoint = CalculateBezierTangent(startPoint, bezierSegment.Point3, bezierSegment.Point2, endPoint);
|
|
|
|
|
|
UpdateArrowPath(endPoint, arrowStartPoint, arrowPath);
|
|
|
|
|
|
}
|
2024-08-07 21:17:19 +08:00
|
|
|
|
|
2024-09-09 16:42:01 +08:00
|
|
|
|
private static Point CalculateBezierTangent(Point startPoint, Point controlPoint1, Point controlPoint2, Point endPoint)
|
|
|
|
|
|
{
|
|
|
|
|
|
double t = 10.0; // 末端点
|
2024-08-07 21:17:19 +08:00
|
|
|
|
|
2024-09-09 16:42:01 +08:00
|
|
|
|
// 计算贝塞尔曲线在 t = 1 处的一阶导数
|
|
|
|
|
|
double dx = 3 * Math.Pow(1 - t, 2) * (controlPoint1.X - startPoint.X) +
|
|
|
|
|
|
6 * (1 - t) * t * (controlPoint2.X - controlPoint1.X) +
|
|
|
|
|
|
3 * Math.Pow(t, 2) * (endPoint.X - controlPoint2.X);
|
2024-08-07 21:17:19 +08:00
|
|
|
|
|
2024-09-09 16:42:01 +08:00
|
|
|
|
double dy = 3 * Math.Pow(1 - t, 2) * (controlPoint1.Y - startPoint.Y) +
|
|
|
|
|
|
6 * (1 - t) * t * (controlPoint2.Y - controlPoint1.Y) +
|
|
|
|
|
|
3 * Math.Pow(t, 2) * (endPoint.Y - controlPoint2.Y);
|
2024-08-07 21:17:19 +08:00
|
|
|
|
|
2024-09-09 16:42:01 +08:00
|
|
|
|
// 返回切线向量
|
|
|
|
|
|
return new Point(dx, dy);
|
|
|
|
|
|
}
|
2024-08-07 21:17:19 +08:00
|
|
|
|
|
2024-09-09 16:42:01 +08:00
|
|
|
|
// 绘制箭头
|
|
|
|
|
|
private static void UpdateArrowPath(Point endPoint,
|
|
|
|
|
|
Point controlPoint,
|
|
|
|
|
|
System.Windows.Shapes.Path arrowPath)
|
|
|
|
|
|
{
|
2024-08-07 21:17:19 +08:00
|
|
|
|
|
2024-09-09 16:42:01 +08:00
|
|
|
|
double arrowLength = 10;
|
|
|
|
|
|
double arrowWidth = 5;
|
2024-08-07 21:17:19 +08:00
|
|
|
|
|
2024-09-09 16:42:01 +08:00
|
|
|
|
Vector direction = endPoint - controlPoint;
|
|
|
|
|
|
direction.Normalize();
|
2024-08-07 21:17:19 +08:00
|
|
|
|
|
2024-09-09 16:42:01 +08:00
|
|
|
|
Point arrowPoint1 = endPoint + direction * arrowLength + new Vector(-direction.Y, direction.X) * arrowWidth;
|
|
|
|
|
|
Point arrowPoint2 = endPoint + direction * arrowLength + new Vector(direction.Y, -direction.X) * arrowWidth;
|
2024-08-07 21:17:19 +08:00
|
|
|
|
|
2024-09-09 16:42:01 +08:00
|
|
|
|
PathFigure arrowFigure = new PathFigure { StartPoint = endPoint };
|
|
|
|
|
|
arrowFigure.Segments.Add(new LineSegment(arrowPoint1, true));
|
|
|
|
|
|
arrowFigure.Segments.Add(new LineSegment(arrowPoint2, true));
|
|
|
|
|
|
arrowFigure.Segments.Add(new LineSegment(endPoint, true));
|
2024-08-07 21:17:19 +08:00
|
|
|
|
|
2024-09-09 16:42:01 +08:00
|
|
|
|
PathGeometry arrowGeometry = new PathGeometry();
|
|
|
|
|
|
arrowGeometry.Figures.Add(arrowFigure);
|
2024-08-07 21:17:19 +08:00
|
|
|
|
|
2024-09-09 16:42:01 +08:00
|
|
|
|
arrowPath.Data = arrowGeometry;
|
2024-09-17 14:20:27 +08:00
|
|
|
|
|
2024-09-09 16:42:01 +08:00
|
|
|
|
}
|
|
|
|
|
|
// 计算终点落点位置
|
|
|
|
|
|
private static Point CalculateEndpointOutsideElement(FrameworkElement element, Canvas canvas, Point startPoint, out Localhost localhost)
|
|
|
|
|
|
{
|
|
|
|
|
|
Point centerPoint = element.TranslatePoint(new Point(element.ActualWidth / 2, element.ActualHeight / 2), canvas);
|
|
|
|
|
|
Vector direction = centerPoint - startPoint;
|
|
|
|
|
|
direction.Normalize();
|
2024-08-07 21:17:19 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-09-09 16:42:01 +08:00
|
|
|
|
var tx = centerPoint.X - startPoint.X;
|
|
|
|
|
|
var ty = startPoint.Y - centerPoint.Y;
|
2024-08-07 21:17:19 +08:00
|
|
|
|
|
|
|
|
|
|
|
2024-09-09 16:42:01 +08:00
|
|
|
|
localhost = (tx < ty, Math.Abs(tx) > Math.Abs(ty)) switch
|
|
|
|
|
|
{
|
|
|
|
|
|
(true, true) => Localhost.Right,
|
|
|
|
|
|
(true, false) => Localhost.Bottom,
|
|
|
|
|
|
(false, true) => Localhost.Left,
|
|
|
|
|
|
(false, false) => Localhost.Top,
|
|
|
|
|
|
};
|
2024-08-07 21:17:19 +08:00
|
|
|
|
|
2024-09-09 16:42:01 +08:00
|
|
|
|
double halfWidth = element.ActualWidth / 2 + 6;
|
|
|
|
|
|
double halfHeight = element.ActualHeight / 2 + 6;
|
|
|
|
|
|
double margin = 0;
|
2024-08-07 21:17:19 +08:00
|
|
|
|
|
2024-09-09 16:42:01 +08:00
|
|
|
|
if (localhost == Localhost.Left)
|
|
|
|
|
|
{
|
|
|
|
|
|
centerPoint.X -= halfWidth;
|
|
|
|
|
|
centerPoint.Y -= direction.Y / Math.Abs(direction.X) * halfHeight - margin;
|
2024-08-07 21:17:19 +08:00
|
|
|
|
}
|
2024-09-09 16:42:01 +08:00
|
|
|
|
else if (localhost == Localhost.Right)
|
2024-08-07 21:17:19 +08:00
|
|
|
|
{
|
2024-09-09 16:42:01 +08:00
|
|
|
|
centerPoint.X -= -halfWidth;
|
|
|
|
|
|
centerPoint.Y -= direction.Y / Math.Abs(direction.X) * halfHeight - margin;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (localhost == Localhost.Top)
|
|
|
|
|
|
{
|
|
|
|
|
|
centerPoint.Y -= halfHeight;
|
|
|
|
|
|
centerPoint.X -= direction.X / Math.Abs(direction.Y) * halfWidth - margin;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (localhost == Localhost.Bottom)
|
|
|
|
|
|
{
|
|
|
|
|
|
centerPoint.Y -= -halfHeight;
|
|
|
|
|
|
centerPoint.X -= direction.X / Math.Abs(direction.Y) * halfWidth - margin;
|
2024-08-07 21:17:19 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-09-09 16:42:01 +08:00
|
|
|
|
return centerPoint;
|
2024-08-07 21:17:19 +08:00
|
|
|
|
}
|
2024-09-07 15:56:34 +08:00
|
|
|
|
|
2024-09-09 16:42:01 +08:00
|
|
|
|
public static SolidColorBrush GetStroke(ConnectionType currentConnectionType)
|
|
|
|
|
|
{
|
|
|
|
|
|
return currentConnectionType switch
|
|
|
|
|
|
{
|
|
|
|
|
|
ConnectionType.IsSucceed => new SolidColorBrush((Color)ColorConverter.ConvertFromString("#04FC10")),
|
|
|
|
|
|
ConnectionType.IsFail => new SolidColorBrush((Color)ColorConverter.ConvertFromString("#F18905")),
|
|
|
|
|
|
ConnectionType.IsError => new SolidColorBrush((Color)ColorConverter.ConvertFromString("#FE1343")),
|
|
|
|
|
|
ConnectionType.Upstream => new SolidColorBrush((Color)ColorConverter.ConvertFromString("#4A82E4")),
|
|
|
|
|
|
_ => throw new Exception(),
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
2024-09-07 15:56:34 +08:00
|
|
|
|
|
2024-08-05 10:11:58 +08:00
|
|
|
|
}
|
2024-09-09 16:42:01 +08:00
|
|
|
|
#endregion
|
2024-08-05 10:11:58 +08:00
|
|
|
|
|
|
|
|
|
|
}
|