From c47320d4de3dc583dad595797e4e09a8ff2581fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=80=E6=B3=93=E7=A7=8B=E6=B0=B4?= <1090698674@qq.com> Date: Thu, 2 Jan 2025 13:58:40 +0800 Subject: [PATCH 1/2] Delete WorkBench directory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 移除不要的项目文件夹 --- WorkBench/App.xaml | 22 - WorkBench/App.xaml.cs | 75 - WorkBench/AssemblyInfo.cs | 10 - WorkBench/LogWindow.xaml | 24 - WorkBench/LogWindow.xaml.cs | 162 - WorkBench/MainWindow.xaml | 259 -- WorkBench/MainWindow.xaml.cs | 3027 ----------------- WorkBench/MainWindowViewModel.cs | 101 - WorkBench/Node/NodeControlViewModelBase.cs | 48 - WorkBench/Node/View/ActionNodeControl.xaml | 118 - WorkBench/Node/View/ActionNodeControl.xaml.cs | 83 - WorkBench/Node/View/ConditionNodeControl.xaml | 110 - .../Node/View/ConditionNodeControl.xaml.cs | 58 - .../Node/View/ConditionRegionControl.xaml | 22 - .../Node/View/ConditionRegionControl.xaml.cs | 94 - WorkBench/Node/View/DllControlControl.xaml | 34 - WorkBench/Node/View/DllControlControl.xaml.cs | 164 - WorkBench/Node/View/ExpOpNodeControl.xaml | 47 - WorkBench/Node/View/ExpOpNodeControl.xaml.cs | 56 - WorkBench/Node/View/FlipflopNodeControl.xaml | 110 - .../Node/View/FlipflopNodeControl.xaml.cs | 72 - .../ViewModel/ActionNodeControlViewModel.cs | 13 - .../ConditionNodeControlViewModel.cs | 54 - .../ConditionRegionNodeControlViewModel.cs | 18 - .../ViewModel/FlipflopNodeControlViewModel.cs | 14 - .../Node/ViewModel/TypeToStringConverter.cs | 27 - WorkBench/Serein.WorkBench.csproj | 74 - .../Serein.WorkBench_d2hd4tgu_wpftmp.csproj | 288 -- WorkBench/Themes/IOCObjectViewControl.xaml | 28 - WorkBench/Themes/IOCObjectViewControl.xaml.cs | 128 - WorkBench/Themes/InputDialog.xaml | 16 - WorkBench/Themes/InputDialog.xaml.cs | 42 - WorkBench/Themes/MethodDetailsControl.xaml | 129 - WorkBench/Themes/MethodDetailsControl.xaml.cs | 90 - WorkBench/Themes/NodeTreeItemViewControl.xaml | 59 - .../Themes/NodeTreeItemViewControl.xaml.cs | 280 -- WorkBench/Themes/NodeTreeViewControl.xaml | 47 - WorkBench/Themes/NodeTreeViewControl.xaml.cs | 85 - WorkBench/Themes/ObjectViewerControl.xaml | 31 - WorkBench/Themes/ObjectViewerControl.xaml.cs | 670 ---- WorkBench/Themes/TypeViewerWindow.xaml | 16 - WorkBench/Themes/TypeViewerWindow.xaml.cs | 279 -- WorkBench/Themes/WindowDialogInput.xaml | 30 - WorkBench/Themes/WindowDialogInput.xaml.cs | 70 - .../InvertableBooleanToVisibilityConverter.cs | 41 - .../Tool/Converters/ThumbPositionConverter.cs | 79 - .../Tool/Converters/TypeToColorConverter.cs | 26 - 47 files changed, 7330 deletions(-) delete mode 100644 WorkBench/App.xaml delete mode 100644 WorkBench/App.xaml.cs delete mode 100644 WorkBench/AssemblyInfo.cs delete mode 100644 WorkBench/LogWindow.xaml delete mode 100644 WorkBench/LogWindow.xaml.cs delete mode 100644 WorkBench/MainWindow.xaml delete mode 100644 WorkBench/MainWindow.xaml.cs delete mode 100644 WorkBench/MainWindowViewModel.cs delete mode 100644 WorkBench/Node/NodeControlViewModelBase.cs delete mode 100644 WorkBench/Node/View/ActionNodeControl.xaml delete mode 100644 WorkBench/Node/View/ActionNodeControl.xaml.cs delete mode 100644 WorkBench/Node/View/ConditionNodeControl.xaml delete mode 100644 WorkBench/Node/View/ConditionNodeControl.xaml.cs delete mode 100644 WorkBench/Node/View/ConditionRegionControl.xaml delete mode 100644 WorkBench/Node/View/ConditionRegionControl.xaml.cs delete mode 100644 WorkBench/Node/View/DllControlControl.xaml delete mode 100644 WorkBench/Node/View/DllControlControl.xaml.cs delete mode 100644 WorkBench/Node/View/ExpOpNodeControl.xaml delete mode 100644 WorkBench/Node/View/ExpOpNodeControl.xaml.cs delete mode 100644 WorkBench/Node/View/FlipflopNodeControl.xaml delete mode 100644 WorkBench/Node/View/FlipflopNodeControl.xaml.cs delete mode 100644 WorkBench/Node/ViewModel/ActionNodeControlViewModel.cs delete mode 100644 WorkBench/Node/ViewModel/ConditionNodeControlViewModel.cs delete mode 100644 WorkBench/Node/ViewModel/ConditionRegionNodeControlViewModel.cs delete mode 100644 WorkBench/Node/ViewModel/FlipflopNodeControlViewModel.cs delete mode 100644 WorkBench/Node/ViewModel/TypeToStringConverter.cs delete mode 100644 WorkBench/Serein.WorkBench.csproj delete mode 100644 WorkBench/Serein.WorkBench_d2hd4tgu_wpftmp.csproj delete mode 100644 WorkBench/Themes/IOCObjectViewControl.xaml delete mode 100644 WorkBench/Themes/IOCObjectViewControl.xaml.cs delete mode 100644 WorkBench/Themes/InputDialog.xaml delete mode 100644 WorkBench/Themes/InputDialog.xaml.cs delete mode 100644 WorkBench/Themes/MethodDetailsControl.xaml delete mode 100644 WorkBench/Themes/MethodDetailsControl.xaml.cs delete mode 100644 WorkBench/Themes/NodeTreeItemViewControl.xaml delete mode 100644 WorkBench/Themes/NodeTreeItemViewControl.xaml.cs delete mode 100644 WorkBench/Themes/NodeTreeViewControl.xaml delete mode 100644 WorkBench/Themes/NodeTreeViewControl.xaml.cs delete mode 100644 WorkBench/Themes/ObjectViewerControl.xaml delete mode 100644 WorkBench/Themes/ObjectViewerControl.xaml.cs delete mode 100644 WorkBench/Themes/TypeViewerWindow.xaml delete mode 100644 WorkBench/Themes/TypeViewerWindow.xaml.cs delete mode 100644 WorkBench/Themes/WindowDialogInput.xaml delete mode 100644 WorkBench/Themes/WindowDialogInput.xaml.cs delete mode 100644 WorkBench/Tool/Converters/InvertableBooleanToVisibilityConverter.cs delete mode 100644 WorkBench/Tool/Converters/ThumbPositionConverter.cs delete mode 100644 WorkBench/Tool/Converters/TypeToColorConverter.cs diff --git a/WorkBench/App.xaml b/WorkBench/App.xaml deleted file mode 100644 index baa41de..0000000 --- a/WorkBench/App.xaml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - diff --git a/WorkBench/App.xaml.cs b/WorkBench/App.xaml.cs deleted file mode 100644 index a90c015..0000000 --- a/WorkBench/App.xaml.cs +++ /dev/null @@ -1,75 +0,0 @@ -using Newtonsoft.Json; -using Serein.Library; -using Serein.Library.Utils; -using System.Diagnostics; -using System.IO; -using System.Windows; - -namespace Serein.Workbench -{ - - /// - /// Interaction logic for App.xaml - /// - public partial class App : Application - { - private async Task LoadLocalProjectAsync() - { - -#if DEBUG - if (1 == 1) - { - // 这里是测试代码,可以删除 - string filePath; - filePath = @"C:\Users\Az\source\repos\CLBanyunqiState\CLBanyunqiState\bin\Release\net8.0\PLCproject.dnf"; - filePath = @"C:\Users\Az\source\repos\CLBanyunqiState\CLBanyunqiState\bin\Release\banyunqi\project.dnf"; - filePath = @"C:\Users\Az\source\repos\CLBanyunqiState\CLBanyunqiState\bin\debug\net8.0\project.dnf"; - //filePath = @"C:\Users\Az\source\repos\CLBanyunqiState\CLBanyunqiState\bin\debug\net8.0\test.dnf"; - string content = System.IO.File.ReadAllText(filePath); // 读取整个文件内容 - App.FlowProjectData = JsonConvert.DeserializeObject(content); - App.FileDataPath = System.IO.Path.GetDirectoryName(filePath)!; // filePath;// - var dir = Path.GetDirectoryName(filePath); - } -#endif - } - - public static SereinProjectData? FlowProjectData { get; set; } - public static string FileDataPath { get; set; } = ""; - - private async void Application_Startup(object sender, StartupEventArgs e) - { - // 检查是否传入了参数 - if (e.Args.Length == 1) - { - // 获取文件路径 - string filePath = e.Args[0]; - // 检查文件是否存在 - if (!System.IO.File.Exists(filePath)) - { - MessageBox.Show($"文件未找到:{filePath}"); - Shutdown(); // 关闭应用程序 - return; - } - - try - { - // 读取文件内容 - string content = System.IO.File.ReadAllText(filePath); // 读取整个文件内容 - FlowProjectData = JsonConvert.DeserializeObject(content); - FileDataPath = System.IO.Path.GetDirectoryName(filePath) ?? ""; - } - catch (Exception ex) - { - MessageBox.Show($"读取文件时发生错误:{ex.Message}"); - Shutdown(); // 关闭应用程序 - } - - } - await this.LoadLocalProjectAsync(); - - - } - } - -} - diff --git a/WorkBench/AssemblyInfo.cs b/WorkBench/AssemblyInfo.cs deleted file mode 100644 index b0ec827..0000000 --- a/WorkBench/AssemblyInfo.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Windows; - -[assembly: ThemeInfo( - ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located - //(used if a resource is not found in the page, - // or application resource dictionaries) - ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located - //(used if a resource is not found in the page, - // app, or any theme specific resource dictionaries) -)] diff --git a/WorkBench/LogWindow.xaml b/WorkBench/LogWindow.xaml deleted file mode 100644 index 29bc07e..0000000 --- a/WorkBench/LogWindow.xaml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - diff --git a/WorkBench/LogWindow.xaml.cs b/WorkBench/LogWindow.xaml.cs deleted file mode 100644 index 495a979..0000000 --- a/WorkBench/LogWindow.xaml.cs +++ /dev/null @@ -1,162 +0,0 @@ -using System.Windows; - -namespace Serein.Workbench -{ - /// - /// DebugWindow.xaml 的交互逻辑 - /// - using System; - using System.IO; - using System.Text; - using System.Threading.Tasks; - using System.Timers; - using System.Windows; - - /// - /// LogWindow.xaml 的交互逻辑 - /// - public partial class LogWindow : Window - { - private StringBuilder logBuffer = new StringBuilder(); - private int logUpdateInterval = 200; // 批量更新的时间间隔(毫秒) - private Timer logUpdateTimer; - private const int MaxLines = 1000; // 最大显示的行数 - private bool autoScroll = true; // 自动滚动标识 - private int flushThreshold = 5; // 设置日志刷新阈值 - private const int maxFlushSize = 1000; // 每次最大刷新字符数 - - public LogWindow() - { - InitializeComponent(); - - // 初始化定时器,用于批量更新日志 - logUpdateTimer = new Timer(logUpdateInterval); - logUpdateTimer.Elapsed += (s, e) => FlushLog(); // 定时刷新日志 - logUpdateTimer.Start(); - - // 添加滚动事件处理,判断用户是否手动滚动 - // LogTextBox.ScrollChanged += LogTextBox_ScrollChanged; - } - - /// - /// 添加日志到缓冲区 - /// - public void AppendText(string text) - { - lock (logBuffer) - { - logBuffer.Append(text); - - // 异步写入日志到文件 - // Task.Run(() => File.AppendAllText("log.txt", text)); - //FlushLog(); - // 如果日志达到阈值,立即刷新 - if (logBuffer.Length > flushThreshold) - { - FlushLog(); - } - } - } - - /// - /// 清空日志缓冲区并更新到 TextBox 中 - /// - private void FlushLog() - { - if (logBuffer.Length == 0) return; - - Dispatcher.InvokeAsync(() => - { - lock (logBuffer) - { - // 仅追加部分日志,避免一次更新过多内容 - string logContent = logBuffer.Length > maxFlushSize - ? logBuffer.ToString(0, maxFlushSize) - : logBuffer.ToString(); - logBuffer.Remove(0, logContent.Length); // 清空已更新的部分 - - LogTextBox.Dispatcher.Invoke(() => - { - LogTextBox.AppendText(logContent); - }); - - } - - // 不必每次都修剪日志,当行数超过限制20%时再修剪 - if (LogTextBox.LineCount > MaxLines * 1.2) - { - TrimLog(); - } - - ScrollToEndIfNeeded(); // 根据是否需要自动滚动来决定 - }, System.Windows.Threading.DispatcherPriority.Background); - } - - /// - /// 限制日志输出的最大行数,超出时删除旧日志 - /// - private void TrimLog() - { - if (LogTextBox.LineCount > MaxLines) - { - // 删除最早的多余行 - LogTextBox.Text = LogTextBox.Text.Substring( - LogTextBox.GetCharacterIndexFromLineIndex(LogTextBox.LineCount - MaxLines)); - } - } - - /// - /// 检测用户是否手动滚动了文本框 - /// - private void LogTextBox_ScrollChanged(object sender, System.Windows.Controls.ScrollChangedEventArgs e) - { - if (e.ExtentHeightChange == 0) // 用户手动滚动时 - { - // 判断是否滚动到底部 - //autoScroll = LogTextBox.VerticalOffset == LogTextBox.ScrollableHeight; - } - } - - /// - /// 根据 autoScroll 标志决定是否滚动到末尾 - /// - private void ScrollToEndIfNeeded() - { - if (autoScroll) - { - LogTextBox.ScrollToEnd(); // 仅在需要时滚动到末尾 - } - } - - /// - /// 清空日志 - /// - public void Clear() - { - Dispatcher.BeginInvoke(() => - { - LogTextBox.Clear(); - }); - } - - /// - /// 点击清空日志按钮时触发 - /// - private void ClearLog_Click(object sender, RoutedEventArgs e) - { - LogTextBox.Clear(); - } - - /// - /// 窗口关闭事件,隐藏窗体而不是关闭 - /// - private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) - { - logBuffer?.Clear(); - Clear(); - e.Cancel = true; // 取消关闭操作 - this.Hide(); // 隐藏窗体而不是关闭 - } - } - -} diff --git a/WorkBench/MainWindow.xaml b/WorkBench/MainWindow.xaml deleted file mode 100644 index 87cef37..0000000 --- a/WorkBench/MainWindow.xaml +++ /dev/null @@ -1,259 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/WorkBench/MainWindow.xaml.cs b/WorkBench/MainWindow.xaml.cs deleted file mode 100644 index f8c3a5a..0000000 --- a/WorkBench/MainWindow.xaml.cs +++ /dev/null @@ -1,3027 +0,0 @@ -using Microsoft.Win32; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using Serein.Library; -using Serein.Library.Api; -using Serein.Library.Utils; -using Serein.NodeFlow; -using Serein.NodeFlow.Tool; -using Serein.Workbench.Extension; -using Serein.Workbench.Node; -using Serein.Workbench.Node.View; -using Serein.Workbench.Node.ViewModel; -using Serein.Workbench.Themes; -using System.IO; -using System.Runtime.CompilerServices; -using System.Text; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Controls.Primitives; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Animation; -using DataObject = System.Windows.DataObject; - -namespace Serein.Workbench -{ - /// - /// 拖拽创建节点类型 - /// - public static class MouseNodeType - { - /// - /// 创建来自DLL的节点 - /// - public static string CreateDllNodeInCanvas { get; } = nameof(CreateDllNodeInCanvas); - /// - /// 创建基础节点 - /// - public static string CreateBaseNodeInCanvas { get; } = nameof(CreateBaseNodeInCanvas); - } - - - - /// - /// Interaction logic for MainWindow.xaml,第一次用git,不太懂 - /// - public partial class MainWindow : Window - { - /// - /// 全局捕获Console输出事件,打印在这个窗体里面 - /// - private readonly LogWindow LogOutWindow = new LogWindow(); - - /// - /// 流程环境装饰器,方便在本地与远程环境下切换 - /// - private IFlowEnvironment EnvDecorator => ViewModel.FlowEnvironment; - private IFlowEnvironmentEvent EnvEventDecorator => ViewModel.FlowEnvironment as IFlowEnvironmentEvent; - private MainWindowViewModel ViewModel { get; set; } - - - /// - /// 节点对应的控件类型 - /// - // private Dictionary NodeUITypes { get; } = []; - - /// - /// 存储所有与节点有关的控件 - /// 任何情景下都应避免直接操作 ViewModel 中的 NodeModel 节点, - /// 而是应该调用 FlowEnvironment 提供接口进行操作, - /// 因为 Workbench 应该更加关注UI视觉效果,而非直接干扰流程环境运行的逻辑。 - /// 之所以暴露 NodeModel 属性,因为有些场景下不可避免的需要直接获取节点的属性。 - /// - private Dictionary NodeControls { get; } = []; - - /// - /// 存储所有的连接。考虑集成在运行环境中。 - /// - private List Connections { get; } = []; - - /// - /// 起始节点 - /// - //private NodeControlBase StartNodeControl{ get; set; } - - #region 与画布相关的字段 - - /// - /// 标记是否正在尝试选取控件 - /// - private bool IsSelectControl; - /// - /// 标记是否正在进行连接操作 - /// - //private bool IsConnecting; - /// - /// 标记是否正在拖动控件 - /// - private bool IsControlDragging; - /// - /// 标记是否正在拖动画布 - /// - private bool IsCanvasDragging; - private bool IsSelectDragging; - - /// - /// 当前选取的控件 - /// - private readonly List selectNodeControls = []; - - /// - /// 记录开始拖动节点控件时的鼠标位置 - /// - private Point startControlDragPoint; - /// - /// 记录移动画布开始时的鼠标位置 - /// - private Point startCanvasDragPoint; - /// - /// 记录开始选取节点控件时的鼠标位置 - /// - private Point startSelectControolPoint; - - - /// - /// 记录开始连接的文本块 - /// - //private NodeControlBase? startConnectNodeControl; - /// - /// 当前正在绘制的连接线 - /// - //private Line? currentLine; - /// - /// 当前正在绘制的真假分支属性 - /// - //private ConnectionInvokeType currentConnectionType; - - - /// - /// 组合变换容器 - /// - private readonly TransformGroup canvasTransformGroup; - /// - /// 缩放画布 - /// - private readonly ScaleTransform scaleTransform; - /// - /// 平移画布 - /// - private readonly TranslateTransform translateTransform; - #endregion - - - public MainWindow() - { - ViewModel = new MainWindowViewModel(this); - this.DataContext = ViewModel; - InitializeComponent(); - - ViewObjectViewer.FlowEnvironment = EnvDecorator; // 设置 节点树视图 的环境为装饰器 - IOCObjectViewer.FlowEnvironment = EnvDecorator; // 设置 IOC容器视图 的环境为装饰器 - IOCObjectViewer.SelectObj += ViewObjectViewer.LoadObjectInformation; // 使选择 IOC容器视图 的某项(对象)时,可以在 数据视图 呈现数据 - - #region 为 NodeControlType 枚举 不同项添加对应的 Control类型 、 ViewModel类型 - NodeMVVMManagement.RegisterUI(NodeControlType.Action, typeof(ActionNodeControl), typeof(ActionNodeControlViewModel)); - NodeMVVMManagement.RegisterUI(NodeControlType.Flipflop, typeof(FlipflopNodeControl), typeof(FlipflopNodeControlViewModel)); - NodeMVVMManagement.RegisterUI(NodeControlType.ExpOp, typeof(ExpOpNodeControl), typeof(ExpOpNodeControlViewModel)); - NodeMVVMManagement.RegisterUI(NodeControlType.ExpCondition, typeof(ConditionNodeControl), typeof(ConditionNodeControlViewModel)); - NodeMVVMManagement.RegisterUI(NodeControlType.ConditionRegion, typeof(ConditionRegionControl), typeof(ConditionRegionNodeControlViewModel)); - NodeMVVMManagement.RegisterUI(NodeControlType.GlobalData, typeof(GlobalDataControl), typeof(GlobalDataNodeControlViewModel)); - NodeMVVMManagement.RegisterUI(NodeControlType.Script, typeof(ScriptNodeControl), typeof(ScriptNodeControlViewModel)); - #endregion - - - #region 缩放平移容器 - canvasTransformGroup = new TransformGroup(); - scaleTransform = new ScaleTransform(); - translateTransform = new TranslateTransform(); - canvasTransformGroup.Children.Add(scaleTransform); - canvasTransformGroup.Children.Add(translateTransform); - FlowChartCanvas.RenderTransform = canvasTransformGroup; - #endregion - - InitFlowEnvironmentEvent(); // 配置环境事件 - - - } - - - - /// - /// 初始化环境事件 - /// - private void InitFlowEnvironmentEvent() - { - EnvEventDecorator.OnDllLoad += FlowEnvironment_DllLoadEvent; - EnvEventDecorator.OnProjectSaving += EnvDecorator_OnProjectSaving; - EnvEventDecorator.OnProjectLoaded += FlowEnvironment_OnProjectLoaded; - EnvEventDecorator.OnStartNodeChange += FlowEnvironment_StartNodeChangeEvent; - EnvEventDecorator.OnNodeConnectChange += FlowEnvironment_NodeConnectChangeEvemt; - EnvEventDecorator.OnNodeCreate += FlowEnvironment_NodeCreateEvent; - EnvEventDecorator.OnNodeRemove += FlowEnvironment_NodeRemoveEvent; - EnvEventDecorator.OnNodePlace += EnvDecorator_OnNodePlaceEvent; - EnvEventDecorator.OnNodeTakeOut += EnvDecorator_OnNodeTakeOutEvent; - EnvEventDecorator.OnFlowRunComplete += FlowEnvironment_OnFlowRunCompleteEvent; - - - EnvEventDecorator.OnMonitorObjectChange += FlowEnvironment_OnMonitorObjectChangeEvent; - EnvEventDecorator.OnNodeInterruptStateChange += FlowEnvironment_OnNodeInterruptStateChangeEvent; - EnvEventDecorator.OnInterruptTrigger += FlowEnvironment_OnInterruptTriggerEvent; - - EnvEventDecorator.OnIOCMembersChanged += FlowEnvironment_OnIOCMembersChangedEvent; - - EnvEventDecorator.OnNodeLocated += FlowEnvironment_OnNodeLocateEvent; - EnvEventDecorator.OnNodeMoved += FlowEnvironment_OnNodeMovedEvent; - EnvEventDecorator.OnEnvOut += FlowEnvironment_OnEnvOutEvent; - } - - - - /// - /// 移除环境事件 - /// - private void ResetFlowEnvironmentEvent() - { - EnvEventDecorator.OnDllLoad -= FlowEnvironment_DllLoadEvent; - EnvEventDecorator.OnProjectSaving -= EnvDecorator_OnProjectSaving; - EnvEventDecorator.OnProjectLoaded -= FlowEnvironment_OnProjectLoaded; - EnvEventDecorator.OnStartNodeChange -= FlowEnvironment_StartNodeChangeEvent; - EnvEventDecorator.OnNodeConnectChange -= FlowEnvironment_NodeConnectChangeEvemt; - EnvEventDecorator.OnNodeCreate -= FlowEnvironment_NodeCreateEvent; - EnvEventDecorator.OnNodeRemove -= FlowEnvironment_NodeRemoveEvent; - EnvEventDecorator.OnNodePlace -= EnvDecorator_OnNodePlaceEvent; - EnvEventDecorator.OnNodeTakeOut -= EnvDecorator_OnNodeTakeOutEvent; - EnvEventDecorator.OnFlowRunComplete -= FlowEnvironment_OnFlowRunCompleteEvent; - - - EnvEventDecorator.OnMonitorObjectChange -= FlowEnvironment_OnMonitorObjectChangeEvent; - EnvEventDecorator.OnNodeInterruptStateChange -= FlowEnvironment_OnNodeInterruptStateChangeEvent; - EnvEventDecorator.OnInterruptTrigger -= FlowEnvironment_OnInterruptTriggerEvent; - - EnvEventDecorator.OnIOCMembersChanged -= FlowEnvironment_OnIOCMembersChangedEvent; - EnvEventDecorator.OnNodeLocated -= FlowEnvironment_OnNodeLocateEvent; - EnvEventDecorator.OnNodeMoved -= FlowEnvironment_OnNodeMovedEvent; - - EnvEventDecorator.OnEnvOut -= FlowEnvironment_OnEnvOutEvent; - - } - - #region 窗体加载方法 - private async void Window_Loaded(object sender, RoutedEventArgs e) - { - var currentPath = System.IO.Directory.GetCurrentDirectory(); // 当前目录 - var baseLibraryFilePath = Path.Combine(currentPath, FlowLibraryManagement.SereinBaseLibrary); - if (File.Exists(baseLibraryFilePath)) - { - EnvDecorator.LoadLibrary(baseLibraryFilePath); // 默认加载 - } - - if (App.FlowProjectData is not null) - { - try - { - await Task.Run(() => - { - EnvDecorator.LoadProject(new FlowEnvInfo { Project = App.FlowProjectData }, App.FileDataPath); // 加载项目 - }); - } - catch (Exception ex) - { - SereinEnv.WriteLine(ex); - return; - } - } - - // - } - private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) - { - LogOutWindow.Close(); - System.Windows.Application.Current.Shutdown(); - } - private void Window_ContentRendered(object sender, EventArgs e) - { - SereinEnv.WriteLine(InfoType.INFO, "load project..."); - var project = App.FlowProjectData; - if (project is null) - { - return; - } - InitializeCanvas(project.Basic.Canvas.Width, project.Basic.Canvas.Height);// 设置画布大小 - //foreach (var connection in Connections) - //{ - // connection.RefreshLine(); // 窗体完成加载后试图刷新所有连接线 - //} - SereinEnv.WriteLine(InfoType.INFO, $"运行环境当前工作目录:{System.IO.Directory.GetCurrentDirectory()}"); - - var canvasData = project.Basic.Canvas; - if (canvasData is not null) - { - scaleTransform.ScaleX = 1; - scaleTransform.ScaleY = 1; - translateTransform.X = 0; - translateTransform.Y = 0; - scaleTransform.ScaleX = canvasData.ScaleX; - scaleTransform.ScaleY = canvasData.ScaleY; - translateTransform.X += canvasData.ViewX; - translateTransform.Y += canvasData.ViewY; - // 应用变换组 - FlowChartCanvas.RenderTransform = canvasTransformGroup; - } - - - } - - - - - #endregion - - #region 运行环境事件 - - /// - /// 环境内容输出 - /// - /// - /// - private void FlowEnvironment_OnEnvOutEvent(InfoType type, string value) - { - LogOutWindow.AppendText($"{DateTime.Now} [{type}] : {value}{Environment.NewLine}"); - } - - /// - /// 需要保存项目 - /// - /// - /// - private void EnvDecorator_OnProjectSaving(ProjectSavingEventArgs eventArgs) - { - SereinProjectData projectData; - try - { - projectData = EnvDecorator.GetProjectInfoAsync() - .GetAwaiter().GetResult(); // 保存项目 - - } - catch (Exception ex) - { - SereinEnv.WriteLine(ex); - return; - } - - projectData.Basic = new Basic - { - Canvas = new FlowCanvas - { - Height = FlowChartCanvas.Height, - Width = FlowChartCanvas.Width, - ViewX = translateTransform.X, - ViewY = translateTransform.Y, - ScaleX = scaleTransform.ScaleX, - ScaleY = scaleTransform.ScaleY, - }, - Versions = "1", - }; - - // 创建一个新的保存文件对话框 - SaveFileDialog saveFileDialog = new() - { - Filter = "DynamicNodeFlow Files (*.dnf)|*.dnf", - DefaultExt = "dnf", - FileName = "project.dnf" - // FileName = System.IO.Path.GetFileName(App.FileDataPath) - }; - - // 显示保存文件对话框 - bool? result = saveFileDialog.ShowDialog(); - // 如果用户选择了文件并点击了保存按钮 - if (result == false) - { - SereinEnv.WriteLine(InfoType.ERROR, "取消保存文件"); - return; - } - - var savePath = saveFileDialog.FileName; - string? librarySavePath = System.IO.Path.GetDirectoryName(savePath); - if (string.IsNullOrEmpty(librarySavePath)) - { - SereinEnv.WriteLine(InfoType.ERROR, "保存项目DLL时返回了意外的文件保存路径"); - return; - } - - - Uri saveProjectFileUri = new Uri(savePath); - SereinEnv.WriteLine(InfoType.INFO, "项目文件保存路径:" + savePath); - for (int index = 0; index < projectData.Librarys.Length; index++) - { - NodeLibraryInfo? library = projectData.Librarys[index]; - string sourceFilePath = new Uri(library.FilePath).LocalPath; // 源文件夹 - string targetFilePath = System.IO.Path.Combine(librarySavePath, library.FileName); // 目标文件夹 - - try - { - if (File.Exists(sourceFilePath)) - { - if (!File.Exists(targetFilePath)) - { - SereinEnv.WriteLine(InfoType.INFO, $"源文件路径 : {sourceFilePath}"); - SereinEnv.WriteLine(InfoType.INFO, $"目标路径 : {targetFilePath}"); - File.Copy(sourceFilePath, targetFilePath, true); - - } - else - { - SereinEnv.WriteLine(InfoType.WARN, $"目标路径已有类库文件: {targetFilePath}"); - } - } - else - { - SereinEnv.WriteLine(InfoType.WARN, $"源文件不存在 : {targetFilePath}"); - } - } - catch (IOException ex) - { - - SereinEnv.WriteLine(InfoType.ERROR, ex.Message); - } - var dirName = System.IO.Path.GetDirectoryName(targetFilePath); - if (!string.IsNullOrEmpty(dirName)) - { - var tmpUri2 = new Uri(targetFilePath); - var relativePath = saveProjectFileUri.MakeRelativeUri(tmpUri2).ToString(); // 转为类库的相对文件路径 - - - - - //string relativePath = System.IO.Path.GetRelativePath(savePath, targetPath); - projectData.Librarys[index].FilePath = relativePath; - } - - } - - JObject projectJsonData = JObject.FromObject(projectData); - File.WriteAllText(savePath, projectJsonData.ToString()); - - - } - - /// - /// 加载完成 - /// - /// - private void FlowEnvironment_OnProjectLoaded(ProjectLoadedEventArgs eventArgs) - { - } - - /// - /// 运行完成 - /// - /// - /// - private void FlowEnvironment_OnFlowRunCompleteEvent(FlowEventArgs eventArgs) - { - SereinEnv.WriteLine(InfoType.INFO, "-------运行完成---------\r\n"); - this.Dispatcher.Invoke(() => - { - IOCObjectViewer.ClearObjItem(); - }); - } - - /// - /// 加载了DLL文件,dll内容 - /// - private void FlowEnvironment_DllLoadEvent(LoadDllEventArgs eventArgs) - { - NodeLibraryInfo nodeLibraryInfo = eventArgs.NodeLibraryInfo; - List methodDetailss = eventArgs.MethodDetailss; - - var dllControl = new DllControl(nodeLibraryInfo); - - foreach (var methodDetailsInfo in methodDetailss) - { - if (!EnumHelper.TryConvertEnum(methodDetailsInfo.NodeType, out var nodeType)) - { - continue; - } - switch (nodeType) - { - case Library.NodeType.Action: - dllControl.AddAction(methodDetailsInfo); // 添加动作类型到控件 - break; - case Library.NodeType.Flipflop: - dllControl.AddFlipflop(methodDetailsInfo); // 添加触发器方法到控件 - break; - } - - } - var menu = new ContextMenu(); - menu.Items.Add(CreateMenuItem("卸载", (s, e) => - { - if (this.EnvDecorator.TryUnloadLibrary(nodeLibraryInfo.AssemblyName)) - { - DllStackPanel.Children.Remove(dllControl); - } - else - { - SereinEnv.WriteLine(InfoType.INFO, "卸载失败"); - } - })); - - dllControl.ContextMenu = menu; - - DllStackPanel.Children.Add(dllControl); // 将控件添加到界面上显示 - - } - - /// - /// 节点连接关系变更 - /// - /// - private void FlowEnvironment_NodeConnectChangeEvemt(NodeConnectChangeEventArgs eventArgs) - { - string fromNodeGuid = eventArgs.FromNodeGuid; - string toNodeGuid = eventArgs.ToNodeGuid; - if (!TryGetControl(fromNodeGuid, out var fromNodeControl) - || !TryGetControl(toNodeGuid, out var toNodeControl)) - { - return; - } - - if (eventArgs.JunctionOfConnectionType == JunctionOfConnectionType.Invoke) - { - ConnectionInvokeType connectionType = eventArgs.ConnectionInvokeType; - #region 创建/删除节点之间的调用关系 - #region 创建连接 - if (eventArgs.ChangeType == NodeConnectChangeEventArgs.ConnectChangeType.Create) // 添加连接 - { - if (fromNodeControl is not INodeJunction IFormJunction || toNodeControl is not INodeJunction IToJunction) - { - SereinEnv.WriteLine(InfoType.INFO, "非预期的连接"); - return; - } - JunctionControlBase startJunction = IFormJunction.NextStepJunction; - JunctionControlBase endJunction = IToJunction.ExecuteJunction; - - // 添加连接 - var connection = new ConnectionControl( - FlowChartCanvas, - connectionType, - startJunction, - endJunction - ); - - if (toNodeControl is FlipflopNodeControl flipflopControl - && flipflopControl?.ViewModel?.NodeModel is NodeModelBase nodeModel) // 某个节点连接到了触发器,尝试从全局触发器视图中移除该触发器 - { - NodeTreeViewer.RemoveGlobalFlipFlop(nodeModel); // 从全局触发器树树视图中移除 - } - Connections.Add(connection); - fromNodeControl.AddCnnection(connection); - toNodeControl.AddCnnection(connection); - EndConnection(); // 环境触发了创建节点连接事件 - - } - #endregion - #region 移除连接 - else if (eventArgs.ChangeType == NodeConnectChangeEventArgs.ConnectChangeType.Remove) // 移除连接 - { - // 需要移除连接 - var removeConnections = Connections.Where(c => - c.Start.MyNode.Guid.Equals(fromNodeGuid) - && c.End.MyNode.Guid.Equals(toNodeGuid) - && (c.Start.JunctionType.ToConnectyionType() == JunctionOfConnectionType.Invoke - || c.End.JunctionType.ToConnectyionType() == JunctionOfConnectionType.Invoke)) - .ToList(); - - - foreach (var connection in removeConnections) - { - Connections.Remove(connection); - fromNodeControl.RemoveConnection(connection); // 移除连接 - toNodeControl.RemoveConnection(connection); // 移除连接 - if (NodeControls.TryGetValue(connection.End.MyNode.Guid, out var control)) - { - JudgmentFlipFlopNode(control); // 连接关系变更时判断 - } - } - } - #endregion - #endregion - } - else - { - ConnectionArgSourceType connectionArgSourceType = eventArgs.ConnectionArgSourceType; - #region 创建/删除节点之间的参数传递关系 - #region 创建连接 - if (eventArgs.ChangeType == NodeConnectChangeEventArgs.ConnectChangeType.Create) // 添加连接 - { - if (fromNodeControl is not INodeJunction IFormJunction || toNodeControl is not INodeJunction IToJunction) - { - SereinEnv.WriteLine(InfoType.INFO, "非预期的情况"); - return; - } - - JunctionControlBase startJunction = eventArgs.ConnectionArgSourceType switch - { - ConnectionArgSourceType.GetPreviousNodeData => IFormJunction.ReturnDataJunction, // 自身节点 - ConnectionArgSourceType.GetOtherNodeData => IFormJunction.ReturnDataJunction, // 其它节点的返回值控制点 - ConnectionArgSourceType.GetOtherNodeDataOfInvoke => IFormJunction.ReturnDataJunction, // 其它节点的返回值控制点 - _ => throw new Exception("窗体事件 FlowEnvironment_NodeConnectChangeEvemt 创建/删除节点之间的参数传递关系 JunctionControlBase 枚举值错误 。非预期的枚举值。") // 应该不会触发 - }; - - if(IToJunction.ArgDataJunction.Length <= eventArgs.ArgIndex) - { - _ = Task.Run(async () => - { - await Task.Delay(500); - FlowEnvironment_NodeConnectChangeEvemt(eventArgs); - }); - return; - } - JunctionControlBase endJunction = IToJunction.ArgDataJunction[eventArgs.ArgIndex]; - LineType lineType = LineType.Bezier; - // 添加连接 - var connection = new ConnectionControl( - lineType, - FlowChartCanvas, - eventArgs.ArgIndex, - eventArgs.ConnectionArgSourceType, - startJunction, - endJunction, - IToJunction - ); - Connections.Add(connection); - fromNodeControl.AddCnnection(connection); - toNodeControl.AddCnnection(connection); - EndConnection(); // 环境触发了创建节点连接事件 - - - } - #endregion - #region 移除连接 - else if (eventArgs.ChangeType == NodeConnectChangeEventArgs.ConnectChangeType.Remove) // 移除连接 - { - // 需要移除连接 - var removeConnections = Connections.Where(c => c.Start.MyNode.Guid.Equals(fromNodeGuid) - && c.End.MyNode.Guid.Equals(toNodeGuid)) - .ToList(); // 获取这两个节点之间的所有连接关系 - - - - foreach (var connection in removeConnections) - { - if (connection.End is ArgJunctionControl junctionControl && junctionControl.ArgIndex == eventArgs.ArgIndex) - { - // 找到符合删除条件的连接线 - Connections.Remove(connection); // 从本地记录中移除 - fromNodeControl.RemoveConnection(connection); // 从节点持有的记录移除 - toNodeControl.RemoveConnection(connection); // 从节点持有的记录移除 - } - - - //if (NodeControls.TryGetValue(connection.End.MyNode.Guid, out var control)) - //{ - // JudgmentFlipFlopNode(control); // 连接关系变更时判断 - //} - } - } - #endregion - #endregion - } - } - - /// - /// 节点移除事件 - /// - /// - private void FlowEnvironment_NodeRemoveEvent(NodeRemoveEventArgs eventArgs) - { - var nodeGuid = eventArgs.NodeGuid; - if (!TryGetControl(nodeGuid, out var nodeControl)) - { - return; - } - - if (nodeControl is null) return; - if (selectNodeControls.Count > 0) - { - if (selectNodeControls.Contains(nodeControl)) - { - selectNodeControls.Remove(nodeControl); - } - } - - if (nodeControl is FlipflopNodeControl flipflopControl) // 判断是否为触发器 - { - var node = flipflopControl?.ViewModel?.NodeModel; - if (node is not null) - { - NodeTreeViewer.RemoveGlobalFlipFlop(node); // 从全局触发器树树视图中移除 - } - } - - - - FlowChartCanvas.Children.Remove(nodeControl); - nodeControl.RemoveAllConection(); - NodeControls.Remove(nodeControl.ViewModel.NodeModel.Guid); - } - - /// - /// 添加节点事件 - /// - /// 添加节点事件参数 - /// - private void FlowEnvironment_NodeCreateEvent(NodeCreateEventArgs eventArgs) - { - var nodeModel = eventArgs.NodeModel; - if (NodeControls.ContainsKey(nodeModel.Guid)) - { - SereinEnv.WriteLine(InfoType.WARN, $"OnNodeCreateEvent 事件接收到意外的返回值:节点Guid重复 - {nodeModel.Guid}"); - return; - } - - PositionOfUI position = eventArgs.Position; - - if(!NodeMVVMManagement.TryGetType(nodeModel.ControlType, out var nodeMVVM)) - { - SereinEnv.WriteLine(InfoType.INFO, $"无法创建{nodeModel.ControlType}节点,节点类型尚未注册。"); - return; - } - if(nodeMVVM.ControlType == null - || nodeMVVM.ViewModelType == null) - { - SereinEnv.WriteLine(InfoType.INFO, $"无法创建{nodeModel.ControlType}节点,UI类型尚未注册(请通过 NodeMVVMManagement.RegisterUI() 方法进行注册)。"); - return; - } - - var nodeCanvas = FlowChartCanvas; - NodeControlBase nodeControl; - try - { - nodeControl = CreateNodeControl(nodeMVVM.ControlType, // 控件UI类型 - nodeMVVM.ViewModelType, // 控件VIewModel类型 - nodeModel, // 控件数据实体 - nodeCanvas); // 所在画布 - } - catch (Exception ex) - { - SereinEnv.WriteLine(ex); - return; - } - - NodeControls.TryAdd(nodeModel.Guid, nodeControl); // 添加到 - if (TryPlaceNodeInRegion(nodeControl, position, out var regionControl)) // 判断添加到区域容器 - { - // 通知运行环境调用加载节点子项的方法 - _ = EnvDecorator.PlaceNodeToContainerAsync(nodeControl.ViewModel.NodeModel.Guid, // 待移动的节点 - regionControl.ViewModel.NodeModel.Guid); // 目标的容器节点 - } - else - { - // 并非添加在容器中,直接放置节点 - PlaceNodeOnCanvas(nodeControl, position.X, position.Y); - } - - - #region 节点树视图 - if (nodeModel.ControlType == NodeControlType.Flipflop) - { - var node = nodeControl?.ViewModel?.NodeModel; - if (node is not null) - { - NodeTreeViewer.AddGlobalFlipFlop(EnvDecorator, node); // 新增的触发器节点添加到全局触发器 - } - } - - GC.Collect(); - #endregion - - } - - /// - /// 放置一个节点 - /// - /// - /// - private void EnvDecorator_OnNodePlaceEvent(NodePlaceEventArgs eventArgs) - { - string nodeGuid = eventArgs.NodeGuid; - string containerNodeGuid = eventArgs.ContainerNodeGuid; - if (!TryGetControl(nodeGuid, out var nodeControl) - || !TryGetControl(containerNodeGuid, out var containerNodeControl)) - { - return; - } - if(containerNodeControl is not INodeContainerControl containerControl) - { - SereinEnv.WriteLine(InfoType.WARN, - $"节点[{nodeGuid}]无法放置于节点[{containerNodeGuid}]," + - $"因为后者并不实现 INodeContainerControl 接口"); - return; - } - nodeControl.PlaceToContainer(containerControl); // 放置在容器节点中 - } - - /// - /// 取出一个节点 - /// - /// - private void EnvDecorator_OnNodeTakeOutEvent(NodeTakeOutEventArgs eventArgs) - { - string nodeGuid = eventArgs.NodeGuid; - if (!TryGetControl(nodeGuid, out var nodeControl)) - { - return; - } - nodeControl.TakeOutContainer(); // 从容器节点中取出 - - } - - - - /// - /// 设置了流程起始控件 - /// - /// - /// - private void FlowEnvironment_StartNodeChangeEvent(StartNodeChangeEventArgs eventArgs) - { - string oldNodeGuid = eventArgs.OldNodeGuid; - string newNodeGuid = eventArgs.NewNodeGuid; - if (!TryGetControl(newNodeGuid, out var newStartNodeControl)) return; - if (!string.IsNullOrEmpty(oldNodeGuid)) - { - if (!TryGetControl(oldNodeGuid, out var oldStartNodeControl)) return; - oldStartNodeControl.BorderBrush = Brushes.Black; - oldStartNodeControl.BorderThickness = new Thickness(0); - } - - newStartNodeControl.BorderBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#04FC10")); - newStartNodeControl.BorderThickness = new Thickness(2); - var node = newStartNodeControl?.ViewModel?.NodeModel; - if (node is not null) - { - NodeTreeViewer.LoadNodeTreeOfStartNode(EnvDecorator, node); - } - - } - - /// - /// 被监视的对象发生改变 - /// - /// - private void FlowEnvironment_OnMonitorObjectChangeEvent(MonitorObjectEventArgs eventArgs) - { - string nodeGuid = eventArgs.NodeGuid; - - string monitorKey = MonitorObjectEventArgs.ObjSourceType.NodeFlowData switch - { - MonitorObjectEventArgs.ObjSourceType.NodeFlowData => nodeGuid, - _ => eventArgs.NewData.GetType().FullName, - }; - - //NodeControlBase nodeControl = GuidToControl(nodeGuid); - if (ViewObjectViewer.MonitorObj is null) // 如果没有加载过对象 - { - ViewObjectViewer.LoadObjectInformation(monitorKey, eventArgs.NewData); // 加载对象 ViewObjectViewerControl.MonitorType.Obj - } - else - { - if (monitorKey.Equals(ViewObjectViewer.MonitorKey)) // 相同对象 - { - ViewObjectViewer.RefreshObjectTree(eventArgs.NewData); // 刷新 - } - else - { - ViewObjectViewer.LoadObjectInformation(monitorKey, eventArgs.NewData); // 加载对象 - } - } - - } - - /// - /// 节点中断状态改变。 - /// - /// - private void FlowEnvironment_OnNodeInterruptStateChangeEvent(NodeInterruptStateChangeEventArgs eventArgs) - { - string nodeGuid = eventArgs.NodeGuid; - if (!TryGetControl(nodeGuid, out var nodeControl)) return; - - //if (eventArgs.Class == InterruptClass.None) - //{ - // nodeControl.ViewModel.IsInterrupt = false; - //} - //else - //{ - // nodeControl.ViewModel.IsInterrupt = true; - //} - if(nodeControl.ContextMenu == null) - { - return; - } - 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 = "取消中断"; - } - - } - } - - } - - /// - /// 节点触发了中断 - /// - /// - /// - private void FlowEnvironment_OnInterruptTriggerEvent(InterruptTriggerEventArgs eventArgs) - { - string nodeGuid = eventArgs.NodeGuid; - if (!TryGetControl(nodeGuid, out var nodeControl)) return; - if(eventArgs.Type == InterruptTriggerEventArgs.InterruptTriggerType.Exp) - { - SereinEnv.WriteLine(InfoType.INFO, $"表达式触发了中断:{eventArgs.Expression}"); - } - else - { - SereinEnv.WriteLine(InfoType.INFO, $"节点触发了中断:{nodeGuid}"); - } - } - - /// - /// IOC变更 - /// - /// - /// - private void FlowEnvironment_OnIOCMembersChangedEvent(IOCMembersChangedEventArgs eventArgs) - { - IOCObjectViewer.AddDependenciesInstance(eventArgs.Key, eventArgs.Instance); - - } - - /// - /// 节点需要定位 - /// - /// - /// - private void FlowEnvironment_OnNodeLocateEvent(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)); - - // 获取控件在画布上的中心点 - 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); - - } - - /// - /// 控件抖动 - /// 来源:https://www.cnblogs.com/RedSky/p/17705411.html - /// 作者:HotSky - /// (……太好用了) - /// - /// - /// 需要抖动的控件 - /// 抖动第一下偏移量 - /// 减弱幅度(小于等于power,大于0) - /// 持续系数(大于0),越大时间越长, - private static void ElasticAnimation(NodeControlBase nodeControl, TranslateTransform translate, int power, int range = 1, double speed = 1) - { - DoubleAnimationUsingKeyFrames animation1 = new DoubleAnimationUsingKeyFrames(); - for (int i = power, j = 1; i >= 0; i -= range) - { - animation1.KeyFrames.Add(new LinearDoubleKeyFrame(-i, TimeSpan.FromMilliseconds(j++ * 100 * speed))); - animation1.KeyFrames.Add(new LinearDoubleKeyFrame(i, TimeSpan.FromMilliseconds(j++ * 100 * speed))); - } - translate.BeginAnimation(TranslateTransform.YProperty, animation1); - DoubleAnimationUsingKeyFrames animation2 = new DoubleAnimationUsingKeyFrames(); - for (int i = power, j = 1; i >= 0; i -= range) - { - animation2.KeyFrames.Add(new LinearDoubleKeyFrame(-i, TimeSpan.FromMilliseconds(j++ * 100 * speed))); - animation2.KeyFrames.Add(new LinearDoubleKeyFrame(i, TimeSpan.FromMilliseconds(j++ * 100 * speed))); - } - translate.BeginAnimation(TranslateTransform.XProperty, animation2); - - animation2.Completed += (s, e) => - { - nodeControl.RenderTransform = null; // 或者重新设置为默认值 - }; - } - - /// - /// 节点移动 - /// - /// - private void FlowEnvironment_OnNodeMovedEvent(NodeMovedEventArgs eventArgs) - { - if (!TryGetControl(eventArgs.NodeGuid, out var nodeControl)) return; - nodeControl.UpdateLocationConnections(); - - //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); - //} - - - } - - /// - /// Guid 转 NodeControl - /// - /// - /// - /// - private bool TryGetControl(string nodeGuid,out NodeControlBase nodeControl) - { - if (string.IsNullOrEmpty(nodeGuid)) - { - nodeControl = null; - return false; - } - if (!NodeControls.TryGetValue(nodeGuid, out nodeControl)) - { - nodeControl = null; - return false; - } - if(nodeControl is null) - { - return false; - } - return true; - } - - #endregion - - - #region 节点控件的创建 - - - /// - /// 创建了节点,添加到画布。配置默认事件 - /// - /// - /// - /// - private void PlaceNodeOnCanvas(NodeControlBase nodeControl, double x, double y) - { - // 添加控件到画布 - FlowChartCanvas.Children.Add(nodeControl); - Canvas.SetLeft(nodeControl, x); - Canvas.SetTop(nodeControl, y); - - ConfigureContextMenu(nodeControl); // 配置节点右键菜单 - ConfigureNodeEvents(nodeControl); // 配置节点事件 - } - - /// - /// 配置节点事件(移动,点击相关) - /// - /// - private void ConfigureNodeEvents(NodeControlBase nodeControl) - { - nodeControl.MouseLeftButtonDown += Block_MouseLeftButtonDown; - nodeControl.MouseMove += Block_MouseMove; - nodeControl.MouseLeftButtonUp += Block_MouseLeftButtonUp; - } - - - #endregion - - #region 配置右键菜单 - - /// - /// 配置节点右键菜单 - /// - /// - /// 任何情景下都尽量避免直接修改 ViewModel 中的 NodeModel 节点实体相关数据。 - /// 而是应该调用 FlowEnvironment 提供接口进行操作。 - /// 因为 Workbench 应该更加关注UI视觉效果,而非直接干扰流程环境运行的逻辑。 - /// 之所以暴露 NodeModel 属性,因为有些场景下不可避免的需要直接获取节点的属性。 - /// - private void ConfigureContextMenu(NodeControlBase nodeControl) - { - - var contextMenu = new ContextMenu(); - var nodeGuid = nodeControl.ViewModel?.NodeModel?.Guid; - #region 触发器节点 - - if(nodeControl.ViewModel?.NodeModel.ControlType == NodeControlType.Flipflop) - { - contextMenu.Items.Add(CreateMenuItem("启动触发器", (s, e) => - { - if (s is MenuItem menuItem) - { - if (menuItem.Header.ToString() == "启动触发器") - { - EnvDecorator.ActivateFlipflopNode(nodeGuid); - - menuItem.Header = "终结触发器"; - } - else - { - EnvDecorator.TerminateFlipflopNode(nodeGuid); - menuItem.Header = "启动触发器"; - - } - } - })); - } - - #endregion - - if (nodeControl.ViewModel?.NodeModel?.MethodDetails?.ReturnType is Type returnType && returnType != typeof(void)) - { - contextMenu.Items.Add(CreateMenuItem("查看返回类型", (s, e) => - { - DisplayReturnTypeTreeViewer(returnType); - })); - } - - - - contextMenu.Items.Add(CreateMenuItem("设为起点", (s, e) => EnvDecorator.SetStartNodeAsync(nodeGuid))); - contextMenu.Items.Add(CreateMenuItem("删除", async (s, e) => - { - var result = await EnvDecorator.RemoveNodeAsync(nodeGuid); - })); - - #region 右键菜单功能 - 控件对齐 - - var AvoidMenu = new MenuItem(); - AvoidMenu.Items.Add(CreateMenuItem("群组对齐", (s, e) => - { - AlignControlsWithGrouping(selectNodeControls, AlignMode.Grouping); - })); - AvoidMenu.Items.Add(CreateMenuItem("规划对齐", (s, e) => - { - AlignControlsWithGrouping(selectNodeControls, AlignMode.Planning); - })); - AvoidMenu.Items.Add(CreateMenuItem("水平中心对齐", (s, e) => - { - AlignControlsWithGrouping(selectNodeControls, AlignMode.HorizontalCenter); - })); - AvoidMenu.Items.Add(CreateMenuItem("垂直中心对齐 ", (s, e) => - { - AlignControlsWithGrouping(selectNodeControls, AlignMode.VerticalCenter); - })); - - AvoidMenu.Items.Add(CreateMenuItem("垂直对齐时水平斜分布", (s, e) => - { - AlignControlsWithGrouping(selectNodeControls, AlignMode.Vertical); - })); - AvoidMenu.Items.Add(CreateMenuItem("水平对齐时垂直斜分布", (s, e) => - { - AlignControlsWithGrouping(selectNodeControls, AlignMode.Horizontal); - })); - - AvoidMenu.Header = "对齐"; - contextMenu.Items.Add(AvoidMenu); - - - #endregion - - nodeControl.ContextMenu = contextMenu; - } - - /// - /// 查看返回类型(树形结构展开类型的成员) - /// - /// - private void DisplayReturnTypeTreeViewer(Type type) - { - try - { - var typeViewerWindow = new TypeViewerWindow - { - Type = type, - }; - typeViewerWindow.LoadTypeInformation(); - typeViewerWindow.Show(); - } - catch (Exception ex) - { - SereinEnv.WriteLine(InfoType.ERROR, ex.ToString()); - } - } - #endregion - - #region 拖拽DLL文件到左侧功能区,加载相关节点清单 - /// - /// 当拖动文件到窗口时触发,加载DLL文件 - /// - /// - /// - private void Window_Drop(object sender, DragEventArgs e) - { - if (e.Data.GetDataPresent(DataFormats.FileDrop)) - { - string[] files = (string[])e.Data.GetData(DataFormats.FileDrop); - foreach (string file in files) - { - if (file.EndsWith(".dll")) - { - try - { - EnvDecorator.LoadLibrary(file); - } - catch (Exception ex) - { - SereinEnv.WriteLine(ex); - return; - } - } - } - } - } - - /// - /// 当拖动文件经过窗口时触发,设置拖放效果为复制 - /// - /// - /// - private void Window_DragOver(object sender, DragEventArgs e) - { - e.Effects = DragDropEffects.Copy; - e.Handled = true; - } - - #endregion - - #region 与流程图/节点相关 - - /// - /// 鼠标在画布移动。 - /// 选择控件状态下,调整选择框大小 - /// 连接状态下,实时更新连接线的终点位置。 - /// 移动画布状态下,移动画布。 - /// - private void FlowChartCanvas_MouseMove(object sender, MouseEventArgs e) - { - var myData = GlobalJunctionData.MyGlobalConnectingData; - if (myData.IsCreateing && e.LeftButton == MouseButtonState.Pressed) - { - - if (myData.Type == JunctionOfConnectionType.Invoke) - { - ViewModel.IsConnectionInvokeNode = true; // 正在连接节点的调用关系 - - } - else - { - ViewModel.IsConnectionArgSourceNode = true; // 正在连接节点的调用关系 - } - var currentPoint = e.GetPosition(FlowChartCanvas); - currentPoint.X -= 2; - currentPoint.Y -= 2; - myData.UpdatePoint(currentPoint); - return; - } - - - - if (IsCanvasDragging && e.MiddleButton == MouseButtonState.Pressed) // 正在移动画布(按住中键) - { - Point currentMousePosition = e.GetPosition(this); - double deltaX = currentMousePosition.X - startCanvasDragPoint.X; - double deltaY = currentMousePosition.Y - startCanvasDragPoint.Y; - - translateTransform.X += deltaX; - translateTransform.Y += deltaY; - - startCanvasDragPoint = currentMousePosition; - - foreach (var line in Connections) - { - line.RefreshLine(); // 画布移动时刷新所有连接线 - } - } - - if (IsSelectControl) // 正在选取节点 - { - IsSelectDragging = 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); - - Canvas.SetLeft(SelectionRectangle, x); - Canvas.SetTop(SelectionRectangle, y); - SelectionRectangle.Width = width; - SelectionRectangle.Height = height; - - } - } - - /// - /// 基础节点的拖拽放置创建 - /// - /// - /// - private void BaseNodeControl_PreviewMouseMove(object sender, MouseEventArgs e) - { - if (sender is UserControl control) - { - if(e.LeftButton == MouseButtonState.Pressed) - { - // 创建一个 DataObject 用于拖拽操作,并设置拖拽效果 - var dragData = new DataObject(MouseNodeType.CreateBaseNodeInCanvas, control.GetType()); - DragDrop.DoDragDrop(control, dragData, DragDropEffects.Move); - } - - } - } - - /// - /// 放置操作,根据拖放数据创建相应的控件,并处理相关操作 - /// - /// - /// - private void FlowChartCanvas_Drop(object sender, DragEventArgs e) - { - try - { - var canvasDropPosition = e.GetPosition(FlowChartCanvas); // 更新画布落点 - PositionOfUI position = new PositionOfUI(canvasDropPosition.X, canvasDropPosition.Y); - if (e.Data.GetDataPresent(MouseNodeType.CreateDllNodeInCanvas)) - { - if (e.Data.GetData(MouseNodeType.CreateDllNodeInCanvas) is MoveNodeData nodeData) - { - Task.Run(async () => - { - await EnvDecorator.CreateNodeAsync(nodeData.NodeControlType, position, nodeData.MethodDetailsInfo); // 创建DLL文件的节点对象 - }); - } - } - else if (e.Data.GetDataPresent(MouseNodeType.CreateBaseNodeInCanvas)) - { - if (e.Data.GetData(MouseNodeType.CreateBaseNodeInCanvas) is Type droppedType) - { - 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, - Type when typeof(GlobalDataControl).IsAssignableFrom(droppedType) => NodeControlType.GlobalData, - Type when typeof(ScriptNodeControl).IsAssignableFrom(droppedType) => NodeControlType.Script, - _ => NodeControlType.None, - }; - if (nodeControlType != NodeControlType.None) - { - Task.Run(async () => - { - await EnvDecorator.CreateNodeAsync(nodeControlType, position); // 创建基础节点对象 - }); - } - } - } - e.Handled = true; - } - catch (Exception ex) - { - SereinEnv.WriteLine(InfoType.ERROR, ex.ToString()); - } - } - - /// - /// 尝试判断是否为区域,如果是,将节点放置在区域中 - /// - /// - /// - /// 目标节点控件 - /// - private bool TryPlaceNodeInRegion(NodeControlBase nodeControl, - PositionOfUI position, - out NodeControlBase targetNodeControl) - { - var point = new Point(position.X, position.Y); - HitTestResult hitTestResult = VisualTreeHelper.HitTest(FlowChartCanvas, point); - if (hitTestResult != null && hitTestResult.VisualHit is UIElement hitElement) - { - // 准备放置条件表达式控件 - if (nodeControl.ViewModel.NodeModel.ControlType == NodeControlType.ExpCondition) - { - ConditionRegionControl? conditionRegion = GetParentOfType(hitElement); - if (conditionRegion is not null) - { - targetNodeControl = conditionRegion; - //// 如果存在条件区域容器 - //conditionRegion.AddCondition(nodeControl); - return true; - } - } - - else - { - // 准备放置全局数据控件 - GlobalDataControl? globalDataControl = GetParentOfType(hitElement); - if (globalDataControl is not null) - { - targetNodeControl = globalDataControl; - return true; - } - } - } - targetNodeControl = null; - return false; - } - - ///// - ///// 将节点放在目标区域中 - ///// - ///// 区域容器 - ///// 节点控件 - //private void TryPlaceNodeInRegion(NodeControlBase regionControl, NodeControlBase nodeControl) - //{ - // // 准备放置条件表达式控件 - // if (nodeControl.ViewModel.NodeModel.ControlType == NodeControlType.ExpCondition) - // { - // if (regionControl is ConditionRegionControl conditionRegion) - // { - // conditionRegion.AddCondition(nodeControl); // 条件区域容器 - // } - // } - // else if(regionControl.ViewModel.NodeModel.ControlType == NodeControlType.GlobalData) - // { - // if (regionControl is GlobalDataControl globalDataControl) - // { - // // 全局数据节点容器 - // globalDataControl.SetDataNodeControl(nodeControl); - // } - // } - //} - - - - /// - /// 拖动效果,根据拖放数据是否为指定类型设置拖放效果 - /// - /// - /// - private void FlowChartCanvas_DragOver(object sender, DragEventArgs e) - { - if (e.Data.GetDataPresent(MouseNodeType.CreateDllNodeInCanvas) - || e.Data.GetDataPresent(MouseNodeType.CreateBaseNodeInCanvas)) - { - e.Effects = DragDropEffects.Move; - } - else - { - e.Effects = DragDropEffects.None; - } - e.Handled = true; - } - - /// - /// 控件的鼠标左键按下事件,启动拖动操作。同时显示当前正在传递的数据。 - /// - private void Block_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) - { - //if (GlobalJunctionData.IsCreatingConnection) - //{ - // return; - //} - if(sender is NodeControlBase nodeControl) - { - ChangeViewerObjOfNode(nodeControl); - if (nodeControl?.ViewModel?.NodeModel?.MethodDetails?.IsProtectionParameter == true) return; - IsControlDragging = true; - startControlDragPoint = e.GetPosition(FlowChartCanvas); // 记录鼠标按下时的位置 - ((UIElement)sender).CaptureMouse(); // 捕获鼠标 - e.Handled = true; // 防止事件传播影响其他控件 - } - } - - /// - /// 控件的鼠标移动事件,根据鼠标拖动更新控件的位置。批量移动计算移动逻辑。 - /// - private void Block_MouseMove(object sender, MouseEventArgs e) - { - if (IsCanvasDragging) - return; - if (IsSelectControl) - return; - - if (IsControlDragging) // 如果正在拖动控件 - { - Point currentPosition = e.GetPosition(FlowChartCanvas); // 获取当前鼠标位置 - - if (selectNodeControls.Count > 0 && sender is NodeControlBase nodeControlMain && selectNodeControls.Contains(nodeControlMain)) - { - // 进行批量移动 - // 获取旧位置 - var oldLeft = Canvas.GetLeft(nodeControlMain); - var oldTop = Canvas.GetTop(nodeControlMain); - - // 计算被选择控件的偏移量 - var deltaX = /*(int)*/(currentPosition.X - startControlDragPoint.X); - var deltaY = /*(int)*/(currentPosition.Y - startControlDragPoint.Y); - - // 移动被选择的控件 - var newLeft = oldLeft + deltaX; - var newTop = oldTop + deltaY; - - this.EnvDecorator.MoveNode(nodeControlMain.ViewModel.NodeModel.Guid, newLeft, newTop); // 移动节点 - - // 计算控件实际移动的距离 - var actualDeltaX = newLeft - oldLeft; - var actualDeltaY = newTop - oldTop; - - // 移动其它选中的控件 - foreach (var nodeControl in selectNodeControls) - { - if (nodeControl != nodeControlMain) // 跳过已经移动的控件 - { - var otherNewLeft = Canvas.GetLeft(nodeControl) + actualDeltaX; - var otherNewTop = Canvas.GetTop(nodeControl) + actualDeltaY; - this.EnvDecorator.MoveNode(nodeControl.ViewModel.NodeModel.Guid, otherNewLeft, otherNewTop); // 移动节点 - } - } - - // 更新节点之间线的连接位置 - foreach (var nodeControl in selectNodeControls) - { - nodeControl.UpdateLocationConnections(); - } - } - else - { // 单个节点移动 - if (sender is not NodeControlBase nodeControl) - { - return; - } - double deltaX = currentPosition.X - startControlDragPoint.X; // 计算X轴方向的偏移量 - double deltaY = currentPosition.Y - startControlDragPoint.Y; // 计算Y轴方向的偏移量 - double newLeft = Canvas.GetLeft(nodeControl) + deltaX; // 新的左边距 - double newTop = Canvas.GetTop(nodeControl) + deltaY; // 新的上边距 - this.EnvDecorator.MoveNode(nodeControl.ViewModel.NodeModel.Guid, newLeft, newTop); // 移动节点 - nodeControl.UpdateLocationConnections(); - } - startControlDragPoint = currentPosition; // 更新起始点位置 - } - - } - - - // 改变对象树? - private void ChangeViewerObjOfNode(NodeControlBase nodeControl) - { - var node = nodeControl.ViewModel.NodeModel; - //if (node is not null && (node.MethodDetails is null || node.MethodDetails.ReturnType != typeof(void)) - if (node is not null && node.MethodDetails?.ReturnType != typeof(void)) - { - var key = node.Guid; - object instance = null; - //Console.WriteLine("WindowXaml 后台代码中 ChangeViewerObjOfNode 需要重新设计"); - //var instance = node.GetFlowData(); // 对象预览树视图获取(后期更改) - if(instance is not null) - { - ViewObjectViewer.LoadObjectInformation(key, instance); - ChangeViewerObj(key, instance); - } - } - } - public void ChangeViewerObj(string key, object instance) - { - if (ViewObjectViewer.MonitorObj is null) - { - // EnvDecorator.SetMonitorObjState(key, true); // 通知环境,该节点的数据更新后需要传到UI - return; - } - if (instance is null) - { - return; - } - if (key.Equals(ViewObjectViewer.MonitorKey) == true) - { - ViewObjectViewer.RefreshObjectTree(instance); - return; - } - else - { - //EnvDecorator.SetMonitorObjState(ViewObjectViewer.MonitorKey,false); // 取消对旧节点的监视 - //EnvDecorator.SetMonitorObjState(key, true); // 通知环境,该节点的数据更新后需要传到UI - } - } - #endregion - - #region UI连接控件操作 - - /// - /// 控件的鼠标左键松开事件,结束拖动操作 - /// - private void Block_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) - { - if (IsControlDragging) - { - IsControlDragging = false; - ((UIElement)sender).ReleaseMouseCapture(); // 释放鼠标捕获 - - } - - //if (IsConnecting) - //{ - // var formNodeGuid = startConnectNodeControl?.ViewModel.NodeModel.Guid; - // var toNodeGuid = (sender as NodeControlBase)?.ViewModel.NodeModel.Guid; - // if (string.IsNullOrEmpty(formNodeGuid) || string.IsNullOrEmpty(toNodeGuid)) - // { - // return; - // } - // EnvDecorator.ConnectNodeAsync(formNodeGuid, toNodeGuid,0,0, currentConnectionType); - //} - //GlobalJunctionData.OK(); - } - - - /// - /// 结束连接操作,清理状态并移除虚线。 - /// - private void EndConnection() - { - Mouse.OverrideCursor = null; // 恢复视觉效果 - ViewModel.IsConnectionArgSourceNode = false; - ViewModel.IsConnectionInvokeNode = false; - GlobalJunctionData.OK(); - } - - #region 拖动画布实现缩放平移效果 - private void FlowChartCanvas_MouseDown(object sender, MouseButtonEventArgs e) - { - IsCanvasDragging = true; - startCanvasDragPoint = e.GetPosition(this); - FlowChartCanvas.CaptureMouse(); - e.Handled = true; // 防止事件传播影响其他控件 - } - - private void FlowChartCanvas_MouseUp(object sender, MouseButtonEventArgs e) - { - - - - if (IsCanvasDragging) - { - IsCanvasDragging = false; - FlowChartCanvas.ReleaseMouseCapture(); - } - } - - // 单纯缩放画布,不改变画布大小 - private void FlowChartCanvas_MouseWheel(object sender, MouseWheelEventArgs e) - { - // if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) - { - if (e.Delta < 0 && scaleTransform.ScaleX < 0.05) return; - if (e.Delta > 0 && scaleTransform.ScaleY > 2.0) return; - // 获取鼠标在 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)); - } - } - - // 设置画布宽度高度 - private void InitializeCanvas(double width, double height) - { - FlowChartCanvas.Width = width; - FlowChartCanvas.Height = height; - } - - - #region 动态调整区域大小 - //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); - - // FlowChartCanvas.Width = newWidth; - // FlowChartCanvas.Height = newHeight; - - // Canvas.SetLeft(FlowChartCanvas, Canvas.GetLeft(FlowChartCanvas) + e.HorizontalChange); - // Canvas.SetTop(FlowChartCanvas, Canvas.GetTop(FlowChartCanvas) + e.VerticalChange); - //} - - //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); - - // FlowChartCanvas.Width = newWidth; - // FlowChartCanvas.Height = newHeight; - - // Canvas.SetTop(FlowChartCanvas, Canvas.GetTop(FlowChartCanvas) + e.VerticalChange); - //} - - //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); - - // FlowChartCanvas.Width = newWidth; - // FlowChartCanvas.Height = newHeight; - - // Canvas.SetLeft(FlowChartCanvas, Canvas.GetLeft(FlowChartCanvas) + e.HorizontalChange); - //} - - private void Thumb_DragDelta_BottomRight(object sender, DragDeltaEventArgs e) - { - // 获取缩放后的水平和垂直变化 - double horizontalChange = e.HorizontalChange * scaleTransform.ScaleX; - double verticalChange = e.VerticalChange * scaleTransform.ScaleY; - - // 计算新的宽度和高度,确保不会小于400 - double newWidth = Math.Max(FlowChartCanvas.ActualWidth + horizontalChange, 400); - double newHeight = Math.Max(FlowChartCanvas.ActualHeight + verticalChange, 400); - - newHeight = newHeight < 400 ? 400 : newHeight; - newWidth = newWidth < 400 ? 400 : newWidth; - - InitializeCanvas(newWidth, newHeight); - - //// 从右下角调整大小 - //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; - - // double deltaX = x * scaleTransform.ScaleX; - // double deltaY = y * scaleTransform.ScaleY; - // Test(deltaX, deltaY); - //} - } - - //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); - //} - - private void Thumb_DragDelta_Right(object sender, DragDeltaEventArgs e) - { - //从右侧调整大小 - // 获取缩放后的水平变化 - double horizontalChange = e.HorizontalChange * scaleTransform.ScaleX; - - // 计算新的宽度,确保不会小于400 - double newWidth = Math.Max(FlowChartCanvas.ActualWidth + horizontalChange, 400); - - newWidth = newWidth < 400 ? 400 : newWidth; - InitializeCanvas(newWidth, FlowChartCanvas.Height); - - } - - //private void Thumb_DragDelta_Top(object sender, DragDeltaEventArgs e) - //{ - // // 从顶部调整大小 - // double newHeight = Math.Max(FlowChartCanvas.ActualHeight - e.VerticalChange, 0); - - // FlowChartCanvas.Height = newHeight; - // Canvas.SetTop(FlowChartCanvas, Canvas.GetTop(FlowChartCanvas) + e.VerticalChange); - //} - - private void Thumb_DragDelta_Bottom(object sender, DragDeltaEventArgs e) - { - // 获取缩放后的垂直变化 - double verticalChange = e.VerticalChange * scaleTransform.ScaleY; - // 计算新的高度,确保不会小于400 - double newHeight = Math.Max(FlowChartCanvas.ActualHeight + verticalChange, 400); - newHeight = newHeight < 400 ? 400 : newHeight; - InitializeCanvas(FlowChartCanvas.Width, newHeight); - } - - - private void Test(double deltaX, double deltaY) - { - //Console.WriteLine((translateTransform.X, translateTransform.Y)); - //translateTransform.X += deltaX; - //translateTransform.Y += deltaY; - } - - #endregion - #endregion - - - - #endregion - - #region 画布中框选节点控件动作 - - /// - /// 在画布中尝试选取控件 - /// - /// - /// - private void FlowChartCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) - { - if (GlobalJunctionData.MyGlobalConnectingData.IsCreateing) - { - return; - } - if (!IsSelectControl) - { - // 进入选取状态 - IsSelectControl = true; - IsSelectDragging = false; // 初始化为非拖动状态 - - // 记录鼠标起始点 - startSelectControolPoint = e.GetPosition(FlowChartCanvas); - - // 初始化选取矩形的位置和大小 - Canvas.SetLeft(SelectionRectangle, startSelectControolPoint.X); - Canvas.SetTop(SelectionRectangle, startSelectControolPoint.Y); - SelectionRectangle.Width = 0; - SelectionRectangle.Height = 0; - - // 显示选取矩形 - SelectionRectangle.Visibility = Visibility.Visible; - SelectionRectangle.ContextMenu ??= ConfiguerSelectionRectangle(); - - // 捕获鼠标,以便在鼠标移动到Canvas外部时仍能处理事件 - FlowChartCanvas.CaptureMouse(); - } - else - { - // 如果已经是选取状态,单击则认为结束框选 - CompleteSelection(); - } - - e.Handled = true; // 防止事件传播影响其他控件 - } - - /// - /// 在画布中释放鼠标按下,结束选取状态 / 停止创建连线,尝试连接节点 - /// - /// - /// - private void FlowChartCanvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) - { - if (IsSelectControl) - { - // 松开鼠标时判断是否为拖动操作 - if (IsSelectDragging) - { - // 完成拖动框选 - CompleteSelection(); - } - - // 释放鼠标捕获 - FlowChartCanvas.ReleaseMouseCapture(); - } - - // 创建连线 - if (GlobalJunctionData.MyGlobalConnectingData is ConnectingData myData && myData.IsCreateing) - { - - if (myData.IsCanConnected) - { - var canvas = this.FlowChartCanvas; - var currentendPoint = e.GetPosition(canvas); // 当前鼠标落点 - var changingJunctionPosition = myData.CurrentJunction.TranslatePoint(new Point(0, 0), canvas); - var changingJunctionRect = new Rect(changingJunctionPosition, new Size(myData.CurrentJunction.Width, myData.CurrentJunction.Height)); - - if (changingJunctionRect.Contains(currentendPoint)) // 可以创建连接 - { - #region 方法调用关系创建 - if (myData.Type == JunctionOfConnectionType.Invoke) - { - this.EnvDecorator.ConnectInvokeNodeAsync(myData.StartJunction.MyNode.Guid, myData.CurrentJunction.MyNode.Guid, - myData.StartJunction.JunctionType, - myData.CurrentJunction.JunctionType, - myData.ConnectionInvokeType); - } - #endregion - - #region 参数来源关系创建 - else if (myData.Type == JunctionOfConnectionType.Arg) - { - var argIndex = 0; - if (myData.StartJunction is ArgJunctionControl argJunction1) - { - argIndex = argJunction1.ArgIndex; - } - else if (myData.CurrentJunction is ArgJunctionControl argJunction2) - { - argIndex = argJunction2.ArgIndex; - } - - this.EnvDecorator.ConnectArgSourceNodeAsync(myData.StartJunction.MyNode.Guid, myData.CurrentJunction.MyNode.Guid, - myData.StartJunction.JunctionType, - myData.CurrentJunction.JunctionType, - myData.ConnectionArgSourceType, - argIndex); - } - #endregion - } - EndConnection(); - } - - } - e.Handled = true; - - } - - /// 完成选取操作 - /// - private void CompleteSelection() - { - IsSelectControl = false; - - // 隐藏选取矩形 - SelectionRectangle.Visibility = Visibility.Collapsed; - - // 获取选取范围 - Rect selectionArea = new Rect(Canvas.GetLeft(SelectionRectangle), - Canvas.GetTop(SelectionRectangle), - SelectionRectangle.Width, - SelectionRectangle.Height); - - // 处理选取范围内的控件 - // selectNodeControls.Clear(); - 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) - { - if (!selectNodeControls.Contains(control)) - { - selectNodeControls.Add(control); - } - } - } - } - - // 选中后的操作 - SelectedNode(); - } - private ContextMenu ConfiguerSelectionRectangle() - { - var contextMenu = new ContextMenu(); - contextMenu.Items.Add(CreateMenuItem("删除", (s, e) => - { - if (selectNodeControls.Count > 0) - { - foreach (var node in selectNodeControls.ToArray()) - { - var guid = node?.ViewModel?.NodeModel?.Guid; - if (!string.IsNullOrEmpty(guid)) - { - EnvDecorator.RemoveNodeAsync(guid); - } - } - } - SelectionRectangle.Visibility = Visibility.Collapsed; - })); - return contextMenu; - // nodeControl.ContextMenu = contextMenu; - } - private void SelectedNode() - { - - if (selectNodeControls.Count == 0) - { - //Console.WriteLine($"没有选择控件"); - SelectionRectangle.Visibility = Visibility.Collapsed; - return; - } - if(selectNodeControls.Count == 1) - { - // ChangeViewerObjOfNode(selectNodeControls[0]); - } - - //Console.WriteLine($"一共选取了{selectNodeControls.Count}个控件"); - foreach (var node in selectNodeControls) - { - //node.ViewModel.IsSelect =true; - // node.ViewModel.CancelSelect(); - node.BorderBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#FFC700")); - node.BorderThickness = new Thickness(4); - } - } - private void CancelSelectNode() - { - IsSelectControl = false; - foreach (var nodeControl in selectNodeControls) - { - //nodeControl.ViewModel.IsSelect = false; - nodeControl.BorderBrush = Brushes.Black; - nodeControl.BorderThickness = new Thickness(0); - if (nodeControl.ViewModel.NodeModel.IsStart) - { - nodeControl.BorderBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#04FC10")); - nodeControl.BorderThickness = new Thickness(2); - } - } - selectNodeControls.Clear(); - } - #endregion - - #region 节点对齐 (有些小瑕疵) - - //public void UpdateConnectedLines() - //{ - // //foreach (var nodeControl in selectNodeControls) - // //{ - // // UpdateConnections(nodeControl); - // //} - // this.Dispatcher.Invoke(() => - // { - // foreach (var line in Connections) - // { - // line.AddOrRefreshLine(); // 节点完成对齐 - // } - // }); - - //} - - - #region Plan A 群组对齐 - - public void AlignControlsWithGrouping(List selectNodeControls, double proximityThreshold = 50, double spacing = 10) - { - if (selectNodeControls is null || selectNodeControls.Count < 2) - return; - - // 按照控件的相对位置进行分组 - var horizontalGroups = GroupByProximity(selectNodeControls, proximityThreshold, isHorizontal: true); - var verticalGroups = GroupByProximity(selectNodeControls, proximityThreshold, isHorizontal: false); - - // 对每个水平群组进行垂直对齐 - foreach (var group in horizontalGroups) - { - double avgY = group.Average(c => Canvas.GetTop(c)); // 计算Y坐标平均值 - foreach (var control in group) - { - Canvas.SetTop(control, avgY); // 对齐Y坐标 - } - } - - // 对每个垂直群组进行水平对齐 - foreach (var group in verticalGroups) - { - double avgX = group.Average(c => Canvas.GetLeft(c)); // 计算X坐标平均值 - foreach (var control in group) - { - Canvas.SetLeft(control, avgX); // 对齐X坐标 - } - } - } - - // 基于控件间的距离来分组,按水平或垂直方向 - private List> GroupByProximity(List controls, double proximityThreshold, bool isHorizontal) - { - var groups = new List>(); - - foreach (var control in controls) - { - bool addedToGroup = false; - - // 尝试将控件加入现有的群组 - foreach (var group in groups) - { - if (IsInProximity(group, control, proximityThreshold, isHorizontal)) - { - group.Add(control); - addedToGroup = true; - break; - } - } - - // 如果没有加入任何群组,创建新群组 - if (!addedToGroup) - { - groups.Add(new List { control }); - } - } - - return groups; - } - - // 判断控件是否接近某个群组 - private bool IsInProximity(List group, NodeControlBase control, double proximityThreshold, bool isHorizontal) - { - foreach (var existingControl in group) - { - double distance = isHorizontal - ? Math.Abs(Canvas.GetTop(existingControl) - Canvas.GetTop(control)) // 垂直方向的距离 - : Math.Abs(Canvas.GetLeft(existingControl) - Canvas.GetLeft(control)); // 水平方向的距离 - - if (distance <= proximityThreshold) - { - return true; - } - } - return false; - } - - #endregion - - #region Plan B 规划对齐 - public void AlignControlsWithDynamicProgramming(List selectNodeControls, double spacing = 10) - { - if (selectNodeControls is null || selectNodeControls.Count < 2) - return; - - int n = selectNodeControls.Count; - double[] dp = new double[n]; - int[] split = new int[n]; - - // 初始化动态规划数组 - for (int i = 1; i < n; i++) - { - dp[i] = double.MaxValue; - for (int j = 0; j < i; j++) - { - double cost = CalculateAlignmentCost(selectNodeControls, j, i, spacing); - if (dp[j] + cost < dp[i]) - { - dp[i] = dp[j] + cost; - split[i] = j; - } - } - } - - // 回溯找到最优的对齐方式 - AlignWithSplit(selectNodeControls, split, n - 1, spacing); - } - - // 计算从控件[j]到控件[i]的对齐代价,并考虑控件的大小和间距 - private double CalculateAlignmentCost(List controls, int start, int end, double spacing) - { - double totalWidth = 0; - double totalHeight = 0; - - for (int i = start; i <= end; i++) - { - totalWidth += controls[i].ActualWidth; - totalHeight += controls[i].ActualHeight; - } - - // 水平和垂直方向代价计算,包括控件大小和间距 - double widthCost = totalWidth + (end - start) * spacing; - double heightCost = totalHeight + (end - start) * spacing; - - // 返回较小的代价,表示更优的对齐方式 - return Math.Min(widthCost, heightCost); - } - - // 根据split数组调整控件位置,确保控件不重叠 - private void AlignWithSplit(List controls, int[] split, int end, double spacing) - { - if (end <= 0) - return; - - AlignWithSplit(controls, split, split[end], spacing); - - // 从split[end]到end的控件进行对齐操作 - double currentX = Canvas.GetLeft(controls[split[end]]); - double currentY = Canvas.GetTop(controls[split[end]]); - - for (int i = split[end] + 1; i <= end; i++) - { - // 水平或垂直对齐,确保控件之间有间距 - if (currentX + controls[i].ActualWidth + spacing <= Canvas.GetLeft(controls[end])) - { - Canvas.SetLeft(controls[i], currentX + controls[i].ActualWidth + spacing); - currentX += controls[i].ActualWidth + spacing; - } - else - { - Canvas.SetTop(controls[i], currentY + controls[i].ActualHeight + spacing); - currentY += controls[i].ActualHeight + spacing; - } - } - } - - #endregion - - public enum AlignMode - { - /// - /// 水平对齐 - /// - Horizontal, - /// - /// 垂直对齐 - /// - Vertical, - /// - /// 水平中心对齐 - /// - HorizontalCenter, - /// - /// 垂直中心对齐 - /// - VerticalCenter, - - /// - /// 规划对齐 - /// - Planning, - /// - /// 群组对齐 - /// - Grouping, - } - - - public void AlignControlsWithGrouping(List selectNodeControls, AlignMode alignMode, double proximityThreshold = 50, double spacing = 10) - { - if (selectNodeControls is null || selectNodeControls.Count < 2) - return; - - switch (alignMode) - { - case AlignMode.Horizontal: - AlignHorizontally(selectNodeControls, spacing);// AlignToCenter - break; - - case AlignMode.Vertical: - - AlignVertically(selectNodeControls, spacing); - break; - - case AlignMode.HorizontalCenter: - AlignToCenter(selectNodeControls, isHorizontal: false, spacing); - break; - - case AlignMode.VerticalCenter: - AlignToCenter(selectNodeControls, isHorizontal: true, spacing); - break; - - case AlignMode.Planning: - AlignControlsWithDynamicProgramming(selectNodeControls, spacing); - break; - case AlignMode.Grouping: - AlignControlsWithGrouping(selectNodeControls, proximityThreshold, spacing); - break; - } - - - } - - // 垂直对齐并避免重叠 - private void AlignHorizontally(List controls, double spacing) - { - double avgY = controls.Average(c => Canvas.GetTop(c)); // 计算Y坐标平均值 - double currentY = avgY; - - foreach (var control in controls.OrderBy(c => Canvas.GetTop(c))) // 按Y坐标排序对齐 - { - Canvas.SetTop(control, currentY); - currentY += control.ActualHeight + spacing; // 保证控件之间有足够的垂直间距 - } - } - - // 水平对齐并避免重叠 - private void AlignVertically(List controls, double spacing) - { - double avgX = controls.Average(c => Canvas.GetLeft(c)); // 计算X坐标平均值 - double currentX = avgX; - - foreach (var control in controls.OrderBy(c => Canvas.GetLeft(c))) // 按X坐标排序对齐 - { - Canvas.SetLeft(control, currentX); - currentX += control.ActualWidth + spacing; // 保证控件之间有足够的水平间距 - } - } - - // 按中心点对齐 - private void AlignToCenter(List controls, bool isHorizontal, double spacing) - { - double avgCenter = isHorizontal - ? controls.Average(c => Canvas.GetLeft(c) + c.ActualWidth / 2) // 水平中心点 - : controls.Average(c => Canvas.GetTop(c) + c.ActualHeight / 2); // 垂直中心点 - - foreach (var control in controls) - { - if (isHorizontal) - { - double left = avgCenter - control.ActualWidth / 2; - Canvas.SetLeft(control, left); - } - else - { - double top = avgCenter - control.ActualHeight / 2; - Canvas.SetTop(control, top); - } - } - } - - #endregion - - #region 静态方法:创建节点,创建菜单子项,获取区域 - - /// - /// 创建节点控件 - /// - /// 节点控件视图控件类型 - /// 节点控件ViewModel类型 - /// 节点Model实例 - /// 节点所在画布 - /// - /// 无法创建节点控件 - private static NodeControlBase CreateNodeControl(Type controlType, Type viewModelType, NodeModelBase model, Canvas nodeCanvas) - { - if ((controlType is null) - || viewModelType is null - || model is null) - { - throw new Exception("无法创建节点控件"); - } - if (typeof(NodeControlBase).IsSubclassOf(controlType) || typeof(NodeControlViewModelBase).IsSubclassOf(viewModelType)) - { - throw new Exception("无法创建节点控件"); - } - - if (string.IsNullOrEmpty(model.Guid)) - { - model.Guid = Guid.NewGuid().ToString(); - } - - var viewModel = Activator.CreateInstance(viewModelType, [model]); - var controlObj = Activator.CreateInstance(controlType, [viewModel]); - if (controlObj is NodeControlBase nodeControl) - { - nodeControl.NodeCanvas = nodeCanvas; - return nodeControl; - } - else - { - throw new Exception("无法创建节点控件"); - } - } - - - /// - /// 创建菜单子项 - /// - /// - /// - /// - public static MenuItem CreateMenuItem(string header, RoutedEventHandler handler) - { - var menuItem = new MenuItem { Header = header }; - menuItem.Click += handler; - return menuItem; - } - - - - /// - /// 穿透元素获取区域容器 - /// - /// - /// - /// - public static T? GetParentOfType(DependencyObject element) where T : DependencyObject - { - while (element != null) - { - if (element is T e) - { - return e; - } - element = VisualTreeHelper.GetParent(element); - } - return null; - } - - #endregion - - #region 节点树、IOC视图管理 - - private void JudgmentFlipFlopNode(NodeControlBase nodeControl) - { - if (nodeControl is FlipflopNodeControl flipflopControl - && flipflopControl?.ViewModel?.NodeModel is NodeModelBase nodeModel) // 判断是否为触发器 - { - int count = 0; - foreach (var ct in NodeStaticConfig.ConnectionTypes) - { - count += nodeModel.PreviousNodes[ct].Count; - } - if (count == 0) - { - NodeTreeViewer.AddGlobalFlipFlop(EnvDecorator, nodeModel); // 添加到全局触发器树树视图 - } - else - { - NodeTreeViewer.RemoveGlobalFlipFlop(nodeModel); // 从全局触发器树树视图中移除 - } - } - } - void LoadIOCObjectViewer() - { - - } - #endregion - - - - #region 顶部菜单栏 - 调试功能区 - - /// - /// 运行测试 - /// - /// - /// - private async void ButtonDebugRun_Click(object sender, RoutedEventArgs e) - { - LogOutWindow?.Show(); - - - -#if WINDOWS - //Dispatcher uiDispatcher = Application.Current.MainWindow.Dispatcher; - //SynchronizationContext? uiContext = SynchronizationContext.Current; - //EnvDecorator.IOC.CustomRegisterInstance(typeof(SynchronizationContextk).FullName, uiContext, false); -#endif - - // 获取主线程的 SynchronizationContext - Action uiInvoke = (uiContext, action) => uiContext?.Post(state => action?.Invoke(), null); - - SereinEnv.WriteLine(InfoType.INFO, "流程开始运行"); - try - { - await EnvDecorator.StartFlowAsync(); - } - catch (Exception ex) - { - SereinEnv.WriteLine(ex); - return; - } - - // await EnvDecorator.StartAsync(); - //await Task.Factory.StartNew(FlowEnvironment.StartAsync); - } - - /// - /// 退出 - /// - /// - /// - private async void ButtonDebugFlipflopNode_Click(object sender, RoutedEventArgs e) - { - try - { - await EnvDecorator.ExitFlowAsync(); // 在运行平台上点击了退出 - } - catch (Exception ex) - { - SereinEnv.WriteLine(ex); - return; - } - } - - /// - /// 从选定的节点开始运行 - /// - /// - /// - private async void ButtonStartFlowInSelectNode_Click(object sender, RoutedEventArgs e) - { - if (selectNodeControls.Count == 0) - { - SereinEnv.WriteLine(InfoType.INFO, "请至少选择一个节点"); - } - else if (selectNodeControls.Count > 1) - { - SereinEnv.WriteLine(InfoType.INFO, "请只选择一个节点"); - } - try - { - await this.EnvDecorator.StartAsyncInSelectNode(selectNodeControls[0].ViewModel.NodeModel.Guid); - } - catch (Exception ex) - { - SereinEnv.WriteLine(ex); - return; - } - } - - - - - #endregion - - #region 顶部菜单栏 - 项目文件菜单 - - - /// - /// 保存为项目文件 - /// - /// - /// - private async void ButtonSaveFile_Click(object sender, RoutedEventArgs e) - { - try - { - EnvDecorator.SaveProject(); - } - catch (Exception ex) - { - SereinEnv.WriteLine(ex); - return; - } - } - - - /// - /// 打开本地项目文件 - /// - /// - /// - private void ButtonOpenLocalProject_Click(object sender, RoutedEventArgs e) - { - - } - - - -#endregion - - #region 顶部菜单栏 - 视图管理 - /// - /// 重置画布 - /// - /// - /// - private void ButtonResetCanvas_Click(object sender, RoutedEventArgs e) - { - translateTransform.X = 0; - translateTransform.Y = 0; - scaleTransform.ScaleX = 1; - scaleTransform.ScaleY = 1; - } - /// - /// 查看输出日志窗口 - /// - /// - /// - private void ButtonOpenConsoleOutWindow_Click(object sender, RoutedEventArgs e) - { - LogOutWindow?.Show(); - } - /// - /// 定位节点 - /// - /// - /// - private void ButtonLocationNode_Click(object sender, RoutedEventArgs e) - { - InputDialog inputDialog = new InputDialog(); - inputDialog.Closed += (s, e) => - { - var nodeGuid = inputDialog.InputValue; - EnvDecorator.NodeLocated(nodeGuid); - }; - inputDialog.ShowDialog(); - } - - #endregion - - #region 顶部菜单栏 - 远程管理 - private async void ButtonStartRemoteServer_Click(object sender, RoutedEventArgs e) - { - try - { - await this.EnvDecorator.StartRemoteServerAsync(); - } - catch (Exception ex) - { - SereinEnv.WriteLine(ex); - return; - } - } - - /// - /// 连接远程运行环境 - /// - /// - /// - private void ButtonConnectionRemoteEnv_Click(object sender, RoutedEventArgs e) - { - var windowEnvRemoteLoginView = new WindowEnvRemoteLoginView(async (addres, port, token) => - { - ResetFlowEnvironmentEvent();// 移除事件 - (var isConnect, var _) = await this.EnvDecorator.ConnectRemoteEnv(addres, port, token); - InitFlowEnvironmentEvent(); // 重新添加事件(如果没有连接成功,那么依然是原本的环境) - if (isConnect) - { - // 连接成功,加载远程项目 - _ = Task.Run(async () => - { - try - { - var flowEnvInfo = await EnvDecorator.GetEnvInfoAsync(); - EnvDecorator.LoadProject(flowEnvInfo, string.Empty);// 加载远程环境的项目 - } - catch (Exception ex) - { - SereinEnv.WriteLine(ex); - return; - } - }); - - } - }); - windowEnvRemoteLoginView.Show(); - - } - #endregion - - - - /// - /// 窗体按键监听。 - /// - /// - /// - private void Window_PreviewKeyDown(object sender, KeyEventArgs e) - { - if (e.Key == Key.Tab) - { - e.Handled = true; // 禁止默认的Tab键行为 - } - - #region 复制粘贴选择的节点 - if (Keyboard.Modifiers == ModifierKeys.Control) - { - if (e.Key == Key.C && selectNodeControls.Count > 0) - { - CpoyNodeInfo(); - } - else if (e.Key == Key.V) - { - PasteNodeInfo(); - } - } - #endregion - if (e.KeyStates == Keyboard.GetKeyStates(Key.Escape)) - { - IsControlDragging = false; - IsCanvasDragging = false; - SelectionRectangle.Visibility = Visibility.Collapsed; - CancelSelectNode(); - EndConnection(); - } - - if(GlobalJunctionData.MyGlobalConnectingData is ConnectingData myData && myData.IsCreateing) - { - if(myData.Type == JunctionOfConnectionType.Invoke) - { - ConnectionInvokeType connectionInvokeType = e.KeyStates switch - { - KeyStates k when k == Keyboard.GetKeyStates(Key.D1) => ConnectionInvokeType.Upstream, - KeyStates k when k == Keyboard.GetKeyStates(Key.D2) => ConnectionInvokeType.IsSucceed, - KeyStates k when k == Keyboard.GetKeyStates(Key.D3) => ConnectionInvokeType.IsFail, - KeyStates k when k == Keyboard.GetKeyStates(Key.D4) => ConnectionInvokeType.IsError, - _ => ConnectionInvokeType.None, - }; - - if (connectionInvokeType != ConnectionInvokeType.None) - { - myData.ConnectionInvokeType = connectionInvokeType; - myData.MyLine.Line.UpdateLineColor(connectionInvokeType.ToLineColor()); - } - } - else if (myData.Type == JunctionOfConnectionType.Arg) - { - ConnectionArgSourceType connectionArgSourceType = e.KeyStates switch - { - KeyStates k when k == Keyboard.GetKeyStates(Key.D1) => ConnectionArgSourceType.GetOtherNodeData, - KeyStates k when k == Keyboard.GetKeyStates(Key.D2) => ConnectionArgSourceType.GetOtherNodeDataOfInvoke, - _ => ConnectionArgSourceType.GetPreviousNodeData, - }; - - if (connectionArgSourceType != ConnectionArgSourceType.GetPreviousNodeData) - { - myData.ConnectionArgSourceType = connectionArgSourceType; - myData.MyLine.Line.UpdateLineColor(connectionArgSourceType.ToLineColor()); - } - } - myData.CurrentJunction.InvalidateVisual(); // 刷新目标节点控制点样式 - - } - - - } - - #region 复制节点,粘贴节点 - - /// - /// 复制节点 - /// - private void CpoyNodeInfo() - { - if(selectNodeControls.Count == 0) - { - return; - } - // 处理复制操作 - var dictSelection = selectNodeControls - .Select(control => control.ViewModel.NodeModel).ToList(); - - - // 遍历当前已选节点 - foreach (var node in dictSelection.ToArray()) - { - if(node.ChildrenNode.Count == 0) - { - continue; - } - // 遍历这些节点的子节点,添加过来 - foreach (var childNode in node.ChildrenNode) - { - dictSelection.Add(childNode); - } - } - - var nodeInfos = dictSelection.Select(item => item.ToInfo()); - - JObject json = new JObject() - { - ["nodes"] = JArray.FromObject(nodeInfos) - }; - - var jsonText = json.ToString(); - - - try - { - //Clipboard.SetDataObject(result, true); // 持久性设置 - Clipboard.SetDataObject(jsonText, true); // 持久性设置 - SereinEnv.WriteLine(InfoType.INFO, $"复制已选节点({dictSelection.Count}个)"); - } - catch (Exception ex) - { - SereinEnv.WriteLine(InfoType.ERROR, $"复制失败:{ex.Message}"); - } - } - - /// - /// 粘贴节点 - /// - private void PasteNodeInfo() - { - if (Clipboard.ContainsText()) - { - try - { - - string clipboardText = Clipboard.GetText(TextDataFormat.Text); - string jsonText = JObject.Parse(clipboardText)["nodes"].ToString(); - List nodes = JsonConvert.DeserializeObject>(jsonText); - if (nodes is null || nodes.Count < 0) - { - return; - } - - #region 节点去重 - Dictionary guids = new Dictionary(); // 记录 Guid - // 遍历当前已选节点 - foreach (var node in nodes.ToArray()) - { - if (NodeControls.ContainsKey(node.Guid) && !guids.ContainsKey(node.Guid)) - { - // 如果是没出现过、且在当前记录中重复的Guid,则记录并新增对应的映射。 - guids.TryAdd(node.Guid, Guid.NewGuid().ToString()); - } - else - { - // 出现过的Guid,说明重复添加了。应该不会走到这。 - continue; - } - - if (node.ChildNodeGuids is null) - { - continue; // 跳过没有子节点的节点 - } - - // 遍历这些节点的子节点,获得完整的已选节点信息 - foreach (var childNodeGuid in node.ChildNodeGuids) - { - if (NodeControls.ContainsKey(node.Guid) && !NodeControls.ContainsKey(node.Guid)) - { - // 当前Guid并不重复,跳过替换 - continue; - } - if (!guids.ContainsKey(childNodeGuid)) - { - // 如果是没出现过的Guid,则记录并新增对应的映射。 - guids.TryAdd(node.Guid, Guid.NewGuid().ToString()); - } - - if (!string.IsNullOrEmpty(childNodeGuid) - && NodeControls.TryGetValue(childNodeGuid, out var nodeControl)) - { - - var newNodeInfo = nodeControl.ViewModel.NodeModel.ToInfo(); - nodes.Add(newNodeInfo); - } - } - } - - //var flashText = new FlashText.NET.TextReplacer(); - - //var t = guids.Select(kvp => (kvp.Key, kvp.Value)).ToArray(); - //var result = flashText.ReplaceWords(jsonText, t); - - StringBuilder sb = new StringBuilder(jsonText); - foreach (var kv in guids) - { - sb.Replace(kv.Key, kv.Value); - } - string result = sb.ToString(); - - - /*var replacer = new GuidReplacer(); - foreach (var kv in guids) - { - replacer.AddReplacement(kv.Key, kv.Value); - } - string result = replacer.Replace(jsonText);*/ - - - //SereinEnv.WriteLine(InfoType.ERROR, result); - nodes = JsonConvert.DeserializeObject>(result); - - if (nodes is null || nodes.Count < 0) - { - return; - } - #endregion - - Point mousePosition = Mouse.GetPosition(FlowChartCanvas); - PositionOfUI positionOfUI = new PositionOfUI(mousePosition.X, mousePosition.Y); // 坐标数据 - - // 获取第一个节点的原始位置 - var index0NodeX = nodes[0].Position.X; - var index0NodeY = nodes[0].Position.Y; - - // 计算所有节点相对于第一个节点的偏移量 - foreach (var node in nodes) - { - - var offsetX = node.Position.X - index0NodeX; - var offsetY = node.Position.Y - index0NodeY; - - // 根据鼠标位置平移节点 - node.Position = new PositionOfUI(positionOfUI.X + offsetX, positionOfUI.Y + offsetY); - } - - _ = EnvDecorator.LoadNodeInfosAsync(nodes); - } - catch (Exception ex) - { - - //SereinEnv.WriteLine(InfoType.ERROR, $"粘贴节点时发生异常:{ex}"); - } - // SereinEnv.WriteLine(InfoType.INFO, $"剪贴板文本内容: {clipboardText}"); - } - else if (Clipboard.ContainsImage()) - { - // var image = Clipboard.GetImage(); - } - else - { - SereinEnv.WriteLine(InfoType.INFO, "剪贴板中没有可识别的数据。"); - } - } - - #endregion - - - - /* /// - /// 对象装箱测试 - /// - /// - /// - private void ButtonTestExpObj_Click(object sender, RoutedEventArgs e) - { - //string jsonString = - //""" - //{ - // "Name": "张三", - // "Age": 24, - // "Address": { - // "City": "北京", - // "PostalCode": "10000" - // } - //} - //"""; - - var externalData = new Dictionary - { - { "Name", "John" }, - { "Age", 30 }, - { "Addresses", new List> - { - new Dictionary - { - { "Street", "123 Main St" }, - { "City", "New York" } - }, - new Dictionary - { - { "Street", "456 Another St" }, - { "City", "Los Angeles" } - } - } - } - }; - - if (!ObjDynamicCreateHelper.TryResolve(externalData, "RootType",out var result)) - { - SereinEnv.WriteLine(InfoType.ERROR, "赋值过程中有错误,请检查属性名和类型!"); - return; - } - ObjDynamicCreateHelper.PrintObjectProperties(result!); - var exp = "@set .Addresses[1].Street = 233"; - var data = SerinExpressionEvaluator.Evaluate(exp, result!, out bool isChange); - exp = "@get .Addresses[1].Street"; - data = SerinExpressionEvaluator.Evaluate(exp,result!, out isChange); - SereinEnv.WriteLine(InfoType.INFO, $"{exp} => {data}"); - } -*/ - } -} \ No newline at end of file diff --git a/WorkBench/MainWindowViewModel.cs b/WorkBench/MainWindowViewModel.cs deleted file mode 100644 index 0aedffd..0000000 --- a/WorkBench/MainWindowViewModel.cs +++ /dev/null @@ -1,101 +0,0 @@ -using Serein.Library.Api; -using Serein.Library.Utils; -using Serein.NodeFlow.Env; -using System.ComponentModel; -using System.Windows; - -namespace Serein.Workbench -{ - /// - /// 工作台数据视图 - /// - /// - public class MainWindowViewModel: INotifyPropertyChanged - { - private readonly MainWindow window ; - - /// - /// 运行环境 - /// - public IFlowEnvironment FlowEnvironment { get; set; } - - /// - /// 工作台数据视图 - /// - /// - public MainWindowViewModel(MainWindow 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); - //_ = FlowEnvironment.StartRemoteServerAsync(); - this.window = window; - } - } - - - private bool _isConnectionInvokeNode = false; - /// - /// 是否正在连接节点的方法调用关系 - /// - public bool IsConnectionInvokeNode { get => _isConnectionInvokeNode; set - { - if (_isConnectionInvokeNode != value) - { - SetProperty(ref _isConnectionInvokeNode, value); - } - } - } - - private bool _isConnectionArgSouceNode = false; - /// - /// 是否正在连接节点的参数传递关系 - /// - public bool IsConnectionArgSourceNode { get => _isConnectionArgSouceNode; set - { - if (_isConnectionArgSouceNode != value) - { - SetProperty(ref _isConnectionArgSouceNode, value); - } - } - } - - - /// - /// 略 - /// 此事件为自动生成 - /// - public event PropertyChangedEventHandler? PropertyChanged; - /// - /// 通知属性变更 - /// - /// 类型 - /// 绑定的变量 - /// 新的数据 - /// - protected void SetProperty(ref T storage, T value, [System.Runtime.CompilerServices.CallerMemberName] string propertyName = null) - { - if (Equals(storage, value)) - { - return; - } - - storage = value; - PropertyChanged?.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName)); - } - } -} diff --git a/WorkBench/Node/NodeControlViewModelBase.cs b/WorkBench/Node/NodeControlViewModelBase.cs deleted file mode 100644 index ed58ff9..0000000 --- a/WorkBench/Node/NodeControlViewModelBase.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System.ComponentModel; -using Serein.Library; -using System.Runtime.CompilerServices; -using System.Windows.Controls; -using System.Windows.Data; -using System; - -namespace Serein.Workbench.Node.ViewModel -{ - public abstract class NodeControlViewModelBase - { - ///// - ///// 对应的节点实体类 - ///// - public NodeModelBase NodeModel { get; } - - public NodeControlViewModelBase(NodeModelBase nodeModel) - { - NodeModel = nodeModel; - - } - - - private bool isInterrupt; - ///// - ///// 控制中断状态的视觉效果 - ///// - public bool IsInterrupt - { - get => NodeModel.DebugSetting.IsInterrupt; - set - { - NodeModel.DebugSetting.IsInterrupt = value; - OnPropertyChanged(); - } - } - - - - public event PropertyChangedEventHandler? PropertyChanged; - protected void OnPropertyChanged([CallerMemberName] string propertyName = null) - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - } - - - } -} diff --git a/WorkBench/Node/View/ActionNodeControl.xaml b/WorkBench/Node/View/ActionNodeControl.xaml deleted file mode 100644 index fb71a3f..0000000 --- a/WorkBench/Node/View/ActionNodeControl.xaml +++ /dev/null @@ -1,118 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/WorkBench/Node/View/ActionNodeControl.xaml.cs b/WorkBench/Node/View/ActionNodeControl.xaml.cs deleted file mode 100644 index f26e7ba..0000000 --- a/WorkBench/Node/View/ActionNodeControl.xaml.cs +++ /dev/null @@ -1,83 +0,0 @@ -using Serein.NodeFlow.Model; -using Serein.Workbench.Node.ViewModel; -using System.Runtime.CompilerServices; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Media; - -namespace Serein.Workbench.Node.View -{ - /// - /// ActionNode.xaml 的交互逻辑 - /// - public partial class ActionNodeControl : NodeControlBase, INodeJunction - { - public ActionNodeControl(ActionNodeControlViewModel viewModel) : base(viewModel) - { - DataContext = viewModel; - InitializeComponent(); - if(ExecuteJunctionControl.MyNode != null) - { - - ExecuteJunctionControl.MyNode.Guid = viewModel.NodeModel.Guid; - } - } - - /// - /// 入参控制点(可能有,可能没) - /// - JunctionControlBase INodeJunction.ExecuteJunction => this.ExecuteJunctionControl; - - /// - /// 下一个调用方法控制点(可能有,可能没) - /// - JunctionControlBase INodeJunction.NextStepJunction => this.NextStepJunctionControl; - - /// - /// 返回值控制点(可能有,可能没) - /// - JunctionControlBase INodeJunction.ReturnDataJunction => this.ResultJunctionControl; - - /// - /// 方法入参控制点(可能有,可能没) - /// - JunctionControlBase[] INodeJunction.ArgDataJunction - { - get - { - // 获取 MethodDetailsControl 实例 - var methodDetailsControl = this.MethodDetailsControl; - var itemsControl = FindVisualChild(methodDetailsControl); // 查找 ItemsControl - if (itemsControl != null) - { - var argDataJunction = new JunctionControlBase[base.ViewModel.NodeModel.MethodDetails.ParameterDetailss.Length]; - var controls = new List(); - - for (int i = 0; i < itemsControl.Items.Count; i++) - { - var container = itemsControl.ItemContainerGenerator.ContainerFromIndex(i) as FrameworkElement; - if (container != null) - { - var argControl = FindVisualChild(container); - if (argControl != null) - { - controls.Add(argControl); // 收集 ArgJunctionControl 实例 - } - } - } - return argDataJunction = controls.ToArray(); - } - else - { - return []; - } - } - - - } - - - - - } -} diff --git a/WorkBench/Node/View/ConditionNodeControl.xaml b/WorkBench/Node/View/ConditionNodeControl.xaml deleted file mode 100644 index f6f8c07..0000000 --- a/WorkBench/Node/View/ConditionNodeControl.xaml +++ /dev/null @@ -1,110 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/WorkBench/Node/View/ConditionNodeControl.xaml.cs b/WorkBench/Node/View/ConditionNodeControl.xaml.cs deleted file mode 100644 index f1ce898..0000000 --- a/WorkBench/Node/View/ConditionNodeControl.xaml.cs +++ /dev/null @@ -1,58 +0,0 @@ -using Serein.NodeFlow.Model; -using Serein.Workbench.Node.ViewModel; - -namespace Serein.Workbench.Node.View -{ - /// - /// ConditionNode.xaml 的交互逻辑 - /// - public partial class ConditionNodeControl : NodeControlBase, INodeJunction - { - public ConditionNodeControl() : base() - { - // 窗体初始化需要 - base.ViewModel = new ConditionNodeControlViewModel (new SingleConditionNode(null)); - DataContext = ViewModel; - InitializeComponent(); - } - - public ConditionNodeControl(ConditionNodeControlViewModel viewModel):base(viewModel) - { - DataContext = viewModel; - InitializeComponent(); - } - - /// - /// 入参控制点(可能有,可能没) - /// - JunctionControlBase INodeJunction.ExecuteJunction => this.ExecuteJunctionControl; - - /// - /// 下一个调用方法控制点(可能有,可能没) - /// - JunctionControlBase INodeJunction.NextStepJunction => this.NextStepJunctionControl; - - /// - /// 返回值控制点(可能有,可能没) - /// - JunctionControlBase INodeJunction.ReturnDataJunction => this.ResultJunctionControl; - - /// - /// 方法入参控制点(可能有,可能没) - /// - private JunctionControlBase[] argDataJunction; - /// - /// 方法入参控制点(可能有,可能没) - /// - JunctionControlBase[] INodeJunction.ArgDataJunction - { - get - { - argDataJunction = new JunctionControlBase[1]; - argDataJunction[0] = this.ArgJunctionControl; - return argDataJunction; - } - } - - } -} diff --git a/WorkBench/Node/View/ConditionRegionControl.xaml b/WorkBench/Node/View/ConditionRegionControl.xaml deleted file mode 100644 index c7932cc..0000000 --- a/WorkBench/Node/View/ConditionRegionControl.xaml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - diff --git a/WorkBench/Themes/WindowDialogInput.xaml.cs b/WorkBench/Themes/WindowDialogInput.xaml.cs deleted file mode 100644 index f5f5441..0000000 --- a/WorkBench/Themes/WindowDialogInput.xaml.cs +++ /dev/null @@ -1,70 +0,0 @@ -using Serein.Library; -using Serein.Library.Utils; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net.Sockets; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -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.Shapes; - -namespace Serein.Workbench.Themes -{ - /// - /// WindowDialogInput.xaml 的交互逻辑 - /// - public partial class WindowEnvRemoteLoginView : Window - { - private Action ConnectRemoteFlowEnv; - - /// - /// 弹窗输入 - /// - /// - public WindowEnvRemoteLoginView(Action connectRemoteFlowEnv) - { - WindowStartupLocation = WindowStartupLocation.CenterScreen; - InitializeComponent(); - ConnectRemoteFlowEnv = connectRemoteFlowEnv; - } - - private void ButtonTestConnect_Client(object sender, RoutedEventArgs e) - { - var addres = this.TextBlockAddres.Text; - _ = int.TryParse(this.TextBlockPort.Text, out var port); - _ = Task.Run(() => { - bool success = false; - try - { - TcpClient tcpClient = new TcpClient(); - var result = tcpClient.BeginConnect(addres, port, null, null); - success = result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(3)); - } - catch - { - success = false; - } - if (!success) - { - SereinEnv.WriteLine(InfoType.ERROR, $"无法连接远程:{addres}:{port}"); - } - }); - - } - - private void ButtonTestLoginEnv_Client(object sender, RoutedEventArgs e) - { - var addres = this.TextBlockAddres.Text; - _ = int.TryParse(this.TextBlockPort.Text, out var port); - var token = this.TextBlockToken.Text; - ConnectRemoteFlowEnv?.Invoke(addres, port, token); - } - } -} diff --git a/WorkBench/Tool/Converters/InvertableBooleanToVisibilityConverter.cs b/WorkBench/Tool/Converters/InvertableBooleanToVisibilityConverter.cs deleted file mode 100644 index e830c6d..0000000 --- a/WorkBench/Tool/Converters/InvertableBooleanToVisibilityConverter.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Data; -using System.Windows; - -namespace Serein.Workbench.Tool.Converters -{ - /// - /// 根据bool类型控制可见性 - /// - [ValueConversion(typeof(bool), typeof(Visibility))] - public class InvertableBooleanToVisibilityConverter : IValueConverter - { - enum Parameters - { - Normal, Inverted - } - - public object Convert(object value, Type targetType, - object parameter, CultureInfo culture) - { - var boolValue = (bool)value; - var direction = (Parameters)Enum.Parse(typeof(Parameters), (string)parameter); - - if (direction == Parameters.Inverted) - return !boolValue ? Visibility.Visible : Visibility.Collapsed; - - return boolValue ? Visibility.Visible : Visibility.Collapsed; - } - - public object? ConvertBack(object value, Type targetType, - object parameter, CultureInfo culture) - { - return null; - } - } -} diff --git a/WorkBench/Tool/Converters/ThumbPositionConverter.cs b/WorkBench/Tool/Converters/ThumbPositionConverter.cs deleted file mode 100644 index df6adbf..0000000 --- a/WorkBench/Tool/Converters/ThumbPositionConverter.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Data; - -namespace Serein.Workbench.Tool.Converters -{ - /// - /// 画布拉动范围距离计算器 - /// - public class RightThumbPositionConverter : IValueConverter - { - public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) - { - if (value is double width) - return width - 10; // Adjust for Thumb width - return 0; - } - - public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) - { - throw new NotImplementedException(); - } - } - /// - /// 画布拉动范围距离计算器 - /// - public class BottomThumbPositionConverter : IValueConverter - { - public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) - { - if (value is double height) - return height - 10; // Adjust for Thumb height - return 0; - } - - public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) - { - throw new NotImplementedException(); - } - } - /// - /// 画布拉动范围距离计算器 - /// - public class VerticalCenterThumbPositionConverter : IValueConverter - { - public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) - { - if (value is double height) - return height / 2 - 5; // Centering Thumb vertically - return 0; - } - - public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) - { - throw new NotImplementedException(); - } - } - /// - /// 画布拉动范围距离计算器 - /// - public class HorizontalCenterThumbPositionConverter : IValueConverter - { - public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) - { - if (value is double width) - return width / 2 - 5; // Centering Thumb horizontally - return 0; - } - - public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) - { - throw new NotImplementedException(); - } - } - -} diff --git a/WorkBench/Tool/Converters/TypeToColorConverter.cs b/WorkBench/Tool/Converters/TypeToColorConverter.cs deleted file mode 100644 index 6d27425..0000000 --- a/WorkBench/Tool/Converters/TypeToColorConverter.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Serein.Library; -using System.Globalization; -using System.Windows.Data; -using System.Windows.Media; - -namespace Serein.Workbench.Tool.Converters -{ - /// - /// 根据控件类型切换颜色 - /// - public class TypeToColorConverter : IValueConverter - { - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - // 根据 ControlType 返回颜色 - return value switch - { - NodeControlType.Action => Brushes.Blue, - NodeControlType.Flipflop => Brushes.Green, - _ => Brushes.Black, - }; - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotImplementedException(); - } -} From 2c160d660ad40d165aa20a3a39dd64fe24398137 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=80=E6=B3=93=E7=A7=8B=E6=B0=B4?= <1090698674@qq.com> Date: Thu, 2 Jan 2025 13:58:55 +0800 Subject: [PATCH 2/2] Delete Workbench directory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 移除不要的文件夹 --- Workbench/Extension/LineExtension.cs | 53 --- Workbench/Extension/MyExtension.cs | 42 -- Workbench/Node/INodeContainerControl.cs | 33 -- Workbench/Node/INodeJunction.cs | 52 --- .../Node/Junction/ConnectionLineShape.cs | 234 ----------- .../Node/Junction/JunctionControlBase.cs | 378 ------------------ Workbench/Node/Junction/JunctionData.cs | 161 -------- .../Node/Junction/NodeJunctionViewBase.cs | 237 ----------- .../Node/Junction/View/ArgJunctionControl.cs | 74 ---- .../Junction/View/ExecuteJunctionControl.cs | 84 ---- .../Junction/View/NextStepJunctionControl.cs | 60 --- .../Junction/View/ResultJunctionControl.cs | 61 --- Workbench/Node/NodeControlBase.cs | 198 --------- Workbench/Node/RelayCommand.cs | 26 -- Workbench/Node/View/ConnectionControl.cs | 297 -------------- Workbench/Node/View/GlobalDataControl.xaml | 87 ---- Workbench/Node/View/GlobalDataControl.xaml.cs | 87 ---- Workbench/Node/View/ScriptNodeControl.xaml | 93 ----- Workbench/Node/View/ScriptNodeControl.xaml.cs | 162 -------- .../ViewModel/ExpOpNodeControlViewModel.cs | 26 -- .../GlobalDataNodeControlViewModel.cs | 51 --- .../ViewModel/ScriptNodeControlViewModel.cs | 62 --- Workbench/Properties/launchSettings.json | 7 - .../Serein.Workbench_wjzi1sgn_wpftmp.csproj | 292 -------------- Workbench/Themes/BindableRichTextBox.cs | 28 -- Workbench/Tool/GuidReplacer.cs | 68 ---- 26 files changed, 2953 deletions(-) delete mode 100644 Workbench/Extension/LineExtension.cs delete mode 100644 Workbench/Extension/MyExtension.cs delete mode 100644 Workbench/Node/INodeContainerControl.cs delete mode 100644 Workbench/Node/INodeJunction.cs delete mode 100644 Workbench/Node/Junction/ConnectionLineShape.cs delete mode 100644 Workbench/Node/Junction/JunctionControlBase.cs delete mode 100644 Workbench/Node/Junction/JunctionData.cs delete mode 100644 Workbench/Node/Junction/NodeJunctionViewBase.cs delete mode 100644 Workbench/Node/Junction/View/ArgJunctionControl.cs delete mode 100644 Workbench/Node/Junction/View/ExecuteJunctionControl.cs delete mode 100644 Workbench/Node/Junction/View/NextStepJunctionControl.cs delete mode 100644 Workbench/Node/Junction/View/ResultJunctionControl.cs delete mode 100644 Workbench/Node/NodeControlBase.cs delete mode 100644 Workbench/Node/RelayCommand.cs delete mode 100644 Workbench/Node/View/ConnectionControl.cs delete mode 100644 Workbench/Node/View/GlobalDataControl.xaml delete mode 100644 Workbench/Node/View/GlobalDataControl.xaml.cs delete mode 100644 Workbench/Node/View/ScriptNodeControl.xaml delete mode 100644 Workbench/Node/View/ScriptNodeControl.xaml.cs delete mode 100644 Workbench/Node/ViewModel/ExpOpNodeControlViewModel.cs delete mode 100644 Workbench/Node/ViewModel/GlobalDataNodeControlViewModel.cs delete mode 100644 Workbench/Node/ViewModel/ScriptNodeControlViewModel.cs delete mode 100644 Workbench/Properties/launchSettings.json delete mode 100644 Workbench/Serein.Workbench_wjzi1sgn_wpftmp.csproj delete mode 100644 Workbench/Themes/BindableRichTextBox.cs delete mode 100644 Workbench/Tool/GuidReplacer.cs diff --git a/Workbench/Extension/LineExtension.cs b/Workbench/Extension/LineExtension.cs deleted file mode 100644 index ce0eb42..0000000 --- a/Workbench/Extension/LineExtension.cs +++ /dev/null @@ -1,53 +0,0 @@ -using Serein.Library; -using Serein.Workbench.Node.View; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Media; - -namespace Serein.Workbench.Extension -{ - /// - /// 线条颜色 - /// - public static class LineExtension - { - /// - /// 根据连接类型指定颜色 - /// - /// - /// - /// - public static SolidColorBrush ToLineColor(this ConnectionInvokeType currentConnectionType) - { - return currentConnectionType switch - { - ConnectionInvokeType.IsSucceed => new SolidColorBrush((Color)ColorConverter.ConvertFromString("#04FC10")), // 04FC10 & 027E08 - ConnectionInvokeType.IsFail => new SolidColorBrush((Color)ColorConverter.ConvertFromString("#F18905")), - ConnectionInvokeType.IsError => new SolidColorBrush((Color)ColorConverter.ConvertFromString("#FE1343")), - ConnectionInvokeType.Upstream => new SolidColorBrush((Color)ColorConverter.ConvertFromString("#4A82E4")), - ConnectionInvokeType.None => new SolidColorBrush((Color)ColorConverter.ConvertFromString("#56CEF6")), - _ => throw new Exception(), - }; - } - /// - /// 根据连接类型指定颜色 - /// - /// - /// - /// - public static SolidColorBrush ToLineColor(this ConnectionArgSourceType connection) - { - return connection switch - { - ConnectionArgSourceType.GetPreviousNodeData => new SolidColorBrush((Color)ColorConverter.ConvertFromString("#56CEF6")), // 04FC10 & 027E08 - ConnectionArgSourceType.GetOtherNodeData => new SolidColorBrush((Color)ColorConverter.ConvertFromString("#56CEF6")), - ConnectionArgSourceType.GetOtherNodeDataOfInvoke => new SolidColorBrush((Color)ColorConverter.ConvertFromString("#B06BBB")), - _ => throw new Exception(), - }; - } - - } -} diff --git a/Workbench/Extension/MyExtension.cs b/Workbench/Extension/MyExtension.cs deleted file mode 100644 index 0bacb12..0000000 --- a/Workbench/Extension/MyExtension.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; - -namespace Serein.Workbench.Extension -{ - public static class PointExtension - { - public static Point Add(this Point a, Point b) - { - return new Point(a.X + b.X, a.Y + b.Y); - } - - public static Point Sub(this Point a, Point b) - { - return new Point(a.X - b.X, a.Y - b.Y); - } - - public static Vector ToVector(this Point me) - { - return new Vector(me.X, me.Y); - } - } - public static class VectorExtension - { - public static double DotProduct(this Vector a, Vector b) - { - return a.X * b.X + a.Y * b.Y; - } - - public static Vector NormalizeTo(this Vector v) - { - var temp = v; - temp.Normalize(); - - return temp; - } - } -} diff --git a/Workbench/Node/INodeContainerControl.cs b/Workbench/Node/INodeContainerControl.cs deleted file mode 100644 index 4c01eff..0000000 --- a/Workbench/Node/INodeContainerControl.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Serein.Workbench.Node.View; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Serein.Workbench.Node -{ - - /// - /// 约束具有容器功能的节点控件应该有什么方法 - /// - public interface INodeContainerControl - { - /// - /// 放置一个节点 - /// - /// - bool PlaceNode(NodeControlBase nodeControl); - - /// - /// 取出一个节点 - /// - /// - bool TakeOutNode(NodeControlBase nodeControl); - - /// - /// 取出所有节点(用于删除容器) - /// - void TakeOutAll(); - } -} diff --git a/Workbench/Node/INodeJunction.cs b/Workbench/Node/INodeJunction.cs deleted file mode 100644 index ae74d0d..0000000 --- a/Workbench/Node/INodeJunction.cs +++ /dev/null @@ -1,52 +0,0 @@ -using Serein.Workbench.Node.View; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; - -namespace Serein.Workbench.Node -{ - - - - /// - /// 约束一个节点应该有哪些控制点 - /// - public interface INodeJunction - { - /// - /// 方法执行入口控制点 - /// - JunctionControlBase ExecuteJunction { get; } - /// - /// 执行完成后下一个要执行的方法控制点 - /// - JunctionControlBase NextStepJunction { get; } - - /// - /// 参数节点控制点 - /// - JunctionControlBase[] ArgDataJunction { get; } - /// - /// 返回值控制点 - /// - JunctionControlBase ReturnDataJunction { get; } - - /// - /// 获取目标参数控制点,用于防止wpf释放资源导致找不到目标节点,返回-1,-1的坐标 - /// - /// - /// - JunctionControlBase GetJunctionOfArgData(int index) - { - var arr = ArgDataJunction; - if (index >= arr.Length) - { - return null; - } - return arr[index]; - } - } -} diff --git a/Workbench/Node/Junction/ConnectionLineShape.cs b/Workbench/Node/Junction/ConnectionLineShape.cs deleted file mode 100644 index 122adaf..0000000 --- a/Workbench/Node/Junction/ConnectionLineShape.cs +++ /dev/null @@ -1,234 +0,0 @@ -using Serein.Library; -using Serein.Workbench.Extension; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Media; -using System.Windows.Shapes; - -namespace Serein.Workbench.Node.View -{ - /// - /// 连接线的类型 - /// - public enum LineType - { - /// - /// 贝塞尔曲线 - /// - Bezier, - /// - /// 半圆线 - /// - Semicircle, - } - - - - /// - /// 贝塞尔曲线 - /// - public class ConnectionLineShape : Shape - { - private readonly double strokeThickness; - - private readonly LineType lineType; - - /// - /// 确定起始坐标和目标坐标、外光样式的曲线 - /// - /// 线条类型 - /// 起始坐标 - /// 结束坐标 - /// 颜色 - /// 是否为虚线 - public ConnectionLineShape(LineType lineType, - Point start, - Point end, - Brush brush, - bool isDotted = false, - bool isTop = false) - { - this.lineType = lineType; - this.brush = brush; - startPoint = start; - endPoint = end; - this.strokeThickness = 4; - InitElementPoint(isDotted, isTop); - InvalidateVisual(); // 触发重绘 - } - - - public void InitElementPoint(bool isDotted , bool isTop = false) - { - hitVisiblePen = new Pen(Brushes.Transparent, 1.0); // 初始化碰撞检测线 - hitVisiblePen.Freeze(); // Freeze以提高性能 - visualPen = new Pen(brush, 3.0); // 默认可视化Pen - opacity = 1.0d; - if (isDotted) - { - opacity = 0.42d; - visualPen.DashStyle = DashStyles.Dash; // 选择虚线样式 - } - visualPen.Freeze(); // Freeze以提高性能 - - linkSize = 4; // 整线条粗细 - int zIndex = -999999; - if (isTop) - { - zIndex *= -1; - } - Panel.SetZIndex(this, zIndex); // 置底 - } - - /// - /// 更新线条落点位置 - /// - /// - /// - public void UpdatePoints(Point start, Point end) - { - startPoint = start; - endPoint = end; - InvalidateVisual(); // 触发重绘 - } - - /// - /// 更新线条落点位置 - /// - /// - public void UpdateEndPoints(Point point) - { - endPoint = point; - InvalidateVisual(); // 触发重绘 - } - /// - /// 更新线条落点位置 - /// - /// - public void UpdateStartPoints(Point point) - { - startPoint = point; - InvalidateVisual(); // 触发重绘 - } - - /// - /// 控件重绘事件 - /// - /// - protected override void OnRender(DrawingContext drawingContext) - { - // 刷新线条显示位置 - switch (this.lineType) - { - case LineType.Bezier: - DrawBezierCurve(drawingContext, startPoint, endPoint); - break; - case LineType.Semicircle: - DrawSemicircleCurve(drawingContext, startPoint, endPoint); - break; - default: - break; - } - - } - #region 重绘 - - private readonly StreamGeometry streamGeometry = new StreamGeometry(); - private Point rightCenterOfStartLocation; // 目标节点选择左侧边缘中心 - private Point leftCenterOfEndLocation; // 起始节点选择右侧边缘中心 - private Pen hitVisiblePen; // 初始化碰撞检测线 - private Pen visualPen; // 默认可视化Pen - private Point startPoint; // 连接线的起始节点 - private Point endPoint; // 连接线的终点 - private Brush brush; // 线条颜色 - private double opacity; // 透明度 - - double linkSize; // 根据缩放比例调整线条粗细 - protected override Geometry DefiningGeometry => streamGeometry; - - public void UpdateLineColor(Brush brush) - { - visualPen = new Pen(brush, 3.0); // 默认可视化Pen - InvalidateVisual(); // 触发重绘 - } - - - private Point c0, c1; // 用于计算贝塞尔曲线控制点逻辑 - private Vector axis = new Vector(1, 0); - private Vector startToEnd; - private void DrawBezierCurve(DrawingContext drawingContext, - Point start, - Point end) - { - // 控制点的计算逻辑 - double power = 140; // 控制贝塞尔曲线的“拉伸”强度 - drawingContext.PushOpacity(opacity); - // 计算轴向向量与起点到终点的向量 - //var axis = new Vector(1, 0); - startToEnd = (end.ToVector() - start.ToVector()).NormalizeTo(); - - // 计算拉伸程度k,拉伸与水平夹角正相关 - var k = 1 - Math.Pow(Math.Max(0, axis.DotProduct(startToEnd)), 10.0); - - // 如果起点x大于终点x,增加额外的偏移量,避免重叠 - var bias = start.X > end.X ? Math.Abs(start.X - end.X) * 0.25 : 0; - - // 控制点的实际计算 - c0 = new Point(+(power + bias) * k + start.X, start.Y); - c1 = new Point(-(power + bias) * k + end.X, end.Y); - - // 准备StreamGeometry以用于绘制曲线 - streamGeometry.Clear(); - using (var context = streamGeometry.Open()) - { - context.BeginFigure(start, true, false); // 曲线起点 - context.BezierTo(c0, c1, end, true, false); // 画贝塞尔曲线 - } - drawingContext.DrawGeometry(null, visualPen, streamGeometry); - - } - - - - private void DrawSemicircleCurve(DrawingContext drawingContext, Point start, Point end) - { - // 计算中心点和半径 - // 计算圆心和半径 - double x = 35; - // 创建一个弧线路径 - streamGeometry.Clear(); - using (var context = streamGeometry.Open()) - { - // 开始绘制 - context.BeginFigure(start, false, false); - - // 生成弧线 - context.ArcTo( - end, // 结束点 - new Size(x, x), // 椭圆的半径 - 0, // 椭圆的旋转角度 - false, // 是否大弧 - SweepDirection.Counterclockwise, // 方向 - true, // 是否连接到起始点 - true // 是否使用高质量渲染 - ); - - // 结束绘制 - context.LineTo(start, false, false); // 连接到起始点(可选) - } - - // 绘制弧线 - drawingContext.DrawGeometry(null, visualPen, streamGeometry); - - } - #endregion - } - - -} diff --git a/Workbench/Node/Junction/JunctionControlBase.cs b/Workbench/Node/Junction/JunctionControlBase.cs deleted file mode 100644 index 5ce870c..0000000 --- a/Workbench/Node/Junction/JunctionControlBase.cs +++ /dev/null @@ -1,378 +0,0 @@ -using Serein.Library; -using Serein.Library.Utils; -using System; -using System.Net; -using System.Reflection; -using System.Windows; -using Serein.Workbench.Extension; -using System.Windows.Controls; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Shapes; -using System.Windows.Media.Media3D; -using System.Windows.Documents; -using System.Threading; - -namespace Serein.Workbench.Node.View -{ - internal static class MyUIFunc - { - public static Pen CreateAndFreezePen() - { - // 创建Pen - Pen pen = new Pen(Brushes.Black, 1); - - // 冻结Pen - if (pen.CanFreeze) - { - pen.Freeze(); - } - return pen; - } - } - - public class ParamsArgControl: Shape - { - - - public ParamsArgControl() - { - this.MouseDown += ParamsArg_OnMouseDown; // 增加或删除 - this.MouseMove += ParamsArgControl_MouseMove; - this.MouseLeave += ParamsArgControl_MouseLeave; - AddOrRemoveParamsTask = AddAsync; - } - - - - protected readonly StreamGeometry StreamGeometry = new StreamGeometry(); - protected override Geometry DefiningGeometry => StreamGeometry; - - - #region 控件属性,所在的节点 - public static readonly DependencyProperty NodeProperty = - DependencyProperty.Register(nameof(MyNode), typeof(NodeModelBase), typeof(ParamsArgControl), new PropertyMetadata(default(NodeModelBase))); - //public NodeModelBase NodeModel; - - /// - /// 所在的节点 - /// - public NodeModelBase MyNode - { - get { return (NodeModelBase)GetValue(NodeProperty); } - set { SetValue(NodeProperty, value); } - } - #endregion - - #region 控件属性,连接器类型 - public static readonly DependencyProperty ArgIndexProperty = - DependencyProperty.Register(nameof(ArgIndex), typeof(int), typeof(ParamsArgControl), new PropertyMetadata(default(int))); - - /// - /// 参数的索引 - /// - public int ArgIndex - { - get { return (int)GetValue(ArgIndexProperty); } - set { SetValue(ArgIndexProperty, value.ToString()); } - } - #endregion - - - /// - /// 控件重绘事件 - /// - /// - protected override void OnRender(DrawingContext drawingContext) - { - Brush brush = isMouseOver ? Brushes.Red : Brushes.Green; - double height = ActualHeight; - // 定义圆形的大小和位置 - double connectorSize = 10; // 连接器的大小 - double circleCenterX = 8; // 圆心 X 坐标 - double circleCenterY = height / 2; // 圆心 Y 坐标 - var circlePoint = new Point(circleCenterX, circleCenterY); - - // 圆形部分 - var ellipse = new EllipseGeometry(circlePoint, connectorSize / 2, connectorSize / 2); - - drawingContext.DrawGeometry(brush, MyUIFunc.CreateAndFreezePen(), ellipse); - } - - - private bool isMouseOver; // 鼠标悬停状态 - - private Func AddOrRemoveParamsTask; // 增加或删除参数 - - public async void ParamsArg_OnMouseDown(object sender, MouseButtonEventArgs e) - { - await AddOrRemoveParamsTask.Invoke(); - } - - private void ParamsArgControl_MouseMove(object sender, MouseEventArgs e) - { - isMouseOver = true; - if (cancellationTokenSource.IsCancellationRequested) { - cancellationTokenSource = new CancellationTokenSource(); - Task.Run(async () => - { - await Task.Delay(380); - - }, cancellationTokenSource.Token).ContinueWith((t) => - { - // 如果焦点仍在控件上时,则改变点击事件 - if (isMouseOver) - { - AddOrRemoveParamsTask = RemoveAsync; - this.Dispatcher.Invoke(InvalidateVisual);// 触发一次重绘 - - } - }); - } - - } - private CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); - - - private void ParamsArgControl_MouseLeave(object sender, MouseEventArgs e) - { - isMouseOver = false; - AddOrRemoveParamsTask = AddAsync; // 鼠标焦点离开时恢复点击事件 - cancellationTokenSource?.Cancel(); - this.Dispatcher.Invoke(InvalidateVisual);// 触发一次重绘 - - } - - - private async Task AddAsync() - { - await this.MyNode.Env.ChangeParameter(MyNode.Guid, true, ArgIndex); - } - private async Task RemoveAsync() - { - await this.MyNode.Env.ChangeParameter(MyNode.Guid, false, ArgIndex); - } - - } - - - - public abstract class JunctionControlBase : Shape - { - protected JunctionControlBase() - { - this.Width = 25; - this.Height = 20; - this.MouseDown += JunctionControlBase_MouseDown; - this.MouseMove += JunctionControlBase_MouseMove; - this.MouseLeave += JunctionControlBase_MouseLeave; ; - } - - - #region 控件属性,所在的节点 - public static readonly DependencyProperty NodeProperty = - DependencyProperty.Register(nameof(MyNode), typeof(NodeModelBase), typeof(JunctionControlBase), new PropertyMetadata(default(NodeModelBase))); - //public NodeModelBase NodeModel; - - /// - /// 所在的节点 - /// - public NodeModelBase MyNode - { - get { return (NodeModelBase)GetValue(NodeProperty); } - set { SetValue(NodeProperty, value); } - } - #endregion - - #region 控件属性,连接器类型 - public static readonly DependencyProperty JunctionTypeProperty = - DependencyProperty.Register(nameof(JunctionType), typeof(string), typeof(JunctionControlBase), new PropertyMetadata(default(string))); - - /// - /// 控制点类型 - /// - public JunctionType JunctionType - { - get { return EnumHelper.ConvertEnum(GetValue(JunctionTypeProperty).ToString()); } - set { SetValue(JunctionTypeProperty, value.ToString()); } - } - #endregion - - protected readonly StreamGeometry StreamGeometry = new StreamGeometry(); - protected override Geometry DefiningGeometry => StreamGeometry; - - /// - /// 重绘方法 - /// - /// - public abstract void Render(DrawingContext drawingContext); - /// - /// 中心点 - /// - public abstract Point MyCenterPoint { get; } - - - - /// - /// 禁止连接 - /// - private bool IsConnectionDisable; - - /// - /// 处理鼠标悬停状态 - /// - private bool _isMouseOver; - public bool IsMouseOver - { - get => _isMouseOver; - set - { - if(_isMouseOver != value) - { - GlobalJunctionData.MyGlobalConnectingData.CurrentJunction = this; - _isMouseOver = value; - InvalidateVisual(); - } - - } - } - - /// - /// 控件重绘事件 - /// - /// - protected override void OnRender(DrawingContext drawingContext) - { - Render(drawingContext); - } - - /// - /// 获取背景颜色 - /// - /// - protected Brush GetBackgrounp() - { - var myData = GlobalJunctionData.MyGlobalConnectingData; - if(!myData.IsCreateing) - { - return Brushes.Transparent; - } - if (IsMouseOver) - { - if (myData.IsCanConnected) - { - if (myData.Type == JunctionOfConnectionType.Invoke) - { - return myData.ConnectionInvokeType.ToLineColor(); - } - else - { - return myData.ConnectionArgSourceType.ToLineColor(); - } - } - else - { - return Brushes.Red; - } - } - else - { - return Brushes.Transparent; - } - } - - private object lockObj = new object(); - - /// - /// 控件获得鼠标焦点事件 - /// - /// - /// - private void JunctionControlBase_MouseMove(object sender, MouseEventArgs e) - { - //if (!GlobalJunctionData.MyGlobalConnectingData.IsCreateing) return; - - //if (IsMouseOver) return; - IsMouseOver = true; - - //this.InvalidateVisual(); - } - - /// - /// 控件失去鼠标焦点事件 - /// - /// - /// - private void JunctionControlBase_MouseLeave(object sender, MouseEventArgs e) - { - IsMouseOver = false; - e.Handled = true; - - } - - - /// - /// 在碰撞点上按下鼠标控件开始进行移动 - /// - /// - /// - protected void JunctionControlBase_MouseDown(object sender, MouseButtonEventArgs e) - { - if (e.LeftButton == MouseButtonState.Pressed) - { - var canvas = MainWindow.GetParentOfType(this); - if (canvas != null) - { - var myData = GlobalJunctionData.MyGlobalConnectingData; - myData.Reset(); - myData.IsCreateing = true; // 表示开始连接 - myData.StartJunction = this; - myData.CurrentJunction = this; - myData.StartPoint = this.TranslatePoint(new Point(this.Width / 2, this.Height / 2), canvas); - - var junctionOfConnectionType = this.JunctionType.ToConnectyionType(); - ConnectionLineShape bezierLine; // 类别 - Brush brushColor; // 临时线的颜色 - if (junctionOfConnectionType == JunctionOfConnectionType.Invoke) - { - brushColor = ConnectionInvokeType.IsSucceed.ToLineColor(); - } - else if(junctionOfConnectionType == JunctionOfConnectionType.Arg) - { - brushColor = ConnectionArgSourceType.GetOtherNodeData.ToLineColor(); - } - else - { - return; - } - bezierLine = new ConnectionLineShape(LineType.Bezier, - myData.StartPoint, - myData.StartPoint, - brushColor, - isTop: true); // 绘制临时的线 - - Mouse.OverrideCursor = Cursors.Cross; // 设置鼠标为正在创建连线 - myData.MyLine = new MyLine(canvas, bezierLine); - } - } - e.Handled = true; - } - - private Point GetStartPoint() - { - return new Point(this.ActualWidth / 2, this.ActualHeight / 2); // 起始节点选择右侧边缘中心 - } - - - - - - } - - - - - - - -} diff --git a/Workbench/Node/Junction/JunctionData.cs b/Workbench/Node/Junction/JunctionData.cs deleted file mode 100644 index ceb3048..0000000 --- a/Workbench/Node/Junction/JunctionData.cs +++ /dev/null @@ -1,161 +0,0 @@ -using Serein.Library; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Shapes; - -namespace Serein.Workbench.Node.View -{ - - #region Model,不科学的全局变量 - public class MyLine - { - public MyLine(Canvas canvas, ConnectionLineShape line) - { - Canvas = canvas; - Line = line; - canvas?.Children.Add(line); - } - - public Canvas Canvas { get; set; } - public ConnectionLineShape Line { get; set; } - - public void Remove() - { - Canvas?.Children.Remove(Line); - } - } - - public class ConnectingData - { - - /// - /// 是否正在创建连线 - /// - public bool IsCreateing { get; set; } - /// - /// 起始控制点 - /// - public JunctionControlBase StartJunction { get; set; } - /// - /// 当前的控制点 - /// - public JunctionControlBase CurrentJunction { get; set; } - /// - /// 开始坐标 - /// - public Point StartPoint { get; set; } - /// - /// 线条样式 - /// - public MyLine MyLine { get; set; } - - /// - /// 线条类别(方法调用) - /// - public ConnectionInvokeType ConnectionInvokeType { get; set; } = ConnectionInvokeType.IsSucceed; - /// - /// 线条类别(参数传递) - /// - public ConnectionArgSourceType ConnectionArgSourceType { get; set; } = ConnectionArgSourceType.GetOtherNodeData; - - /// - /// 判断当前连接类型 - /// - public JunctionOfConnectionType Type => StartJunction.JunctionType.ToConnectyionType(); - - - /// - /// 是否允许连接 - /// - - public bool IsCanConnected { get - { - - if(StartJunction is null - || CurrentJunction is null - ) - { - return false; - } - - - if (!StartJunction.MyNode.Equals(CurrentJunction.MyNode) - && StartJunction.JunctionType.IsCanConnection(CurrentJunction.JunctionType)) - { - return true; - } - else - { - return false; - } - } - } - - /// - /// 更新临时的连接线 - /// - /// - public void UpdatePoint(Point point) - { - if (StartJunction is null - || CurrentJunction is null - ) - { - return; - } - if (StartJunction.JunctionType == Library.JunctionType.Execute - || StartJunction.JunctionType == Library.JunctionType.ArgData) - { - MyLine.Line.UpdateStartPoints(point); - } - else - { - MyLine.Line.UpdateEndPoints(point); - - } - } - - /// - /// 重置 - /// - public void Reset() - { - IsCreateing = false; - StartJunction = null; - CurrentJunction = null; - MyLine?.Remove(); - ConnectionInvokeType = ConnectionInvokeType.IsSucceed; - ConnectionArgSourceType = ConnectionArgSourceType.GetOtherNodeData; - } - - - - } - - public static class GlobalJunctionData - { - //private static ConnectingData? myGlobalData; - //private static object _lockObj = new object(); - - /// - /// 创建节点之间控制点的连接行为 - /// - public static ConnectingData MyGlobalConnectingData { get; } = new ConnectingData(); - - /// - /// 删除连接视觉效果 - /// - public static void OK() - { - MyGlobalConnectingData.Reset(); - } - } - #endregion -} diff --git a/Workbench/Node/Junction/NodeJunctionViewBase.cs b/Workbench/Node/Junction/NodeJunctionViewBase.cs deleted file mode 100644 index 92e6a59..0000000 --- a/Workbench/Node/Junction/NodeJunctionViewBase.cs +++ /dev/null @@ -1,237 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Media; -using System.Windows; -using Serein.Workbench.Node.View; -using System.Windows.Controls; -using Serein.Library; -using System.Windows.Data; - -namespace Serein.Workbench.Node.View -{ - - - public abstract class NodeJunctionViewBase : ContentControl, IDisposable - { - public NodeJunctionViewBase() - { - var transfromGroup = new TransformGroup(); - transfromGroup.Children.Add(_Translate); - RenderTransform = transfromGroup; - } - - /// - /// 每个连接器都有一个唯一标识符(Guid),用于标识连接器。 - /// - public Guid Guid - { - get => (Guid)GetValue(GuidProperty); - set => SetValue(GuidProperty, value); - } - public static readonly DependencyProperty GuidProperty = DependencyProperty.Register( - nameof(Guid), - typeof(Guid), - typeof(NodeJunctionViewBase), // NodeConnectorContent - new PropertyMetadata(Guid.Empty)); - - /// - /// 连接器当前的连接数,表示有多少条 NodeLink 连接到此连接器。该属性为只读。 - /// - public int ConnectedCount - { - get => (int)GetValue(ConnectedCountProperty); - private set => SetValue(ConnectedCountPropertyKey, value); - } - public static readonly DependencyPropertyKey ConnectedCountPropertyKey = DependencyProperty.RegisterReadOnly( - nameof(ConnectedCount), - typeof(int), - typeof(NodeJunctionViewBase), // NodeConnectorContent - new PropertyMetadata(0)); - - public static readonly DependencyProperty ConnectedCountProperty = ConnectedCountPropertyKey.DependencyProperty; - - /// - /// 布尔值,指示此连接器是否有任何连接。 - /// - public bool IsConnected - { - get => (bool)GetValue(IsConnectedProperty); - private set => SetValue(IsConnectedPropertyKey, value); - } - public static readonly DependencyPropertyKey IsConnectedPropertyKey = DependencyProperty.RegisterReadOnly( - nameof(IsConnected), - typeof(bool), - typeof(NodeJunctionViewBase), // NodeConnectorContent - new PropertyMetadata(false)); - - public static readonly DependencyProperty IsConnectedProperty = IsConnectedPropertyKey.DependencyProperty; - - /// - /// 这些属性控制连接器的外观(颜色、边框厚度、填充颜色)。 - /// - public Brush Stroke - { - get => (Brush)GetValue(StrokeProperty); - set => SetValue(StrokeProperty, value); - } - public static readonly DependencyProperty StrokeProperty = DependencyProperty.Register( - nameof(Stroke), - typeof(Brush), - typeof(NodeJunctionViewBase), // NodeConnectorContent - new FrameworkPropertyMetadata(Brushes.Blue)); - - /// - /// 这些属性控制连接器的外观(颜色、边框厚度、填充颜色)。 - /// - public double StrokeThickness - { - get => (double)GetValue(StrokeThicknessProperty); - set => SetValue(StrokeThicknessProperty, value); - } - public static readonly DependencyProperty StrokeThicknessProperty = DependencyProperty.Register( - nameof(StrokeThickness), - typeof(double), - typeof(NodeJunctionViewBase), // NodeConnectorContent - new FrameworkPropertyMetadata(1.0)); - - /// - /// 这些属性控制连接器的外观(颜色、边框厚度、填充颜色)。 - /// - public Brush Fill - { - get => (Brush)GetValue(FillProperty); - set => SetValue(FillProperty, value); - } - public static readonly DependencyProperty FillProperty = DependencyProperty.Register( - nameof(Fill), - typeof(Brush), - typeof(NodeJunctionViewBase),// NodeConnectorContent - new FrameworkPropertyMetadata(Brushes.Gray)); - - /// - /// 指示该连接器是否可以与其他连接器进行连接。 - /// - public bool CanConnect - { - get => (bool)GetValue(CanConnectProperty); - set => SetValue(CanConnectProperty, value); - } - public static readonly DependencyProperty CanConnectProperty = DependencyProperty.Register( - nameof(CanConnect), - typeof(bool), - typeof(NodeJunctionViewBase),// NodeConnectorContent - new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.AffectsRender)); - - - private Point _Position = new Point(); - /// - /// 该连接器的当前坐标(位置)。 - /// - public Point Position - { - get => _Position; - set => UpdatePosition(value); - } - - /// - /// (重要数据)表示连接器所属的节点。 - /// - public NodeModelBase NodeModel { get; private set; } = null; - - /// - /// 该连接器所连接的所有 NodeLink 的集合。 - /// - public IEnumerable NodeLinks => _NodeLinks; - List _NodeLinks = new List(); - - protected abstract FrameworkElement ConnectorControl { get; } - TranslateTransform _Translate = new TranslateTransform(); - void UpdatePosition(Point pos) - { - _Position = pos; - _Translate.X = _Position.X; - _Translate.Y = _Position.Y; - - InvalidateVisual(); - } - - /// - /// 将 NodeLink 添加到连接器,并更新 ConnectedCount 和 IsConnected。 - /// - /// - public void Connect(ConnectionControl nodeLink) - { - _NodeLinks.Add(nodeLink); - ConnectedCount = _NodeLinks.Count; - IsConnected = ConnectedCount > 0; - } - - /// - /// 断开与某个 NodeLink 的连接,更新连接状态。 - /// - /// - public void Disconnect(ConnectionControl nodeLink) - { - _NodeLinks.Remove(nodeLink); - ConnectedCount = _NodeLinks.Count; - IsConnected = ConnectedCount > 0; - } - - /// - /// 获取连接器相对于指定 Canvas 的位置。 - /// - /// - /// - /// - /// - public Point GetContentPosition(Canvas canvas, double xScaleOffset = 0.5, double yScaleOffset = 0.5) - { - // it will be shifted Control position if not called UpdateLayout(). - ConnectorControl.UpdateLayout(); - var transformer = ConnectorControl.TransformToVisual(canvas); - - var x = ConnectorControl.ActualWidth * xScaleOffset; - var y = ConnectorControl.ActualHeight * yScaleOffset; - return transformer.Transform(new Point(x, y)); - } - - /// - /// 更新与此连接器相连的所有 NodeLink 的位置。这个方法是抽象的,要求子类实现。 - /// - /// - public abstract void UpdateLinkPosition(Canvas canvas); - - /// - /// 用于检查此连接器是否可以与另一个连接器相连接,要求子类实现。 - /// - /// - /// - public abstract bool CanConnectTo(NodeJunctionViewBase connector); - - /// - /// 释放连接器相关的资源,包括样式、绑定和已连接的 NodeLink - /// - public void Dispose() - { - // You need to clear Style. - // Because implemented on style for binding. - Style = null; - - // Clear binding for subscribing source changed event from old control. - // throw exception about visual tree ancestor different if you not clear binding. - BindingOperations.ClearAllBindings(this); - - var nodeLinks = _NodeLinks.ToArray(); - - // it must instance to nodeLinks because change node link collection in NodeLink Dispose. - foreach (var nodeLink in nodeLinks) - { - // nodeLink.Dispose(); - } - } - - } -} diff --git a/Workbench/Node/Junction/View/ArgJunctionControl.cs b/Workbench/Node/Junction/View/ArgJunctionControl.cs deleted file mode 100644 index 6ef6927..0000000 --- a/Workbench/Node/Junction/View/ArgJunctionControl.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System.Windows; -using System.Windows.Media; -using System.Windows.Shapes; -using Serein.Library; - -namespace Serein.Workbench.Node.View -{ - public class ArgJunctionControl : JunctionControlBase - { - public ArgJunctionControl() - { - base.JunctionType = JunctionType.ArgData; - this.InvalidateVisual(); - } - - #region 控件属性,对应的参数 - public static readonly DependencyProperty ArgIndexProperty = - DependencyProperty.Register("ArgIndex", typeof(int), typeof(ArgJunctionControl), new PropertyMetadata(default(int))); - - /// - /// 所在的节点 - /// - public int ArgIndex - { - get { return (int)GetValue(ArgIndexProperty); } - set { SetValue(ArgIndexProperty, value); } - } - - - #endregion - private Point _myCenterPoint; - public override Point MyCenterPoint { get => _myCenterPoint; } - - - public override void Render(DrawingContext drawingContext) - { - double width = ActualWidth; - double height = ActualHeight; - var background = GetBackgrounp(); - // 输入连接器的背景 - var connectorRect = new Rect(0, 0, width, height); - drawingContext.DrawRectangle(Brushes.Transparent, null, connectorRect); - - // 定义圆形的大小和位置 - double connectorSize = 10; // 连接器的大小 - double circleCenterX = 8; // 圆心 X 坐标 - double circleCenterY = height / 2; // 圆心 Y 坐标 - var circlePoint = new Point(circleCenterX, circleCenterY); - _myCenterPoint = new Point(circleCenterX - connectorSize / 2, circleCenterY); // 中心坐标 - - // 绘制连接器的圆形部分 - var ellipse = new EllipseGeometry(circlePoint, connectorSize / 2, connectorSize / 2); - drawingContext.DrawGeometry(background, MyUIFunc.CreateAndFreezePen(), ellipse); - - // 定义三角形的间距 - double triangleOffsetX = 4; // 三角形与圆形的间距 - double triangleCenterX = circleCenterX + connectorSize / 2 + triangleOffsetX; // 三角形中心 X 坐标 - double triangleCenterY = circleCenterY; // 三角形中心 Y 坐标 - - // 绘制三角形 - var pathGeometry = new StreamGeometry(); - using (var context = pathGeometry.Open()) - { - context.BeginFigure(new Point(triangleCenterX, triangleCenterY - 4.5), true, true); - context.LineTo(new Point(triangleCenterX + 5, triangleCenterY), true, false); - context.LineTo(new Point(triangleCenterX, triangleCenterY + 4.5), true, false); - context.LineTo(new Point(triangleCenterX, triangleCenterY - 4.5), true, false); - } - drawingContext.DrawGeometry(background, MyUIFunc.CreateAndFreezePen(), pathGeometry); - } - } - - -} diff --git a/Workbench/Node/Junction/View/ExecuteJunctionControl.cs b/Workbench/Node/Junction/View/ExecuteJunctionControl.cs deleted file mode 100644 index 9247df1..0000000 --- a/Workbench/Node/Junction/View/ExecuteJunctionControl.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System.Windows; -using System.Windows.Controls; -using System.Windows.Media; -using System.Windows.Shapes; -using Serein.Library; - -namespace Serein.Workbench.Node.View -{ - public class ExecuteJunctionControl : JunctionControlBase - { - - - - public ExecuteJunctionControl() - { - base.JunctionType = JunctionType.Execute; - this.InvalidateVisual(); - - } - private Point _myCenterPoint; - public override Point MyCenterPoint { get => _myCenterPoint; } - public override void Render(DrawingContext drawingContext) - { - double width = ActualWidth; - double height = ActualHeight; - var background = GetBackgrounp(); - // 绘制边框 - //var borderBrush = new SolidColorBrush(Colors.Black); - //var borderThickness = 1.0; - //var borderRect = new Rect(0, 0, width, height); - //drawingContext.DrawRectangle(null, new Pen(borderBrush, borderThickness), borderRect); - - // 输入连接器的背景 - var connectorRect = new Rect(0, 0, width, height); - drawingContext.DrawRectangle(Brushes.Transparent,null, connectorRect); - //drawingContext.DrawRectangle(Brushes.Transparent, new Pen(background,2), connectorRect); - - // 定义圆形的大小和位置 - double connectorSize = 10; // 连接器的大小 - double circleCenterX = 8; // 圆心 X 坐标 - double circleCenterY = height / 2; // 圆心 Y 坐标 - _myCenterPoint = new Point(circleCenterX - connectorSize / 2, circleCenterY); // 中心坐标 - - var circlePoint = new Point(circleCenterX, circleCenterY); - // 绘制连接器的圆形部分 - var ellipse = new EllipseGeometry(circlePoint, connectorSize / 2, connectorSize / 2); - - - drawingContext.DrawGeometry(background, MyUIFunc.CreateAndFreezePen(), ellipse); - - - - - // 定义三角形的间距 - double triangleOffsetX = 4; // 三角形与圆形的间距 - double triangleCenterX = circleCenterX + connectorSize / 2 + triangleOffsetX; // 三角形中心 X 坐标 - double triangleCenterY = circleCenterY; // 三角形中心 Y 坐标 - - // 绘制三角形 - var pathGeometry = new StreamGeometry(); - using (var context = pathGeometry.Open()) - { - context.BeginFigure(new Point(triangleCenterX, triangleCenterY - 4.5), true, true); - context.LineTo(new Point(triangleCenterX + 5, triangleCenterY), true, false); - context.LineTo(new Point(triangleCenterX, triangleCenterY + 4.5), true, false); - context.LineTo(new Point(triangleCenterX, triangleCenterY - 4.5), true, false); - } - drawingContext.DrawGeometry(background, MyUIFunc.CreateAndFreezePen(), pathGeometry); - - // 绘制标签 - //var formattedText = new FormattedText( - // "执行", - // System.Globalization.CultureInfo.CurrentCulture, - // FlowDirection.LeftToRight, - // new Typeface("Segoe UI"), - // 12, - // Brushes.Black, - // VisualTreeHelper.GetDpi(this).PixelsPerDip); - //drawingContext.DrawText(formattedText, new Point(18,1)); - } - } - - -} diff --git a/Workbench/Node/Junction/View/NextStepJunctionControl.cs b/Workbench/Node/Junction/View/NextStepJunctionControl.cs deleted file mode 100644 index 7c5bde9..0000000 --- a/Workbench/Node/Junction/View/NextStepJunctionControl.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System.Windows; -using System.Windows.Media; -using System.Windows.Shapes; -using Serein.Library; - -namespace Serein.Workbench.Node.View -{ - - public class NextStepJunctionControl : JunctionControlBase - { - //public override JunctionType JunctionType { get; } = JunctionType.NextStep; - public NextStepJunctionControl() - { - base.JunctionType = JunctionType.NextStep; - this.InvalidateVisual(); - } - private Point _myCenterPoint; - public override Point MyCenterPoint { get => _myCenterPoint; } - public override void Render(DrawingContext drawingContext) - { - double width = ActualWidth; - double height = ActualHeight; - var background = GetBackgrounp(); - // 输入连接器的背景 - var connectorRect = new Rect(0, 0, width, height); - drawingContext.DrawRectangle(Brushes.Transparent, null, connectorRect); - - // 定义圆形的大小和位置 - double connectorSize = 10; // 连接器的大小 - double circleCenterX = 8; // 圆心 X 坐标 - double circleCenterY = height / 2; // 圆心 Y 坐标 - _myCenterPoint = new Point(circleCenterX - connectorSize / 2, circleCenterY); // 中心坐标 - - var circlePoint = new Point(circleCenterX, circleCenterY); - // 绘制连接器的圆形部分 - var ellipse = new EllipseGeometry(circlePoint, connectorSize / 2, connectorSize / 2); - drawingContext.DrawGeometry(background, MyUIFunc.CreateAndFreezePen(), ellipse); - - // 绘制连接器的圆形部分 - //var ellipse = new EllipseGeometry(circlePoint, connectorSize / 2, connectorSize / 2); - - - // 定义三角形的间距 - double triangleOffsetX = 4; // 三角形与圆形的间距 - double triangleCenterX = circleCenterX + connectorSize / 2 + triangleOffsetX; // 三角形中心 X 坐标 - double triangleCenterY = circleCenterY; // 三角形中心 Y 坐标 - - // 绘制三角形 - var pathGeometry = new StreamGeometry(); - using (var context = pathGeometry.Open()) - { - context.BeginFigure(new Point(triangleCenterX, triangleCenterY - 4.5), true, true); - context.LineTo(new Point(triangleCenterX + 5, triangleCenterY), true, false); - context.LineTo(new Point(triangleCenterX, triangleCenterY + 4.5), true, false); - context.LineTo(new Point(triangleCenterX, triangleCenterY - 4.5), true, false); - } - drawingContext.DrawGeometry(background, MyUIFunc.CreateAndFreezePen(), pathGeometry); - } - } -} diff --git a/Workbench/Node/Junction/View/ResultJunctionControl.cs b/Workbench/Node/Junction/View/ResultJunctionControl.cs deleted file mode 100644 index aaad0d3..0000000 --- a/Workbench/Node/Junction/View/ResultJunctionControl.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System.Windows; -using System.Windows.Media; -using System.Windows.Shapes; -using Serein.Library; - -namespace Serein.Workbench.Node.View -{ - - public class ResultJunctionControl : JunctionControlBase - { - //public override JunctionType JunctionType { get; } = JunctionType.ReturnData; - - public ResultJunctionControl() - { - base.JunctionType = JunctionType.ReturnData; - this.InvalidateVisual(); - } - private Point _myCenterPoint; - public override Point MyCenterPoint { get => _myCenterPoint; } - - public override void Render(DrawingContext drawingContext) - { - double width = ActualWidth; - double height = ActualHeight; - - // 输入连接器的背景 - var connectorRect = new Rect(0, 0, width, height); - drawingContext.DrawRectangle(Brushes.Transparent, null, connectorRect); - - var background = GetBackgrounp(); - - // 定义圆形的大小和位置 - double connectorSize = 10; // 连接器的大小 - double circleCenterX = 8; // 圆心 X 坐标 - double circleCenterY = height / 2; // 圆心 Y 坐标 - var circlePoint = new Point(circleCenterX, circleCenterY); - - _myCenterPoint = new Point(circleCenterX - connectorSize / 2 , circleCenterY); // 中心坐标 - - // 绘制连接器的圆形部分 - var ellipse = new EllipseGeometry(circlePoint, connectorSize / 2, connectorSize / 2); - drawingContext.DrawGeometry(background, MyUIFunc.CreateAndFreezePen(), ellipse); - - // 定义三角形的间距 - double triangleOffsetX = 4; // 三角形与圆形的间距 - double triangleCenterX = circleCenterX + connectorSize / 2 + triangleOffsetX; // 三角形中心 X 坐标 - double triangleCenterY = circleCenterY; // 三角形中心 Y 坐标 - - // 绘制三角形 - var pathGeometry = new StreamGeometry(); - using (var context = pathGeometry.Open()) - { - context.BeginFigure(new Point(triangleCenterX, triangleCenterY - 4.5), true, true); - context.LineTo(new Point(triangleCenterX + 5, triangleCenterY), true, false); - context.LineTo(new Point(triangleCenterX, triangleCenterY + 4.5), true, false); - context.LineTo(new Point(triangleCenterX, triangleCenterY - 4.5), true, false); - } - drawingContext.DrawGeometry(background, MyUIFunc.CreateAndFreezePen(), pathGeometry); - } - } -} diff --git a/Workbench/Node/NodeControlBase.cs b/Workbench/Node/NodeControlBase.cs deleted file mode 100644 index 2487cfb..0000000 --- a/Workbench/Node/NodeControlBase.cs +++ /dev/null @@ -1,198 +0,0 @@ -using Serein.Library; -using Serein.Library.Api; -using Serein.Workbench.Node.ViewModel; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Input; -using System.Windows.Media; - -namespace Serein.Workbench.Node.View -{ - - /// - /// 节点控件基类(控件) - /// - public abstract class NodeControlBase : UserControl, IDynamicFlowNode - { - /// - /// 节点所在的画布(以后需要将画布封装出来,实现多画布的功能) - /// - public Canvas NodeCanvas { get; set; } - - private INodeContainerControl nodeContainerControl; - /// - /// 如果该节点放置在了某个容器节点,就会记录这个容器节点 - /// - private INodeContainerControl NodeContainerControl { get; } - - /// - /// 记录与该节点控件有关的所有连接 - /// - private readonly List connectionControls = new List(); - - public NodeControlViewModelBase ViewModel { get; set; } - - - protected NodeControlBase() - { - this.Background = Brushes.Transparent; - } - - protected NodeControlBase(NodeControlViewModelBase viewModelBase) - { - ViewModel = viewModelBase; - this.Background = Brushes.Transparent; - this.DataContext = viewModelBase; - SetBinding(); - } - - /// - /// 放置在某个节点容器中 - /// - public void PlaceToContainer(INodeContainerControl nodeContainerControl) - { - this.nodeContainerControl = nodeContainerControl; - NodeCanvas.Children.Remove(this); // 临时从画布上移除 - var result = nodeContainerControl.PlaceNode(this); - if (!result) // 检查是否放置成功,如果不成功,需要重新添加回来 - { - NodeCanvas.Children.Add(this); // 从画布上移除 - - } - } - - /// - /// 从某个节点容器取出 - /// - public void TakeOutContainer() - { - var result = nodeContainerControl.TakeOutNode(this); // 从控件取出 - if (result) // 移除成功时才添加到画布上 - { - NodeCanvas.Children.Add(this); // 重新添加到画布上 - if (nodeContainerControl is NodeControlBase containerControl) - { - this.ViewModel.NodeModel.Position.X = containerControl.ViewModel.NodeModel.Position.X + containerControl.Width + 10; - this.ViewModel.NodeModel.Position.Y = containerControl.ViewModel.NodeModel.Position.Y; - } - } - - } - - /// - /// 添加与该节点有关的连接后,记录下来 - /// - /// - public void AddCnnection(ConnectionControl connection) - { - connectionControls.Add(connection); - } - - /// - /// 删除了连接之后,还需要从节点中的记录移除 - /// - /// - public void RemoveConnection(ConnectionControl connection) - { - connectionControls.Remove(connection); - connection.Remote(); - } - - /// - /// 删除所有连接 - /// - public void RemoveAllConection() - { - foreach (var connection in this.connectionControls) - { - connection.Remote(); - } - } - - /// - /// 更新与该节点有关的数据 - /// - public void UpdateLocationConnections() - { - foreach (var connection in this.connectionControls) - { - connection.RefreshLine(); // 主动更新连线位置 - } - } - - - /// - /// 设置绑定: - /// Canvas.X and Y : 画布位置 - /// - public void SetBinding() - { - // 绑定 Canvas.Left - Binding leftBinding = new Binding("X") - { - Source = ViewModel.NodeModel.Position, // 如果 X 属性在当前 DataContext 中 - Mode = BindingMode.TwoWay - }; - BindingOperations.SetBinding(this, Canvas.LeftProperty, leftBinding); - - // 绑定 Canvas.Top - Binding topBinding = new Binding("Y") - { - Source = ViewModel.NodeModel.Position, // 如果 Y 属性在当前 DataContext 中 - Mode = BindingMode.TwoWay - }; - BindingOperations.SetBinding(this, Canvas.TopProperty, topBinding); - } - - /// - /// 穿透视觉树获取指定类型的第一个元素 - /// - /// - /// - /// - protected T FindVisualChild(DependencyObject parent) where T : DependencyObject - { - for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++) - { - var child = VisualTreeHelper.GetChild(parent, i); - if (child is T typedChild) - { - return typedChild; - } - - var childOfChild = FindVisualChild(child); - if (childOfChild != null) - { - return childOfChild; - } - } - return null; - } - - - - } - - - - - //public class FLowNodeObObservableCollection : ObservableCollection - //{ - - // public void AddRange(IEnumerable items) - // { - // foreach (var item in items) - // { - // this.Items.Add(item); - // } - // OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add)); - // } - //} -} - - - - - - diff --git a/Workbench/Node/RelayCommand.cs b/Workbench/Node/RelayCommand.cs deleted file mode 100644 index a19b531..0000000 --- a/Workbench/Node/RelayCommand.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.Windows.Input; - -namespace Serein.Workbench.Node -{ - - public class RelayCommand : ICommand - { - private readonly Action _execute; - private readonly Func _canExecute; - - public RelayCommand(Action execute, Func canExecute = null) - { - _execute = execute; - _canExecute = canExecute; - } - - public event EventHandler CanExecuteChanged; - - public bool CanExecute(object parameter) => _canExecute == null || _canExecute(parameter); - - public void Execute(object parameter) => _execute(parameter); - - public void RaiseCanExecuteChanged() => CanExecuteChanged?.Invoke(this, EventArgs.Empty); - } - -} diff --git a/Workbench/Node/View/ConnectionControl.cs b/Workbench/Node/View/ConnectionControl.cs deleted file mode 100644 index e41637d..0000000 --- a/Workbench/Node/View/ConnectionControl.cs +++ /dev/null @@ -1,297 +0,0 @@ -using Serein.Library; -using Serein.Library.Api; -using Serein.Workbench.Extension; -using System; -using System.Net; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Media; -using System.Windows.Shapes; -using Color = System.Windows.Media.Color; -using ColorConverter = System.Windows.Media.ColorConverter; -using Point = System.Windows.Point; - -namespace Serein.Workbench.Node.View -{ - #region 连接点相关代码 - - - - public class ConnectionModelBase - { - /// - /// 起始节点 - /// - public NodeModelBase StartNode { get; set; } - /// - /// 目标节点 - /// - public NodeModelBase EndNode { get; set; } - - /// - /// 来源于起始节点的(控制点)类型 - /// - public JunctionType JoinTypeOfStart { get; set; } - - /// - /// 连接到目标节点的(控制点)类型 - /// - public JunctionType JoinTypeOfEnd { get; set; } - - /// - /// 连接类型 - /// - public ConnectionInvokeType Type { get; set; } - } - - - public interface IJunctionNode - { - string BoundNodeGuid { get; } - } - - /// - /// 连接点 - /// - public class JunctionNode : IJunctionNode - { - /// - /// 连接点类型 - /// - public JunctionType JunctionType { get; } - /// - /// 对应的视图对象 - /// - public NodeModelBase NodeModel { get; set; } - /// - /// - /// - public string BoundNodeGuid { get => NodeModel.Guid; } - } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #endregion - - /// - /// 连接控件,表示控件的连接关系 - /// - public class ConnectionControl - { - /// - /// 所在的画布 - /// - public Canvas Canvas { get; } - - /// - /// 调用方法类型,连接类型 - /// - public ConnectionInvokeType InvokeType { get; } - - /// - /// 目标节点控制点 - /// - private INodeJunction EndNode; - - /// - /// 获取参数类型,第几个参数 - /// - public int ArgIndex { get; set; } = -1; - - /// - /// 参数来源(决定了连接线的样式) - /// - public ConnectionArgSourceType ArgSourceType { get; set; } - - /// - /// 起始控制点 - /// - public JunctionControlBase Start { get; set; } - - /// - /// 目标控制点 - /// - public JunctionControlBase End { get; set; } - - /// - /// 连接线 - /// - private ConnectionLineShape BezierLine; - - - - private LineType LineType; - - /// - /// 关于调用 - /// - /// - /// - public ConnectionControl(Canvas Canvas, - ConnectionInvokeType invokeType, - JunctionControlBase Start, - JunctionControlBase End) - { - this.LineType = LineType.Bezier; - this.Canvas = Canvas; - this.InvokeType = invokeType; - this.Start = Start; - this.End = End; - InitElementPoint(); - } - - /// - /// 关于入参 - /// - /// - /// - public ConnectionControl(LineType LineType, - Canvas Canvas, - int argIndex, - ConnectionArgSourceType argSourceType, - JunctionControlBase Start, - JunctionControlBase End, - INodeJunction nodeJunction) - { - this.LineType = LineType; - this.Canvas = Canvas; - this.ArgIndex = argIndex; - this.ArgSourceType = argSourceType; - this.Start = Start; - this.End = End; - this.EndNode = nodeJunction; - InitElementPoint(); - } - - /// - /// 绘制 - /// - public void InitElementPoint() - { - leftCenterOfEndLocation = Start.MyCenterPoint; - rightCenterOfStartLocation = End.MyCenterPoint; - - (Point startPoint, Point endPoint) = RefreshPoint(Canvas, Start, End); - var connectionType = Start.JunctionType.ToConnectyionType(); - bool isDotted; - Brush brush; - if(connectionType == JunctionOfConnectionType.Invoke) - { - brush = InvokeType.ToLineColor(); - isDotted = false; - } - else - { - brush = ArgSourceType.ToLineColor(); - isDotted = true; // 如果为参数,则绘制虚线 - } - BezierLine = new ConnectionLineShape(LineType, startPoint, endPoint, brush, isDotted); - Grid.SetZIndex(BezierLine, -9999999); // 置底 - Canvas.Children.Add(BezierLine); - - ConfigureLineContextMenu(); //配置右键菜单 - } - - - /// - /// 配置连接曲线的右键菜单 - /// - private void ConfigureLineContextMenu() - { - var contextMenu = new ContextMenu(); - contextMenu.Items.Add(MainWindow.CreateMenuItem("删除连线", (s, e) => Remote())); - contextMenu.Items.Add(MainWindow.CreateMenuItem("于父节点调用顺序中置顶", (s, e) => Topping())); - BezierLine.ContextMenu = contextMenu; - } - - - /// - /// 删除该连线 - /// - public void Remote() - { - Canvas.Children.Remove(BezierLine); - var env = Start.MyNode.Env; - if (Start.JunctionType.ToConnectyionType() == JunctionOfConnectionType.Invoke) - { - env.RemoveConnectInvokeAsync(Start.MyNode.Guid, End.MyNode.Guid, InvokeType); - } - else if (Start.JunctionType.ToConnectyionType() == JunctionOfConnectionType.Arg) - { - env.RemoveConnectArgSourceAsync(Start.MyNode.Guid, End.MyNode.Guid, ArgIndex) ; - } - } - - /// - /// 置顶调用关系 - /// - public void Topping() - { - var env = Start.MyNode.Env; - if (Start.JunctionType.ToConnectyionType() == JunctionOfConnectionType.Invoke) - { - env.SetConnectPriorityInvoke(Start.MyNode.Guid, End.MyNode.Guid, InvokeType); - } - } - - /// - /// 重新绘制 - /// - public void RefreshLine() - { - if(ArgIndex > -1) - { - End = EndNode.GetJunctionOfArgData(ArgIndex) ?? End; - } - (Point startPoint, Point endPoint) = RefreshPoint(Canvas, Start, End); - BezierLine.UpdatePoints(startPoint, endPoint); - } - - - private Point rightCenterOfStartLocation; // 目标节点选择左侧边缘中心 - private Point leftCenterOfEndLocation; // 起始节点选择右侧边缘中心 - /// - /// 刷新坐标 - /// - - private (Point startPoint, Point endPoint) RefreshPoint(Canvas canvas, FrameworkElement startElement, FrameworkElement endElement) - { - var startPoint = startElement.TranslatePoint(rightCenterOfStartLocation, canvas); // 获取起始节点的中心位置 - var endPoint = endElement.TranslatePoint(leftCenterOfEndLocation, canvas); // 计算终点位置 - return (startPoint, endPoint); - } - } - - - - - - - - -} diff --git a/Workbench/Node/View/GlobalDataControl.xaml b/Workbench/Node/View/GlobalDataControl.xaml deleted file mode 100644 index 56b23c3..0000000 --- a/Workbench/Node/View/GlobalDataControl.xaml +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Workbench/Node/View/GlobalDataControl.xaml.cs b/Workbench/Node/View/GlobalDataControl.xaml.cs deleted file mode 100644 index f3f4bf3..0000000 --- a/Workbench/Node/View/GlobalDataControl.xaml.cs +++ /dev/null @@ -1,87 +0,0 @@ -using Serein.NodeFlow.Model; -using Serein.Workbench.Node.ViewModel; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -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.Node.View -{ - /// - /// UserControl1.xaml 的交互逻辑 - /// - public partial class GlobalDataControl : NodeControlBase, INodeJunction, INodeContainerControl - { - public GlobalDataControl() : base() - { - // 窗体初始化需要 - base.ViewModel = new GlobalDataNodeControlViewModel(new SingleGlobalDataNode(null)); - DataContext = ViewModel; - InitializeComponent(); - } - - public GlobalDataControl(GlobalDataNodeControlViewModel viewModel) : base(viewModel) - { - DataContext = viewModel; - InitializeComponent(); - } - - - /// - /// 入参控制点(可能有,可能没) - /// - JunctionControlBase INodeJunction.ExecuteJunction => this.ExecuteJunctionControl; - - /// - /// 下一个调用方法控制点(可能有,可能没) - /// - JunctionControlBase INodeJunction.NextStepJunction => this.NextStepJunctionControl; - - /// - /// 返回值控制点(可能有,可能没) - /// - JunctionControlBase INodeJunction.ReturnDataJunction => throw new NotImplementedException(); - - /// - /// 方法入参控制点(可能有,可能没) - /// - JunctionControlBase[] INodeJunction.ArgDataJunction => throw new NotImplementedException(); - - - public bool PlaceNode(NodeControlBase nodeControl) - { - if (GlobalDataPanel.Children.Contains(nodeControl)) - { - return false; - } - GlobalDataPanel.Children.Add(nodeControl); - return true; - } - - public bool TakeOutNode(NodeControlBase nodeControl) - { - if (!GlobalDataPanel.Children.Contains(nodeControl)) - { - return false; - } - GlobalDataPanel.Children.Remove(nodeControl); - return true; - } - - public void TakeOutAll() - { - GlobalDataPanel.Children.Clear(); - } - - } -} diff --git a/Workbench/Node/View/ScriptNodeControl.xaml b/Workbench/Node/View/ScriptNodeControl.xaml deleted file mode 100644 index b7d0808..0000000 --- a/Workbench/Node/View/ScriptNodeControl.xaml +++ /dev/null @@ -1,93 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Workbench/Node/View/ScriptNodeControl.xaml.cs b/Workbench/Node/View/ScriptNodeControl.xaml.cs deleted file mode 100644 index f16decf..0000000 --- a/Workbench/Node/View/ScriptNodeControl.xaml.cs +++ /dev/null @@ -1,162 +0,0 @@ -using Serein.NodeFlow.Model; -using Serein.Workbench.Node.ViewModel; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -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; -using System.Windows.Threading; - -namespace Serein.Workbench.Node.View -{ - /// - /// ScriptNodeControl.xaml 的交互逻辑 - /// - public partial class ScriptNodeControl : NodeControlBase , INodeJunction - { - private ScriptNodeControlViewModel viewModel => (ScriptNodeControlViewModel)ViewModel; - private DispatcherTimer _debounceTimer; // 用于延迟更新 - private bool _isUpdating = false; // 防止重复更新 - - public ScriptNodeControl() - { - InitializeComponent(); - } - public ScriptNodeControl(ScriptNodeControlViewModel viewModel) : base(viewModel) - { - DataContext = viewModel; - InitializeComponent(); - -#if false - // 初始化定时器 - _debounceTimer = new DispatcherTimer(); - _debounceTimer.Interval = TimeSpan.FromMilliseconds(500); // 停止输入 500ms 后更新 - _debounceTimer.Tick += DebounceTimer_Tick; -#endif - } - - - - - /// - /// 入参控制点(可能有,可能没) - /// - JunctionControlBase INodeJunction.ExecuteJunction => this.ExecuteJunctionControl; - - /// - /// 下一个调用方法控制点(可能有,可能没) - /// - JunctionControlBase INodeJunction.NextStepJunction => this.NextStepJunctionControl; - - /// - /// 返回值控制点(可能有,可能没) - /// - JunctionControlBase INodeJunction.ReturnDataJunction => this.ResultJunctionControl; - - /// - /// 方法入参控制点(可能有,可能没) - /// - JunctionControlBase[] INodeJunction.ArgDataJunction - { - get - { - // 获取 MethodDetailsControl 实例 - var methodDetailsControl = this.MethodDetailsControl; - var itemsControl = FindVisualChild(methodDetailsControl); // 查找 ItemsControl - if (itemsControl != null) - { - var argDataJunction = new JunctionControlBase[base.ViewModel.NodeModel.MethodDetails.ParameterDetailss.Length]; - var controls = new List(); - - for (int i = 0; i < itemsControl.Items.Count; i++) - { - var container = itemsControl.ItemContainerGenerator.ContainerFromIndex(i) as FrameworkElement; - if (container != null) - { - var argControl = FindVisualChild(container); - if (argControl != null) - { - controls.Add(argControl); // 收集 ArgJunctionControl 实例 - } - } - } - return argDataJunction = controls.ToArray(); - } - else - { - return []; - } - } - - - } - - - - - - - - - - - - - -#if false - // 每次输入时重置定时器 - private void RichTextBox_TextChanged(object sender, TextChangedEventArgs e) - { - _debounceTimer.Stop(); - _debounceTimer.Start(); - } - - // 定时器事件,用户停止输入后触发 - private async void DebounceTimer_Tick(object sender, EventArgs e) - { - _debounceTimer.Stop(); - - if (_isUpdating) - return; - - // 开始后台处理语法分析和高亮 - _isUpdating = true; - await Task.Run(() => HighlightKeywordsAsync(viewModel.Script)); - } - - // 异步执行语法高亮操作 - private async Task HighlightKeywordsAsync(string text) - { - if (string.IsNullOrEmpty(text)) - { - return; - } - // 模拟语法分析和高亮(可以替换为实际逻辑) - var highlightedText = text; - - // 在 UI 线程中更新 RichTextBox 的内容 - await Dispatcher.BeginInvoke(() => - { - var range = new TextRange(richTextBox.Document.ContentStart, richTextBox.Document.ContentEnd); - range.Text = highlightedText; - }); - - _isUpdating = false; - } - -#endif - - - - - } -} diff --git a/Workbench/Node/ViewModel/ExpOpNodeControlViewModel.cs b/Workbench/Node/ViewModel/ExpOpNodeControlViewModel.cs deleted file mode 100644 index d9aaa08..0000000 --- a/Workbench/Node/ViewModel/ExpOpNodeControlViewModel.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Serein.NodeFlow.Model; -using Serein.Workbench.Node.View; - -namespace Serein.Workbench.Node.ViewModel -{ - public class ExpOpNodeControlViewModel: NodeControlViewModelBase - { - public new SingleExpOpNode NodeModel { get; } - - //public string Expression - //{ - // get => node.Expression; - // set - // { - // node.Expression = value; - // OnPropertyChanged(); - // } - //} - - - public ExpOpNodeControlViewModel(SingleExpOpNode nodeModel) : base(nodeModel) - { - this.NodeModel = nodeModel; - } - } -} diff --git a/Workbench/Node/ViewModel/GlobalDataNodeControlViewModel.cs b/Workbench/Node/ViewModel/GlobalDataNodeControlViewModel.cs deleted file mode 100644 index a396cba..0000000 --- a/Workbench/Node/ViewModel/GlobalDataNodeControlViewModel.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Serein.Library; -using Serein.NodeFlow.Model; -using Serein.Workbench.Node.View; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Input; - -namespace Serein.Workbench.Node.ViewModel -{ - public class GlobalDataNodeControlViewModel : NodeControlViewModelBase - { - private SingleGlobalDataNode NodeModel => (SingleGlobalDataNode)base.NodeModel; - - /// - /// 复制全局数据表达式 - /// - public ICommand CommandCopyDataExp { get; } - - /// - /// 刷新数据 - /// - public ICommand CommandRefreshData { get; } - - - public GlobalDataNodeControlViewModel(SingleGlobalDataNode node) : base(node) - { - CommandCopyDataExp = new RelayCommand( o => - { - string exp = NodeModel.KeyName; - string copyValue = $"@Get #{exp}#"; - Clipboard.SetDataObject(copyValue); - }); - } - - /// - /// 自定义参数值 - /// - public string? KeyName - { - get => NodeModel?.KeyName; - set { NodeModel.KeyName = value; OnPropertyChanged(); } - } - - - - } -} diff --git a/Workbench/Node/ViewModel/ScriptNodeControlViewModel.cs b/Workbench/Node/ViewModel/ScriptNodeControlViewModel.cs deleted file mode 100644 index 6b03113..0000000 --- a/Workbench/Node/ViewModel/ScriptNodeControlViewModel.cs +++ /dev/null @@ -1,62 +0,0 @@ -using Serein.Library; -using Serein.Library.Core; -using Serein.Library.Utils; -using Serein.NodeFlow.Model; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Input; - -namespace Serein.Workbench.Node.ViewModel -{ - public class ScriptNodeControlViewModel : NodeControlViewModelBase - { - private SingleScriptNode NodeModel => (SingleScriptNode)base.NodeModel; - - public string? Script - { - get => NodeModel?.Script; - set { NodeModel.Script = value; OnPropertyChanged(); } - } - - - - public ScriptNodeControlViewModel(NodeModelBase nodeModel) : base(nodeModel) - { - CommandExecuting = new RelayCommand(async o => - { - try - { - var result = await NodeModel.ExecutingAsync(new DynamicContext(nodeModel.Env)); - SereinEnv.WriteLine(InfoType.INFO, result?.ToString()); - } - catch (Exception ex) - { - SereinEnv.WriteLine(InfoType.ERROR, ex.ToString()); - } - }); - - CommandLoadScript = new RelayCommand( o => - { - NodeModel.ReloadScript(); - }); - } - - - /// - /// 加载脚本代码 - /// - public ICommand CommandLoadScript{ get; } - - /// - /// 尝试执行 - /// - public ICommand CommandExecuting { get; } - - - - } -} diff --git a/Workbench/Properties/launchSettings.json b/Workbench/Properties/launchSettings.json deleted file mode 100644 index f8eb472..0000000 --- a/Workbench/Properties/launchSettings.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "profiles": { - "Serein.Workbench": { - "commandName": "Project" - } - } -} \ No newline at end of file diff --git a/Workbench/Serein.Workbench_wjzi1sgn_wpftmp.csproj b/Workbench/Serein.Workbench_wjzi1sgn_wpftmp.csproj deleted file mode 100644 index 4810142..0000000 --- a/Workbench/Serein.Workbench_wjzi1sgn_wpftmp.csproj +++ /dev/null @@ -1,292 +0,0 @@ - - - Serein.Workbench - obj\Release\ - obj\ - D:\Project\C#\DynamicControl\SereinFlow\WorkBench\obj\ - <_TargetAssemblyProjectName>Serein.Workbench - Serein.Workbench - - - - WinExe - net8.0-windows - enable - enable - True - D:\Project\C#\DynamicControl\SereinFlow\.Output - MIT - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Code - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Workbench/Themes/BindableRichTextBox.cs b/Workbench/Themes/BindableRichTextBox.cs deleted file mode 100644 index f7c9d1e..0000000 --- a/Workbench/Themes/BindableRichTextBox.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Controls; -using System.Windows.Documents; -using System.Windows; - -namespace Serein.Workbench.Themes -{ - public partial class BindableRichTextBox : RichTextBox - { - public new FlowDocument Document - { - get { return (FlowDocument)GetValue(DocumentProperty); } - set { SetValue(DocumentProperty, value); } - } - // Using a DependencyProperty as the backing store for Document. This enables animation, styling, binding, etc... - public static readonly DependencyProperty DocumentProperty = - DependencyProperty.Register("Document", typeof(FlowDocument), typeof(BindableRichTextBox), new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnDucumentChanged))); - private static void OnDucumentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - RichTextBox rtb = (RichTextBox)d; - rtb.Document = (FlowDocument)e.NewValue; - } - } -} diff --git a/Workbench/Tool/GuidReplacer.cs b/Workbench/Tool/GuidReplacer.cs deleted file mode 100644 index eb2cf77..0000000 --- a/Workbench/Tool/GuidReplacer.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Serein.Workbench.Tool -{ - /// - /// Guid替换工具类 - /// - public class GuidReplacer - { - private class TrieNode - { - public Dictionary Children = new(); - public string Replacement; // 替换后的值 - } - - private readonly TrieNode _root = new(); - - // 构建字典树 - public void AddReplacement(string guid, string replacement) - { - var current = _root; - foreach (var c in guid) - { - if (!current.Children.ContainsKey(c)) - { - current.Children[c] = new TrieNode(); - } - current = current.Children[c]; - } - current.Replacement = replacement; - } - - // 替换逻辑 - public string Replace(string input) - { - var result = new StringBuilder(); - var current = _root; - int i = 0; - - while (i < input.Length) - { - if (current.Children.ContainsKey(input[i])) - { - current = current.Children[input[i]]; - i++; - - if (current.Replacement != null) // 找到匹配 - { - result.Append(current.Replacement); - current = _root; // 回到根节点 - } - } - else - { - result.Append(input[i]); - current = _root; // 未匹配,回到根节点 - i++; - } - } - return result.ToString(); - } - } - -}