From 181acff16bbec617861e38626c7a338315ce86e0 Mon Sep 17 00:00:00 2001 From: fengjiayi <12821976+ning_xi@user.noreply.gitee.com> Date: Mon, 9 Sep 2024 21:06:47 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8F=96=E6=B6=88=E7=BC=A9=E6=94=BE=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=EF=BC=88=E6=9C=89=E9=97=AE=E9=A2=98=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .editorconfig | 118 ++++++++++++++++++++++++++++++ NodeFlow/Tool/TcsSignal.cs | 57 +++++---------- WorkBench/MainWindow.xaml | 23 +++--- WorkBench/MainWindow.xaml.cs | 136 +++++++++++++++++++++++++---------- 4 files changed, 245 insertions(+), 89 deletions(-) diff --git a/.editorconfig b/.editorconfig index 091dadd..cc2dc64 100644 --- a/.editorconfig +++ b/.editorconfig @@ -2,3 +2,121 @@ # CS8618: 在退出构造函数时,不可为 null 的字段必须包含非 null 值。请考虑声明为可以为 null。 dotnet_diagnostic.CS8618.severity = warning + +[*.cs] +#### 命名样式 #### + +# 命名规则 + +dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i + +dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.types_should_be_pascal_case.symbols = types +dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case + +# 符号规范 + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types.required_modifiers = + +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.non_field_members.required_modifiers = + +# 命名样式 + +dotnet_naming_style.begins_with_i.required_prefix = I +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case +csharp_using_directive_placement = outside_namespace:silent +csharp_style_expression_bodied_methods = false:silent +csharp_style_expression_bodied_constructors = false:silent +csharp_style_expression_bodied_operators = false:silent +csharp_style_expression_bodied_properties = true:silent +csharp_style_expression_bodied_indexers = true:silent +csharp_style_expression_bodied_accessors = true:silent +csharp_style_expression_bodied_lambdas = true:silent +csharp_style_expression_bodied_local_functions = false:silent +csharp_style_conditional_delegate_call = true:suggestion +csharp_space_around_binary_operators = before_and_after +csharp_indent_labels = one_less_than_current + +[*.vb] +#### 命名样式 #### + +# 命名规则 + +dotnet_naming_rule.interface_should_be_以_i_开始.severity = suggestion +dotnet_naming_rule.interface_should_be_以_i_开始.symbols = interface +dotnet_naming_rule.interface_should_be_以_i_开始.style = 以_i_开始 + +dotnet_naming_rule.类型_should_be_帕斯卡拼写法.severity = suggestion +dotnet_naming_rule.类型_should_be_帕斯卡拼写法.symbols = 类型 +dotnet_naming_rule.类型_should_be_帕斯卡拼写法.style = 帕斯卡拼写法 + +dotnet_naming_rule.非字段成员_should_be_帕斯卡拼写法.severity = suggestion +dotnet_naming_rule.非字段成员_should_be_帕斯卡拼写法.symbols = 非字段成员 +dotnet_naming_rule.非字段成员_should_be_帕斯卡拼写法.style = 帕斯卡拼写法 + +# 符号规范 + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.类型.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.类型.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected +dotnet_naming_symbols.类型.required_modifiers = + +dotnet_naming_symbols.非字段成员.applicable_kinds = property, event, method +dotnet_naming_symbols.非字段成员.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected +dotnet_naming_symbols.非字段成员.required_modifiers = + +# 命名样式 + +dotnet_naming_style.以_i_开始.required_prefix = I +dotnet_naming_style.以_i_开始.required_suffix = +dotnet_naming_style.以_i_开始.word_separator = +dotnet_naming_style.以_i_开始.capitalization = pascal_case + +dotnet_naming_style.帕斯卡拼写法.required_prefix = +dotnet_naming_style.帕斯卡拼写法.required_suffix = +dotnet_naming_style.帕斯卡拼写法.word_separator = +dotnet_naming_style.帕斯卡拼写法.capitalization = pascal_case + +dotnet_naming_style.帕斯卡拼写法.required_prefix = +dotnet_naming_style.帕斯卡拼写法.required_suffix = +dotnet_naming_style.帕斯卡拼写法.word_separator = +dotnet_naming_style.帕斯卡拼写法.capitalization = pascal_case + +[*.{cs,vb}] +end_of_line = crlf +dotnet_style_qualification_for_field = false:silent +dotnet_style_qualification_for_property = false:silent +dotnet_style_qualification_for_method = false:silent +dotnet_style_qualification_for_event = false:silent +indent_size = 4 +tab_width = 4 +dotnet_style_operator_placement_when_wrapping = beginning_of_line \ No newline at end of file diff --git a/NodeFlow/Tool/TcsSignal.cs b/NodeFlow/Tool/TcsSignal.cs index 1678906..bee7f2d 100644 --- a/NodeFlow/Tool/TcsSignal.cs +++ b/NodeFlow/Tool/TcsSignal.cs @@ -15,68 +15,43 @@ namespace Serein.NodeFlow.Tool public class TcsSignal where TSignal : struct, Enum { + //public ConcurrentDictionary>> TcsEvent { get; } = new(); + public ConcurrentDictionary> TcsEvent { get; } = new(); + public ConcurrentDictionary TcsValue { get; } = new(); - public ConcurrentDictionary>> TcsEvent { get; } = new(); - - // public object tcsObj = new object(); - - public bool TriggerSignal(TSignal signal, T state) + /// + /// 触发信号 + /// + /// + /// 信号 + /// 传递的参数 + /// 是否成功触发 + public bool TriggerSignal(TSignal signal, T value) { - if (TcsEvent.TryRemove(signal, out var waitTcss)) + if (TcsEvent.TryRemove(signal, out var waitTcs)) { - while (waitTcss.Count > 0) - { - - waitTcss.Pop().SetResult(state); - - } + waitTcs.SetResult(value); return true; } return false; - - } public TaskCompletionSource CreateTcs(TSignal signal) { - - var tcs = new TaskCompletionSource(); - TcsEvent.GetOrAdd(signal, _ => new Stack>()).Push(tcs); + var tcs = TcsEvent.GetOrAdd(signal,_ = new TaskCompletionSource()); return tcs; - - - } - //public TaskCompletionSource GetOrCreateTcs(TSignal signal) - //{ - // lock (tcsObj) - // { - // var tcs = TcsEvent.GetOrAdd(signal, _ => new TaskCompletionSource()); - // if (tcs.Task.IsCompleted) - // { - // TcsEvent.TryRemove(signal, out _); - // tcs = new TaskCompletionSource(); - // TcsEvent[signal] = tcs; - // } - // return tcs; - // } - //} public void CancelTask() { lock (TcsEvent) { - - foreach (var tcss in TcsEvent.Values) + foreach (var tcs in TcsEvent.Values) { - while (tcss.Count > 0) - { - tcss.Pop().SetException(new TcsSignalException("Task Cancel")); - } + tcs.SetException(new TcsSignalException("任务取消")); } TcsEvent.Clear(); } } - } } diff --git a/WorkBench/MainWindow.xaml b/WorkBench/MainWindow.xaml index 83e8212..21d9c10 100644 --- a/WorkBench/MainWindow.xaml +++ b/WorkBench/MainWindow.xaml @@ -5,6 +5,7 @@ xmlns:custom="clr-namespace:Serein.WorkBench.Node.View" Title="Dynamic Node Flow" Height="700" Width="1200" AllowDrop="True" Drop="Window_Drop" DragOver="Window_DragOver" + SizeChanged ="Window_SizeChanged" Loaded="Window_Loaded" Closing="Window_Closing"> @@ -77,17 +78,19 @@ x:Name="FlowChartScrollViewer" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"> - - + + + diff --git a/WorkBench/MainWindow.xaml.cs b/WorkBench/MainWindow.xaml.cs index 9e3aaee..b0792c1 100644 --- a/WorkBench/MainWindow.xaml.cs +++ b/WorkBench/MainWindow.xaml.cs @@ -1294,8 +1294,9 @@ namespace Serein.WorkBench if (e.MiddleButton == MouseButtonState.Pressed) { IsCanvasDragging = true; - startPoint = e.GetPosition(this); + startPoint = e.GetPosition(FlowChartScrollViewer); FlowChartCanvas.CaptureMouse(); + e.Handled = true; // 防止事件传播影响其他控件 } } @@ -1305,80 +1306,131 @@ namespace Serein.WorkBench { IsCanvasDragging = false; FlowChartCanvas.ReleaseMouseCapture(); - - foreach(var line in connections) - { - line.Refresh(); - } } } + // 缩放功能有问题 private void FlowChartCanvas_MouseWheel(object sender, MouseWheelEventArgs e) { if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) { - double scale = e.Delta > 0 ? 1.1 : 0.9; - scaleTransform.ScaleX *= scale; - scaleTransform.ScaleY *= scale; + //double scale = e.Delta > 0 ? 0.1 : -0.1; + //scaleTransform.ScaleX += scale; + //scaleTransform.ScaleY += scale; + //AdjustCanvasSize(); + + + //double zoomFactor = e.Delta > 0 ? 1.1 : 0.9; + + //// 获取鼠标相对于Canvas的位置 + //Point mousePosition = e.GetPosition(FlowChartCanvas); + + //// 计算缩放后的Canvas中心位置 + //double absoluteX = mousePosition.X * scaleTransform.ScaleX; + //double absoluteY = mousePosition.Y * scaleTransform.ScaleY; + + //// 应用缩放 + //scaleTransform.ScaleX *= zoomFactor; + //scaleTransform.ScaleY *= zoomFactor; + + //// 平移,使缩放中心保持在鼠标光标处 + //translateTransform.X = mousePosition.X - absoluteX * zoomFactor; + //translateTransform.Y = mousePosition.Y - absoluteY * zoomFactor; + + // 调整画布大小,使其始终占据整个容器 + //AdjustCanvasSizeToContainer(); } } + + private void AdjustCanvasSizeToContainer() + { + // 获取当前缩放后的画布大小 + double newWidth = FlowChartCanvas.Width * scaleTransform.ScaleX; + double newHeight = FlowChartCanvas.Height * scaleTransform.ScaleY; + + // 设置画布大小,使其至少与ScrollViewer的可视区域大小相同 + FlowChartCanvas.Width = Math.Max(FlowChartScrollViewer.Width, newWidth); + FlowChartCanvas.Height = Math.Max(FlowChartScrollViewer.Height, newHeight); + } + + private void AdjustCanvasSize() + { + // 获取 ScrollViewer 可视区域的宽度和高度 + double scrollViewerWidth = FlowChartScrollViewer.Width * scaleTransform.ScaleX; + double scrollViewerHeight = FlowChartScrollViewer.Height * scaleTransform.ScaleY; + + // 调整 Canvas 大小 + if (scrollViewerWidth > 0 && scrollViewerHeight > 0) + { + FlowChartCanvas.Width = scrollViewerWidth; + FlowChartCanvas.Height = scrollViewerHeight; + } + } + + private void AdjustCanvasSizeAndContent(double deltaX, double deltaY) { - var myCanvas = FlowChartCanvas; - + // 获取画布的边界框 - Rect transformedBounds = myCanvas.RenderTransform.TransformBounds(new Rect(myCanvas.RenderSize)); + Rect transformedBounds = FlowChartCanvas.RenderTransform.TransformBounds(new Rect(FlowChartCanvas.RenderSize)); + // Debug.Print($" {FlowChartScrollViewer.ActualWidth} / {FlowChartScrollViewer.ActualHeight} -- {transformedBounds.Right} / {transformedBounds.Bottom}"); + // Debug.Print($" {transformedBounds.Left} / {transformedBounds.Top} -- {deltaX} / {deltaY}"); + + + // 检查画布的左边缘是否超出视图 - if (transformedBounds.Left > 0) + if (deltaX > 0 && transformedBounds.Left > 0) { double offsetX = transformedBounds.Left; - myCanvas.Width += offsetX; + FlowChartCanvas.Width += offsetX; translateTransform.X -= offsetX; + Debug.Print($" offsetX : {offsetX}"); // 移动所有控件的位置 - foreach (UIElement child in myCanvas.Children) + foreach (UIElement child in FlowChartCanvas.Children) { Canvas.SetLeft(child, Canvas.GetLeft(child) + offsetX); } } // 检查画布的上边缘是否超出视图 - if (transformedBounds.Top > 0) + //if (transformedBounds.Top > 0) + if (deltaY > 0 & transformedBounds.Top > 0) { double offsetY = transformedBounds.Top; - myCanvas.Height += offsetY; + FlowChartCanvas.Height += offsetY; translateTransform.Y -= offsetY; + Debug.Print($" offsetY : {offsetY}"); // 移动所有控件的位置 - foreach (UIElement child in myCanvas.Children) + foreach (UIElement child in FlowChartCanvas.Children) { Canvas.SetTop(child, Canvas.GetTop(child) + offsetY); } } - //Debug.Print($" {FlowChartScrollViewer.ActualWidth} / {FlowChartScrollViewer.ActualHeight} -- {transformedBounds.Right} / {transformedBounds.Bottom}"); - var size = 50; // 检查画布的右边缘是否超出当前宽度 - if (transformedBounds.Right + size < FlowChartScrollViewer.ActualWidth) + if ( transformedBounds.Right + size < FlowChartScrollViewer.ActualWidth) { double extraWidth = FlowChartScrollViewer.ActualWidth - transformedBounds.Right; - FlowChartCanvas.Width += extraWidth; + this.FlowChartCanvas.Width += extraWidth; } // 检查画布的下边缘是否超出当前高度 if (transformedBounds.Bottom + size < FlowChartScrollViewer.ActualHeight) { double extraHeight = FlowChartScrollViewer.ActualHeight - transformedBounds.Bottom; - FlowChartCanvas.Height += extraHeight; + this.FlowChartCanvas.Height += extraHeight; } } + #endregion /// @@ -1398,10 +1450,9 @@ namespace Serein.WorkBench currentLine.X2 = position.X; currentLine.Y2 = position.Y; } - if (IsCanvasDragging) { - Point currentMousePosition = e.GetPosition(this); + Point currentMousePosition = e.GetPosition(FlowChartScrollViewer); double deltaX = currentMousePosition.X - startPoint.X; double deltaY = currentMousePosition.Y - startPoint.Y; @@ -1410,9 +1461,15 @@ namespace Serein.WorkBench startPoint = currentMousePosition; - // Adjust canvas size and content if necessary AdjustCanvasSizeAndContent(deltaX, deltaY); + foreach (var line in connections) + { + line.Refresh(); + } + + e.Handled = true; // 防止事件传播影响其他控件 } + } /// @@ -1550,19 +1607,19 @@ namespace Serein.WorkBench /// private void FlowChartScrollViewer_SizeChanged(object sender, SizeChangedEventArgs e) { - // 确保 FlowChartCanvas 的最小尺寸等于 ScrollViewer 的可见尺寸 - var scrollViewerViewportWidth = FlowChartScrollViewer.ViewportWidth; - var scrollViewerViewportHeight = FlowChartScrollViewer.ViewportHeight; + //// 确保 FlowChartCanvas 的最小尺寸等于 ScrollViewer 的可见尺寸 + //var scrollViewerViewportWidth = FlowChartScrollViewer.ViewportWidth; + //var scrollViewerViewportHeight = FlowChartScrollViewer.ViewportHeight; - if (FlowChartCanvas.Width < scrollViewerViewportWidth) - { - FlowChartCanvas.Width = scrollViewerViewportWidth; - } + //if (FlowChartCanvas.Width < scrollViewerViewportWidth) + //{ + // FlowChartCanvas.Width = scrollViewerViewportWidth; + //} - if (FlowChartCanvas.Height < scrollViewerViewportHeight) - { - FlowChartCanvas.Height = scrollViewerViewportHeight; - } + //if (FlowChartCanvas.Height < scrollViewerViewportHeight) + //{ + // FlowChartCanvas.Height = scrollViewerViewportHeight; + //} } @@ -2124,7 +2181,10 @@ namespace Serein.WorkBench return Uri.UnescapeDataString(relativeUri.ToString().Replace('/', System.IO.Path.DirectorySeparatorChar)); } - + private void Window_SizeChanged(object sender, SizeChangedEventArgs e) + { + AdjustCanvasSize(); + } } #region 创建两个控件之间的连接关系,在UI层面上显示为 带箭头指向的贝塞尔曲线