From 9bb6c6d32102ed2d57c5639268604b2492533b60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=89=BE=E7=AB=B9?= Date: Thu, 26 Jan 2023 18:27:17 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AE=AD=E5=A4=B4=E5=88=86=E7=A6=BB=E5=88=B0?= =?UTF-8?q?=E7=8B=AC=E7=AB=8B=E7=9A=84model=E4=B8=AD=EF=BC=8C=E6=96=B9?= =?UTF-8?q?=E4=BE=BF=E8=87=AA=E5=AE=9A=E4=B9=89path?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AIStudio.Wpf.DiagramApp.csproj | 7 +- .../DesignItems/Customs/1.json | 102 --------- .../ViewModels/DiagramsViewModel.cs | 11 + .../ViewModels/MainWindowViewModel.cs | 11 + AIStudio.Wpf.DiagramApp/Views/MainWindow.xaml | 10 +- .../AIStudio.Wpf.DiagramDesigner.Demo.csproj | 2 +- .../ViewModels/Links/LabelsViewModel.cs | 66 ++++++ .../ViewModels/Links/MarkersViewModel.cs | 59 +++++ .../ReconnectLinksToClosestPortsViewModel.cs | 47 ++++ .../ViewModels/ZoomViewModel.cs | 38 ++++ .../ReconnectLinksToClosestPortsView.xaml | 17 ++ .../ReconnectLinksToClosestPortsView.xaml.cs | 26 +++ .../Views/Links/LabelsView.xaml | 16 ++ .../Views/Links/LabelsView.xaml.cs | 26 +++ .../Views/Links/MarkersView.xaml | 16 ++ .../Views/Links/MarkersView.xaml.cs | 26 +++ .../Views/ZoomView.xaml | 29 +++ .../Views/ZoomView.xaml.cs | 26 +++ .../Algorithms/LinksReconnectionAlgorithms.cs | 61 ++++++ .../Enums/ArrowPathStyle.cs | 3 +- .../Helpers/CopyHelper.cs | 16 ++ .../Serializables/SelectableItemBase.cs | 84 ++++++-- .../PathGenerators/PathGenerators.Boundary.cs | 4 +- .../PathGenerators/PathGenerators.Corner.cs | 4 +- .../PathGenerators/PathGenerators.Smooth.cs | 8 +- .../PathGenerators/PathGenerators.Straight.cs | 4 +- .../UserControls/LineControl.xaml | 12 +- .../AdditionViewModel/ColorViewModel.cs | 82 +------ .../DiagramServicesProvider.cs | 52 +++-- .../{ => Interface}/IColorViewModel.cs | 25 +-- .../Interface/IDiagramServiceProvider.cs | 45 ++++ .../{ => Interface}/IDrawModeViewModel.cs | 0 .../{ => Interface}/IFontViewModel.cs | 0 .../{ => Interface}/ILockObjectViewModel.cs | 0 .../{ => Interface}/IQuickThemeViewModel.cs | 0 .../Interface/IShapeViewModel.cs | 24 +++ .../AdditionViewModel/ShapeViewModel.cs | 201 ++++++++++++++++++ .../BaseViewModel/ConnectionViewModel.cs | 69 ++++-- .../Connector/ConnectorLabelModel.cs | 3 + .../BaseViewModel/DiagramViewModel.cs | 10 + .../BaseViewModel/SelectableViewModelBase.cs | 42 +++- .../ViewModels/IDiagramViewModel.cs | 8 + 42 files changed, 993 insertions(+), 299 deletions(-) delete mode 100644 AIStudio.Wpf.DiagramApp/DesignItems/Customs/1.json create mode 100644 AIStudio.Wpf.DiagramDesigner.Demo/ViewModels/Links/LabelsViewModel.cs create mode 100644 AIStudio.Wpf.DiagramDesigner.Demo/ViewModels/Links/MarkersViewModel.cs create mode 100644 AIStudio.Wpf.DiagramDesigner.Demo/ViewModels/ReconnectLinksToClosestPortsViewModel.cs create mode 100644 AIStudio.Wpf.DiagramDesigner.Demo/ViewModels/ZoomViewModel.cs create mode 100644 AIStudio.Wpf.DiagramDesigner.Demo/Views/Animations/ReconnectLinksToClosestPortsView.xaml create mode 100644 AIStudio.Wpf.DiagramDesigner.Demo/Views/Animations/ReconnectLinksToClosestPortsView.xaml.cs create mode 100644 AIStudio.Wpf.DiagramDesigner.Demo/Views/Links/LabelsView.xaml create mode 100644 AIStudio.Wpf.DiagramDesigner.Demo/Views/Links/LabelsView.xaml.cs create mode 100644 AIStudio.Wpf.DiagramDesigner.Demo/Views/Links/MarkersView.xaml create mode 100644 AIStudio.Wpf.DiagramDesigner.Demo/Views/Links/MarkersView.xaml.cs create mode 100644 AIStudio.Wpf.DiagramDesigner.Demo/Views/ZoomView.xaml create mode 100644 AIStudio.Wpf.DiagramDesigner.Demo/Views/ZoomView.xaml.cs create mode 100644 AIStudio.Wpf.DiagramDesigner/Algorithms/LinksReconnectionAlgorithms.cs rename AIStudio.Wpf.DiagramDesigner/ViewModels/AdditionViewModel/{ => Interface}/IColorViewModel.cs (60%) create mode 100644 AIStudio.Wpf.DiagramDesigner/ViewModels/AdditionViewModel/Interface/IDiagramServiceProvider.cs rename AIStudio.Wpf.DiagramDesigner/ViewModels/AdditionViewModel/{ => Interface}/IDrawModeViewModel.cs (100%) rename AIStudio.Wpf.DiagramDesigner/ViewModels/AdditionViewModel/{ => Interface}/IFontViewModel.cs (100%) rename AIStudio.Wpf.DiagramDesigner/ViewModels/AdditionViewModel/{ => Interface}/ILockObjectViewModel.cs (100%) rename AIStudio.Wpf.DiagramDesigner/ViewModels/AdditionViewModel/{ => Interface}/IQuickThemeViewModel.cs (100%) create mode 100644 AIStudio.Wpf.DiagramDesigner/ViewModels/AdditionViewModel/Interface/IShapeViewModel.cs create mode 100644 AIStudio.Wpf.DiagramDesigner/ViewModels/AdditionViewModel/ShapeViewModel.cs diff --git a/AIStudio.Wpf.DiagramApp/AIStudio.Wpf.DiagramApp.csproj b/AIStudio.Wpf.DiagramApp/AIStudio.Wpf.DiagramApp.csproj index e1a927f..a1bb605 100644 --- a/AIStudio.Wpf.DiagramApp/AIStudio.Wpf.DiagramApp.csproj +++ b/AIStudio.Wpf.DiagramApp/AIStudio.Wpf.DiagramApp.csproj @@ -231,9 +231,6 @@ - - PreserveNewest - PreserveNewest @@ -877,6 +874,10 @@ PreserveNewest + + + + 8.0 diff --git a/AIStudio.Wpf.DiagramApp/DesignItems/Customs/1.json b/AIStudio.Wpf.DiagramApp/DesignItems/Customs/1.json deleted file mode 100644 index 75e975d..0000000 --- a/AIStudio.Wpf.DiagramApp/DesignItems/Customs/1.json +++ /dev/null @@ -1,102 +0,0 @@ -{ - "Title": null, - "DiagramType": 0, - "DiagramItems": [ - { - "Name": null, - "DiagramType": 0, - "DesignerItems": [ - ], - "PersistDesignerItems": [ - ], - "SettingsDesignerItems": [ - ], - "PathDesignerItems": [ - { - "Left": 132.80000000000007, - "Top": 101.26000022888184, - "ScaleX": 1, - "ScaleY": 1, - "Margin": 0.0, - "ItemWidth": 65.0, - "ItemHeight": 65.0, - "Icon": "M 0,0 H 60 V 40 C 30,30 30,50 0,40 Z", - "ItemTypeName": "AIStudio.Wpf.DiagramDesigner.Additionals.Extensions.ViewModels.PathItemViewModel", - "Id": "da395032-ad9e-4dab-a035-f59bed5cb4c4", - "ZIndex": 0, - "IsGroup": false, - "ParentId": "00000000-0000-0000-0000-000000000000", - "Text": "欢迎来到AIStudio画板", - "ColorItem": { - "LineColor": { - "BrushType": 1, - "Color": "#FF808080", - "GradientStop": null, - "Offset": null, - "Image": null, - "SubType": 0, - "StartPoint": "0,0", - "EndPoint": "0,0", - "Opacity": 1.0, - "LinearOrientation": 0, - "RadialOrientation": 0, - "Angle": 0 - }, - "FillColor": { - "BrushType": 1, - "Color": "#FFFFA500", - "GradientStop": null, - "Offset": null, - "Image": null, - "SubType": 0, - "StartPoint": "0,0", - "EndPoint": "0,0", - "Opacity": 1.0, - "LinearOrientation": 0, - "RadialOrientation": 0, - "Angle": 0 - }, - "ShadowColor": "#00FFFFFF", - "LineWidth": 1.0, - "LeftArrowPathStyle": 0, - "RightArrowPathStyle": 1, - "LeftArrowSizeStyle": 10, - "RightArrowSizeStyle": 10 - }, - "FontItem": { - "FontWeight": "Normal", - "FontStyle": "Normal", - "FontStretch": "Normal", - "Underline": false, - "Strikethrough": false, - "OverLine": false, - "FontColor": "#FF000000", - "FontFamily": "Arial", - "FontSize": 11.0, - "FontObject": "Arial, 11pt", - "TextEffectColor": "#00FFFFFF", - "HighlightColor": "#00FFFFFF", - "FontCase": 0, - "HorizontalAlignment": 1, - "VerticalAlignment": 1, - "LineHeight": 0.0 - } - } - ], - "MediaDesignerItems": [ - ], - "ImageDesignerItems": [ - ], - "TextDesignerItems": [ - ], - "LogicalGateItems": [ - ], - "FlowNodeDesignerItems": [ - ], - "ConnectionIds": [ - ], - "Connections": [ - ] - } - ] -} \ No newline at end of file diff --git a/AIStudio.Wpf.DiagramApp/ViewModels/DiagramsViewModel.cs b/AIStudio.Wpf.DiagramApp/ViewModels/DiagramsViewModel.cs index d46b6e5..705fd32 100644 --- a/AIStudio.Wpf.DiagramApp/ViewModels/DiagramsViewModel.cs +++ b/AIStudio.Wpf.DiagramApp/ViewModels/DiagramsViewModel.cs @@ -436,6 +436,17 @@ namespace AIStudio.Wpf.DiagramApp.ViewModels } } + public void SetSharp(IShapeViewModel shapeViewModel, string propertyName) + { + foreach (var item in DiagramViewModel.SelectedItems) + { + if (item.ShapeViewModel != shapeViewModel) + { + CopyHelper.CopyPropertyValue(shapeViewModel, item.ShapeViewModel, propertyName); + } + } + } + public void SetQuickItem(IQuickThemeViewModel quickThemeViewModel, string propertyName) { if (propertyName == nameof(QuickTheme) && quickThemeViewModel.QuickTheme != null) diff --git a/AIStudio.Wpf.DiagramApp/ViewModels/MainWindowViewModel.cs b/AIStudio.Wpf.DiagramApp/ViewModels/MainWindowViewModel.cs index 2ce1657..5038ee2 100644 --- a/AIStudio.Wpf.DiagramApp/ViewModels/MainWindowViewModel.cs +++ b/AIStudio.Wpf.DiagramApp/ViewModels/MainWindowViewModel.cs @@ -140,6 +140,13 @@ namespace AIStudio.Wpf.DiagramApp.ViewModels return _service.ColorViewModel; } } + public IShapeViewModel ShapeViewModel + { + get + { + return _service.ShapeViewModel; + } + } public IQuickThemeViewModel QuickThemeViewModel { get @@ -677,6 +684,7 @@ namespace AIStudio.Wpf.DiagramApp.ViewModels if (e.PropertyName == nameof(DrawModeViewModel) || e.PropertyName == nameof(FontViewModel) || e.PropertyName == nameof(ColorViewModel) + || e.PropertyName == nameof(ShapeViewModel) || e.PropertyName == nameof(QuickThemeViewModel) || e.PropertyName == nameof(LockObjectViewModel) || e.PropertyName == nameof(SelectedItem)) @@ -692,6 +700,9 @@ namespace AIStudio.Wpf.DiagramApp.ViewModels if (sender is IColorViewModel) DiagramsViewModel.SetColor(sender as IColorViewModel, e.PropertyName); + if (sender is IShapeViewModel) + DiagramsViewModel.SetSharp(sender as IShapeViewModel, e.PropertyName); + if (sender is IQuickThemeViewModel) DiagramsViewModel.SetQuickItem(sender as IQuickThemeViewModel, e.PropertyName); diff --git a/AIStudio.Wpf.DiagramApp/Views/MainWindow.xaml b/AIStudio.Wpf.DiagramApp/Views/MainWindow.xaml index 4305720..f3827c3 100644 --- a/AIStudio.Wpf.DiagramApp/Views/MainWindow.xaml +++ b/AIStudio.Wpf.DiagramApp/Views/MainWindow.xaml @@ -1141,7 +1141,7 @@ - + @@ -1167,8 +1167,8 @@ - - + + @@ -1205,14 +1205,14 @@ - + - + diff --git a/AIStudio.Wpf.DiagramDesigner.Demo/AIStudio.Wpf.DiagramDesigner.Demo.csproj b/AIStudio.Wpf.DiagramDesigner.Demo/AIStudio.Wpf.DiagramDesigner.Demo.csproj index 0144991..ade4264 100644 --- a/AIStudio.Wpf.DiagramDesigner.Demo/AIStudio.Wpf.DiagramDesigner.Demo.csproj +++ b/AIStudio.Wpf.DiagramDesigner.Demo/AIStudio.Wpf.DiagramDesigner.Demo.csproj @@ -11,7 +11,7 @@ - + diff --git a/AIStudio.Wpf.DiagramDesigner.Demo/ViewModels/Links/LabelsViewModel.cs b/AIStudio.Wpf.DiagramDesigner.Demo/ViewModels/Links/LabelsViewModel.cs new file mode 100644 index 0000000..9dead39 --- /dev/null +++ b/AIStudio.Wpf.DiagramDesigner.Demo/ViewModels/Links/LabelsViewModel.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows; + +namespace AIStudio.Wpf.DiagramDesigner.Demo.ViewModels +{ + class LabelsViewModel : BaseViewModel + { + public LabelsViewModel() + { + Title = "Link Labels"; + Info = "Labels help you show more information through out a link. You can specify a distance or an offset." + + "The content of the labels is still limited because of Blazor's poor SVG support."; + + _service.ColorViewModel.FillColor.Color = System.Windows.Media.Colors.Orange; + + DiagramViewModel = new DiagramViewModel(); + DiagramViewModel.PageSizeType = PageSizeType.Custom; + DiagramViewModel.PageSize = new Size(double.NaN, double.NaN); + + DefaultDesignerItemViewModel node1 = new DefaultDesignerItemViewModel() { Left = 50, Top = 50 }; + DiagramViewModel.DirectAddItemCommand.Execute(node1); + + DefaultDesignerItemViewModel node2 = new DefaultDesignerItemViewModel() { Left = 400, Top = 50 }; + DiagramViewModel.DirectAddItemCommand.Execute(node2); + + ConnectionViewModel connector1 = new ConnectionViewModel(node1.RightConnector, node2.LeftConnector); + connector1.AddLabel("Content"); + DiagramViewModel.DirectAddItemCommand.Execute(connector1); + + node1 = new DefaultDesignerItemViewModel() { Left = 50, Top = 160, Text = "1" }; + DiagramViewModel.DirectAddItemCommand.Execute(node1); + + node2 = new DefaultDesignerItemViewModel() { Left = 400, Top = 160, Text = "2" }; + DiagramViewModel.DirectAddItemCommand.Execute(node2); + + connector1 = new ConnectionViewModel(node1.RightConnector, node2.LeftConnector); + connector1.AddLabel("0.25", 0.3); + connector1.AddLabel("0.75", 0.7); + DiagramViewModel.DirectAddItemCommand.Execute(connector1); + + node1 = new DefaultDesignerItemViewModel() { Left = 50, Top = 270, Text = "1" }; + DiagramViewModel.DirectAddItemCommand.Execute(node1); + + node2 = new DefaultDesignerItemViewModel() { Left = 400, Top = 270, Text = "2" }; + DiagramViewModel.DirectAddItemCommand.Execute(node2); + + connector1 = new ConnectionViewModel(node1.RightConnector, node2.LeftConnector); + connector1.AddLabel("50", 50); + connector1.AddLabel("-50", -50); + DiagramViewModel.DirectAddItemCommand.Execute(connector1); + + node1 = new DefaultDesignerItemViewModel() { Left = 50, Top = 380, Text = "1" }; + DiagramViewModel.DirectAddItemCommand.Execute(node1); + + node2 = new DefaultDesignerItemViewModel() { Left = 400, Top = 380, Text = "2" }; + DiagramViewModel.DirectAddItemCommand.Execute(node2); + + connector1 = new ConnectionViewModel(node1.RightConnector, node2.LeftConnector); + connector1.AddLabel("(0,-20)", 50, new Point(0, -20)); + connector1.AddLabel("(0,20)", -50, new Point(0, 20)); + DiagramViewModel.DirectAddItemCommand.Execute(connector1); + } + } +} diff --git a/AIStudio.Wpf.DiagramDesigner.Demo/ViewModels/Links/MarkersViewModel.cs b/AIStudio.Wpf.DiagramDesigner.Demo/ViewModels/Links/MarkersViewModel.cs new file mode 100644 index 0000000..df7e37a --- /dev/null +++ b/AIStudio.Wpf.DiagramDesigner.Demo/ViewModels/Links/MarkersViewModel.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows; + +namespace AIStudio.Wpf.DiagramDesigner.Demo.ViewModels +{ + class MarkersViewModel : BaseViewModel + { + public MarkersViewModel() + { + Title = "Link Markers"; + Info = "Markers are SVG Paths that you can put at the beginning or at the end of your links."; + + _service.ColorViewModel.FillColor.Color = System.Windows.Media.Colors.Orange; + + DiagramViewModel = new DiagramViewModel(); + DiagramViewModel.PageSizeType = PageSizeType.Custom; + DiagramViewModel.PageSize = new Size(double.NaN, double.NaN); + + DefaultDesignerItemViewModel node1 = new DefaultDesignerItemViewModel() { Left = 50, Top = 50, Text = "1" }; + DiagramViewModel.DirectAddItemCommand.Execute(node1); + + DefaultDesignerItemViewModel node2 = new DefaultDesignerItemViewModel() { Left = 400, Top = 50, Text = "2" }; + DiagramViewModel.DirectAddItemCommand.Execute(node2); + + ConnectionViewModel connector1 = new ConnectionViewModel(node1.RightConnector, node2.LeftConnector); + connector1.ShapeViewModel.SourceMarker = LinkMarker.Arrow; + connector1.ShapeViewModel.SinkMarker = LinkMarker.Arrow; + connector1.AddLabel("Arrow"); + DiagramViewModel.DirectAddItemCommand.Execute(connector1); + + node1 = new DefaultDesignerItemViewModel() { Left = 50, Top = 160, Text = "1" }; + DiagramViewModel.DirectAddItemCommand.Execute(node1); + + node2 = new DefaultDesignerItemViewModel() { Left = 400, Top = 160, Text = "2" }; + DiagramViewModel.DirectAddItemCommand.Execute(node2); + + connector1 = new ConnectionViewModel(node1.RightConnector, node2.LeftConnector); + connector1.ShapeViewModel.SourceMarker = LinkMarker.Circle; + connector1.ShapeViewModel.SinkMarker = LinkMarker.Circle; + connector1.AddLabel("Circle"); + DiagramViewModel.DirectAddItemCommand.Execute(connector1); + + node1 = new DefaultDesignerItemViewModel() { Left = 50, Top = 270, Text = "1" }; + DiagramViewModel.DirectAddItemCommand.Execute(node1); + + node2 = new DefaultDesignerItemViewModel() { Left = 400, Top = 270, Text = "2" }; + DiagramViewModel.DirectAddItemCommand.Execute(node2); + + connector1 = new ConnectionViewModel(node1.RightConnector, node2.LeftConnector); + connector1.ShapeViewModel.SourceMarker = LinkMarker.Square; + connector1.ShapeViewModel.SinkMarker = LinkMarker.Square; + connector1.AddLabel("Square"); + DiagramViewModel.DirectAddItemCommand.Execute(connector1); + + } + } +} diff --git a/AIStudio.Wpf.DiagramDesigner.Demo/ViewModels/ReconnectLinksToClosestPortsViewModel.cs b/AIStudio.Wpf.DiagramDesigner.Demo/ViewModels/ReconnectLinksToClosestPortsViewModel.cs new file mode 100644 index 0000000..ffffc8d --- /dev/null +++ b/AIStudio.Wpf.DiagramDesigner.Demo/ViewModels/ReconnectLinksToClosestPortsViewModel.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows; +using AIStudio.Wpf.DiagramDesigner.Algorithms; + +namespace AIStudio.Wpf.DiagramDesigner.Demo.ViewModels +{ + class ReconnectLinksToClosestPortsViewModel : BaseViewModel + { + public ReconnectLinksToClosestPortsViewModel() + { + Title = "Reconnect links"; + Info = "An example of reconnecting links to the closest ports."; + + _service.ColorViewModel.FillColor.Color = System.Windows.Media.Colors.Orange; + + DiagramViewModel = new DiagramViewModel(); + DiagramViewModel.PageSizeType = PageSizeType.Custom; + DiagramViewModel.PageSize = new Size(double.NaN, double.NaN); + + DefaultDesignerItemViewModel node1 = new DefaultDesignerItemViewModel() { Left = 50, Top = 50, Text = "1" }; + DiagramViewModel.DirectAddItemCommand.Execute(node1); + + DefaultDesignerItemViewModel node2 = new DefaultDesignerItemViewModel() { Left = 300, Top = 300, Text = "2" }; + DiagramViewModel.DirectAddItemCommand.Execute(node2); + + DefaultDesignerItemViewModel node3 = new DefaultDesignerItemViewModel() { Left = 300, Top = 50, Text = "3" }; + DiagramViewModel.DirectAddItemCommand.Execute(node3); + + ConnectionViewModel connector1 = new ConnectionViewModel(node1.RightConnector, node2.LeftConnector, DrawMode.ConnectingLineSmooth, RouterMode.RouterNormal); + DiagramViewModel.DirectAddItemCommand.Execute(connector1); + + ConnectionViewModel connector2 = new ConnectionViewModel(node2.RightConnector, node3.RightConnector, DrawMode.ConnectingLineStraight, RouterMode.RouterOrthogonal); + DiagramViewModel.DirectAddItemCommand.Execute(connector2); + + ReconnectLinksCommand = new SimpleCommand(ReconnectLinks); + } + + public SimpleCommand ReconnectLinksCommand + { + get; private set; + } + + protected void ReconnectLinks(object para) => DiagramViewModel.ReconnectLinksToClosestPorts(); + } +} diff --git a/AIStudio.Wpf.DiagramDesigner.Demo/ViewModels/ZoomViewModel.cs b/AIStudio.Wpf.DiagramDesigner.Demo/ViewModels/ZoomViewModel.cs new file mode 100644 index 0000000..d5854bb --- /dev/null +++ b/AIStudio.Wpf.DiagramDesigner.Demo/ViewModels/ZoomViewModel.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows; + +namespace AIStudio.Wpf.DiagramDesigner.Demo.ViewModels +{ + class ZoomViewModel : BaseViewModel + { + public ZoomViewModel() + { + Title = "Zoom"; + Info = "Drag the upper-right scroll bar to make the canvas larger and smaller."; + + _service.ColorViewModel.FillColor.Color = System.Windows.Media.Colors.Orange; + + DiagramViewModel = new DiagramViewModel(); + DiagramViewModel.PageSizeType = PageSizeType.Custom; + DiagramViewModel.PageSize = new Size(double.NaN, double.NaN); + + DefaultDesignerItemViewModel node1 = new DefaultDesignerItemViewModel() { Left = 50, Top = 50, Text = "1" }; + DiagramViewModel.DirectAddItemCommand.Execute(node1); + + DefaultDesignerItemViewModel node2 = new DefaultDesignerItemViewModel() { Left = 300, Top = 300, Text = "2" }; + DiagramViewModel.DirectAddItemCommand.Execute(node2); + + DefaultDesignerItemViewModel node3 = new DefaultDesignerItemViewModel() { Left = 300, Top = 50, Text = "3" }; + DiagramViewModel.DirectAddItemCommand.Execute(node3); + + ConnectionViewModel connector1 = new ConnectionViewModel(node1.RightConnector, node2.LeftConnector, DrawMode.ConnectingLineSmooth, RouterMode.RouterNormal); + DiagramViewModel.DirectAddItemCommand.Execute(connector1); + + ConnectionViewModel connector2 = new ConnectionViewModel(node2.RightConnector, node3.RightConnector, DrawMode.ConnectingLineStraight, RouterMode.RouterOrthogonal); + DiagramViewModel.DirectAddItemCommand.Execute(connector2); + + } + } +} diff --git a/AIStudio.Wpf.DiagramDesigner.Demo/Views/Animations/ReconnectLinksToClosestPortsView.xaml b/AIStudio.Wpf.DiagramDesigner.Demo/Views/Animations/ReconnectLinksToClosestPortsView.xaml new file mode 100644 index 0000000..fb0fbdb --- /dev/null +++ b/AIStudio.Wpf.DiagramDesigner.Demo/Views/Animations/ReconnectLinksToClosestPortsView.xaml @@ -0,0 +1,17 @@ + + + + + + + + + diff --git a/AIStudio.Wpf.DiagramDesigner.Demo/Views/Animations/ReconnectLinksToClosestPortsView.xaml.cs b/AIStudio.Wpf.DiagramDesigner.Demo/Views/Animations/ReconnectLinksToClosestPortsView.xaml.cs new file mode 100644 index 0000000..e702b48 --- /dev/null +++ b/AIStudio.Wpf.DiagramDesigner.Demo/Views/Animations/ReconnectLinksToClosestPortsView.xaml.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Text; +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 AIStudio.Wpf.DiagramDesigner.Demo.Views +{ + /// + /// ReconnectLinksToClosestPortsView.xaml 的交互逻辑 + /// + public partial class ReconnectLinksToClosestPortsView : UserControl + { + public ReconnectLinksToClosestPortsView() + { + InitializeComponent(); + } + } +} diff --git a/AIStudio.Wpf.DiagramDesigner.Demo/Views/Links/LabelsView.xaml b/AIStudio.Wpf.DiagramDesigner.Demo/Views/Links/LabelsView.xaml new file mode 100644 index 0000000..e12ee71 --- /dev/null +++ b/AIStudio.Wpf.DiagramDesigner.Demo/Views/Links/LabelsView.xaml @@ -0,0 +1,16 @@ + + + + + + + + diff --git a/AIStudio.Wpf.DiagramDesigner.Demo/Views/Links/LabelsView.xaml.cs b/AIStudio.Wpf.DiagramDesigner.Demo/Views/Links/LabelsView.xaml.cs new file mode 100644 index 0000000..3ff0493 --- /dev/null +++ b/AIStudio.Wpf.DiagramDesigner.Demo/Views/Links/LabelsView.xaml.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Text; +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 AIStudio.Wpf.DiagramDesigner.Demo.Views +{ + /// + /// LabelsView.xaml 的交互逻辑 + /// + public partial class LabelsView : UserControl + { + public LabelsView() + { + InitializeComponent(); + } + } +} diff --git a/AIStudio.Wpf.DiagramDesigner.Demo/Views/Links/MarkersView.xaml b/AIStudio.Wpf.DiagramDesigner.Demo/Views/Links/MarkersView.xaml new file mode 100644 index 0000000..6c7a1c9 --- /dev/null +++ b/AIStudio.Wpf.DiagramDesigner.Demo/Views/Links/MarkersView.xaml @@ -0,0 +1,16 @@ + + + + + + + + diff --git a/AIStudio.Wpf.DiagramDesigner.Demo/Views/Links/MarkersView.xaml.cs b/AIStudio.Wpf.DiagramDesigner.Demo/Views/Links/MarkersView.xaml.cs new file mode 100644 index 0000000..da3ac7c --- /dev/null +++ b/AIStudio.Wpf.DiagramDesigner.Demo/Views/Links/MarkersView.xaml.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Text; +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 AIStudio.Wpf.DiagramDesigner.Demo.Views +{ + /// + /// MarkersView.xaml 的交互逻辑 + /// + public partial class MarkersView : UserControl + { + public MarkersView() + { + InitializeComponent(); + } + } +} diff --git a/AIStudio.Wpf.DiagramDesigner.Demo/Views/ZoomView.xaml b/AIStudio.Wpf.DiagramDesigner.Demo/Views/ZoomView.xaml new file mode 100644 index 0000000..5eb9bb3 --- /dev/null +++ b/AIStudio.Wpf.DiagramDesigner.Demo/Views/ZoomView.xaml @@ -0,0 +1,29 @@ + + + + + + + + + + diff --git a/AIStudio.Wpf.DiagramDesigner.Demo/Views/ZoomView.xaml.cs b/AIStudio.Wpf.DiagramDesigner.Demo/Views/ZoomView.xaml.cs new file mode 100644 index 0000000..c7b99ca --- /dev/null +++ b/AIStudio.Wpf.DiagramDesigner.Demo/Views/ZoomView.xaml.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Text; +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 AIStudio.Wpf.DiagramDesigner.Demo.Views +{ + /// + /// ZoomView.xaml 的交互逻辑 + /// + public partial class ZoomView : UserControl + { + public ZoomView() + { + InitializeComponent(); + } + } +} diff --git a/AIStudio.Wpf.DiagramDesigner/Algorithms/LinksReconnectionAlgorithms.cs b/AIStudio.Wpf.DiagramDesigner/Algorithms/LinksReconnectionAlgorithms.cs new file mode 100644 index 0000000..972cab1 --- /dev/null +++ b/AIStudio.Wpf.DiagramDesigner/Algorithms/LinksReconnectionAlgorithms.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace AIStudio.Wpf.DiagramDesigner.Algorithms +{ + public static class LinksReconnectionAlgorithms + { + public static void ReconnectLinksToClosestPorts(this IDiagramViewModel diagram) + { + // Only refresh ports once + //var portsToRefresh = new HashSet(); + + foreach (var link in diagram.Items.OfType()) + { + if (link.IsFullConnection == false) + continue; + + var sourcePorts = link.SourceConnectorInfo.DataItem.Connectors; + var targetPorts = link.SinkConnectorInfoFully.DataItem.Connectors; + + // Find the ports with minimal distance + var minDistance = double.MaxValue; + var minSourcePort = link.SourceConnectorInfo; + var minTargetPort = link.SinkConnectorInfoFully; + foreach (var sourcePort in sourcePorts) + { + foreach (var targetPort in targetPorts) + { + var distance = sourcePort.Position.DistanceTo(targetPort.Position); + if (distance < minDistance) + { + minDistance = distance; + minSourcePort = sourcePort; + minTargetPort = targetPort; + } + } + } + + // Reconnect + if (link.SourceConnectorInfo != minSourcePort) + { + //portsToRefresh.Add(link.SourceConnectorInfo); + //portsToRefresh.Add(minSourcePort); + link.SetSourcePort(minSourcePort); + } + + if (link.SinkConnectorInfo != minTargetPort) + { + //portsToRefresh.Add(link.SinkConnectorInfoFully); + //portsToRefresh.Add(minTargetPort); + link.SetSinkPort(minTargetPort); + } + } + + //foreach (var port in portsToRefresh) + // port.Refresh(); + } + } +} diff --git a/AIStudio.Wpf.DiagramDesigner/Enums/ArrowPathStyle.cs b/AIStudio.Wpf.DiagramDesigner/Enums/ArrowPathStyle.cs index ace6f8f..338056f 100644 --- a/AIStudio.Wpf.DiagramDesigner/Enums/ArrowPathStyle.cs +++ b/AIStudio.Wpf.DiagramDesigner/Enums/ArrowPathStyle.cs @@ -9,7 +9,6 @@ namespace AIStudio.Wpf.DiagramDesigner None, Arrow, Circle, - Square, - + Square, } } diff --git a/AIStudio.Wpf.DiagramDesigner/Helpers/CopyHelper.cs b/AIStudio.Wpf.DiagramDesigner/Helpers/CopyHelper.cs index d99f67c..5cd1b0c 100644 --- a/AIStudio.Wpf.DiagramDesigner/Helpers/CopyHelper.cs +++ b/AIStudio.Wpf.DiagramDesigner/Helpers/CopyHelper.cs @@ -160,6 +160,22 @@ namespace AIStudio.Wpf.DiagramDesigner return d; } + public static ShapeViewModel Mapper(IShapeViewModel s) + { + var d = CopyHelper.Mapper(s); + d.SourceMarker = CopyHelper.Mapper(s.SourceMarker); + d.SinkMarker = CopyHelper.Mapper(s.SinkMarker); + return d; + } + + public static T Mapper(IShapeViewModel s) where T : IShapeViewModel + { + var d = CopyHelper.Mapper(s); + d.SourceMarker = CopyHelper.Mapper(s.SourceMarker); + d.SinkMarker = CopyHelper.Mapper(s.SinkMarker); + return d; + } + public static void CopyPropertyValue(IColorViewModel s, IColorViewModel d, string propertyName = null) { if (propertyName == "LineColor") diff --git a/AIStudio.Wpf.DiagramDesigner/Models/Serializables/SelectableItemBase.cs b/AIStudio.Wpf.DiagramDesigner/Models/Serializables/SelectableItemBase.cs index 36bcf65..18afd9c 100644 --- a/AIStudio.Wpf.DiagramDesigner/Models/Serializables/SelectableItemBase.cs +++ b/AIStudio.Wpf.DiagramDesigner/Models/Serializables/SelectableItemBase.cs @@ -34,6 +34,7 @@ namespace AIStudio.Wpf.DiagramDesigner ColorItem = CopyHelper.Mapper(viewmodel.ColorViewModel); FontItem = CopyHelper.Mapper(viewmodel.FontViewModel); + SharpItem = CopyHelper.Mapper(viewmodel.ShapeViewModel); } [XmlAttribute] @@ -76,9 +77,16 @@ namespace AIStudio.Wpf.DiagramDesigner public FontItem FontItem { get; set; - } + } + + [XmlElement] + public SharpItem SharpItem + { + get; set; + } } + [XmlInclude(typeof(ColorItem))] public class ColorItem : IColorViewModel { [XmlIgnore] @@ -149,46 +157,54 @@ namespace AIStudio.Wpf.DiagramDesigner } [XmlAttribute] - public ArrowPathStyle LeftArrowPathStyle + public LineDashStyle LineDashStyle { get; set; } - [XmlAttribute] - public ArrowPathStyle RightArrowPathStyle - { - get; set; - } + public event PropertyChangedEventHandler PropertyChanged; + } - [XmlAttribute] - public ArrowSizeStyle LeftArrowSizeStyle - { - get; set; - } - - [XmlAttribute] - public ArrowSizeStyle RightArrowSizeStyle + [XmlInclude(typeof(SharpItem))] + public class SharpItem : IShapeViewModel + { + [XmlIgnore] + public ILinkMarker SourceMarker { get; set; } [JsonIgnore] - [XmlIgnore] - public double LeftArrowSize + [XmlElement("SourceMarker")] + public LinkMarkerItem XmlSourceMarker { get { - throw new NotImplementedException(); + return SourceMarker as LinkMarkerItem; + } + set + { + SourceMarker = value; } } - [JsonIgnore] [XmlIgnore] - public double RightArrowSize + public ILinkMarker SinkMarker + { + get; set; + } + + [JsonIgnore] + [XmlElement("SinkMarker")] + public LinkMarkerItem XmlSinkMarker { get { - throw new NotImplementedException(); + return SinkMarker as LinkMarkerItem; + } + set + { + SinkMarker = value; } } @@ -734,4 +750,30 @@ namespace AIStudio.Wpf.DiagramDesigner } + public class LinkMarkerItem : ILinkMarker + { + [XmlAttribute] + public string Path + { + get; set; + } + + [XmlAttribute] + public double Width + { + get; set; + } + + [XmlAttribute] + public ArrowPathStyle PathStyle + { + get; set; + } + + public ArrowSizeStyle SizeStyle + { + get; set; + } + } + } diff --git a/AIStudio.Wpf.DiagramDesigner/PathGenerators/PathGenerators.Boundary.cs b/AIStudio.Wpf.DiagramDesigner/PathGenerators/PathGenerators.Boundary.cs index 853fc5b..c50741d 100644 --- a/AIStudio.Wpf.DiagramDesigner/PathGenerators/PathGenerators.Boundary.cs +++ b/AIStudio.Wpf.DiagramDesigner/PathGenerators/PathGenerators.Boundary.cs @@ -16,8 +16,8 @@ namespace AIStudio.Wpf.DiagramDesigner route = GetRouteWithMiddlePoints(_, link, route); - double sourceAngle = SourceMarkerAdjustement(route, link.ColorViewModel.LeftArrowSize); - double targetAngle = TargetMarkerAdjustement(route, link.ColorViewModel.RightArrowSize); + double sourceAngle = SourceMarkerAdjustement(route, link.GetSourceMarkerWidth()); + double targetAngle = TargetMarkerAdjustement(route, link.GetSinkMarkerWidth()); DoShift(route, link); diff --git a/AIStudio.Wpf.DiagramDesigner/PathGenerators/PathGenerators.Corner.cs b/AIStudio.Wpf.DiagramDesigner/PathGenerators/PathGenerators.Corner.cs index c7bb742..01f6b00 100644 --- a/AIStudio.Wpf.DiagramDesigner/PathGenerators/PathGenerators.Corner.cs +++ b/AIStudio.Wpf.DiagramDesigner/PathGenerators/PathGenerators.Corner.cs @@ -19,8 +19,8 @@ namespace AIStudio.Wpf.DiagramDesigner else route = GetRouteWithPartConnectionLine(_, link, route); - double sourceAngle = SourceMarkerAdjustement(route, link.ColorViewModel.LeftArrowSize); - double targetAngle = TargetMarkerAdjustement(route, link.ColorViewModel.RightArrowSize); + double sourceAngle = SourceMarkerAdjustement(route, link.GetSourceMarkerWidth()); + double targetAngle = TargetMarkerAdjustement(route, link.GetSinkMarkerWidth()); DoShift(route, link); diff --git a/AIStudio.Wpf.DiagramDesigner/PathGenerators/PathGenerators.Smooth.cs b/AIStudio.Wpf.DiagramDesigner/PathGenerators/PathGenerators.Smooth.cs index 2cee246..cd389d3 100644 --- a/AIStudio.Wpf.DiagramDesigner/PathGenerators/PathGenerators.Smooth.cs +++ b/AIStudio.Wpf.DiagramDesigner/PathGenerators/PathGenerators.Smooth.cs @@ -17,8 +17,8 @@ namespace AIStudio.Wpf.DiagramDesigner route = GetRouteWithCurvePoints(link, route); - double sourceAngle = SourceMarkerAdjustement(route, link.ColorViewModel.LeftArrowSize); - double targetAngle = TargetMarkerAdjustement(route, link.ColorViewModel.RightArrowSize); + double sourceAngle = SourceMarkerAdjustement(route, link.GetSourceMarkerWidth()); + double targetAngle = TargetMarkerAdjustement(route, link.GetSinkMarkerWidth()); DoShift(route, link); @@ -28,8 +28,8 @@ namespace AIStudio.Wpf.DiagramDesigner private static PathGeneratorResult CurveThroughPoints(PointBase[] route, ConnectionViewModel link) { - double sourceAngle = SourceMarkerAdjustement(route, link.ColorViewModel.LeftArrowSize); - double targetAngle = TargetMarkerAdjustement(route, link.ColorViewModel.RightArrowSize); + double sourceAngle = SourceMarkerAdjustement(route, link.GetSourceMarkerWidth()); + double targetAngle = TargetMarkerAdjustement(route, link.GetSinkMarkerWidth()); BezierSpline.GetCurveControlPoints(route, out var firstControlPoints, out var secondControlPoints); diff --git a/AIStudio.Wpf.DiagramDesigner/PathGenerators/PathGenerators.Straight.cs b/AIStudio.Wpf.DiagramDesigner/PathGenerators/PathGenerators.Straight.cs index 6b10cb4..7f70428 100644 --- a/AIStudio.Wpf.DiagramDesigner/PathGenerators/PathGenerators.Straight.cs +++ b/AIStudio.Wpf.DiagramDesigner/PathGenerators/PathGenerators.Straight.cs @@ -9,8 +9,8 @@ namespace AIStudio.Wpf.DiagramDesigner { route = ConcatRouteAndSourceAndTarget(route, source, target); - double sourceAngle = SourceMarkerAdjustement(route, link.ColorViewModel.LeftArrowSize); - double targetAngle = TargetMarkerAdjustement(route, link.ColorViewModel.RightArrowSize); + double sourceAngle = SourceMarkerAdjustement(route, link.GetSourceMarkerWidth()); + double targetAngle = TargetMarkerAdjustement(route, link.GetSinkMarkerWidth()); DoShift(route, link); diff --git a/AIStudio.Wpf.DiagramDesigner/UserControls/LineControl.xaml b/AIStudio.Wpf.DiagramDesigner/UserControls/LineControl.xaml index 913e28a..b8d39a5 100644 --- a/AIStudio.Wpf.DiagramDesigner/UserControls/LineControl.xaml +++ b/AIStudio.Wpf.DiagramDesigner/UserControls/LineControl.xaml @@ -44,10 +44,10 @@ - /// Simple service interface - /// - public interface IDiagramServiceProvider : INotifyPropertyChanged - { - IColorViewModel ColorViewModel { get; } - IFontViewModel FontViewModel { get; } - IDrawModeViewModel DrawModeViewModel { get; } - IQuickThemeViewModel QuickThemeViewModel { get; } - ILockObjectViewModel LockObjectViewModel { get; } - SelectableDesignerItemViewModelBase SelectedItem { get; set; } - IColorViewModel CopyDefaultColorViewModel(); - IFontViewModel CopyDefaultFontViewModel(); - } - - /// /// Simple service locator /// @@ -28,7 +12,9 @@ namespace AIStudio.Wpf.DiagramDesigner { ColorViewModel = new ColorViewModel(); FontViewModel = new FontViewModel(); + ShapeViewModel = new ShapeViewModel(); LockObjectViewModel = new LockObjectViewModel(); + _drawModeViewModel = new DrawModeViewModel(); _quickThemeViewModel = new QuickThemeViewModel(); @@ -37,6 +23,7 @@ namespace AIStudio.Wpf.DiagramDesigner SetOldValue(ColorViewModel, nameof(ColorViewModel)); SetOldValue(FontViewModel, nameof(FontViewModel)); + SetOldValue(ShapeViewModel, nameof(ShapeViewModel)); SetOldValue(LockObjectViewModel, nameof(LockObjectViewModel)); } @@ -57,6 +44,12 @@ namespace AIStudio.Wpf.DiagramDesigner return CopyHelper.Mapper(viewModel); } + public IShapeViewModel CopyDefaultShapeViewModel() + { + var viewModel = GetOldValue(nameof(ShapeViewModel)); + return CopyHelper.Mapper(viewModel); + } + private IColorViewModel _colorViewModel; public IColorViewModel ColorViewModel { @@ -76,7 +69,7 @@ namespace AIStudio.Wpf.DiagramDesigner _colorViewModel.PropertyChanged += ViewModel_PropertyChanged; } } - } + } private IFontViewModel _fontViewModel; public IFontViewModel FontViewModel @@ -99,6 +92,27 @@ namespace AIStudio.Wpf.DiagramDesigner } } + private IShapeViewModel _linkMarkerViewModel; + public IShapeViewModel ShapeViewModel + { + get + { + return _linkMarkerViewModel; + } + set + { + if (_linkMarkerViewModel != null) + { + _linkMarkerViewModel.PropertyChanged -= ViewModel_PropertyChanged; + } + SetProperty(ref _linkMarkerViewModel, value); + if (_linkMarkerViewModel != null) + { + _linkMarkerViewModel.PropertyChanged += ViewModel_PropertyChanged; + } + } + } + private DrawModeViewModel _drawModeViewModel; public IDrawModeViewModel DrawModeViewModel { @@ -151,12 +165,14 @@ namespace AIStudio.Wpf.DiagramDesigner { ColorViewModel = GetOldValue(nameof(ColorViewModel)); FontViewModel = GetOldValue(nameof(FontViewModel)); + ShapeViewModel = GetOldValue(nameof(ShapeViewModel)); LockObjectViewModel = GetOldValue(nameof(LockObjectViewModel)); } else { ColorViewModel = _selectedItem.ColorViewModel; FontViewModel = _selectedItem.FontViewModel; + ShapeViewModel = _selectedItem.ShapeViewModel; LockObjectViewModel = _selectedItem.LockObjectViewModel; } } @@ -168,8 +184,6 @@ namespace AIStudio.Wpf.DiagramDesigner } } - - /// /// Simple service locator helper /// diff --git a/AIStudio.Wpf.DiagramDesigner/ViewModels/AdditionViewModel/IColorViewModel.cs b/AIStudio.Wpf.DiagramDesigner/ViewModels/AdditionViewModel/Interface/IColorViewModel.cs similarity index 60% rename from AIStudio.Wpf.DiagramDesigner/ViewModels/AdditionViewModel/IColorViewModel.cs rename to AIStudio.Wpf.DiagramDesigner/ViewModels/AdditionViewModel/Interface/IColorViewModel.cs index b83645c..5404069 100644 --- a/AIStudio.Wpf.DiagramDesigner/ViewModels/AdditionViewModel/IColorViewModel.cs +++ b/AIStudio.Wpf.DiagramDesigner/ViewModels/AdditionViewModel/Interface/IColorViewModel.cs @@ -25,33 +25,10 @@ namespace AIStudio.Wpf.DiagramDesigner { get; set; } - ArrowPathStyle LeftArrowPathStyle + LineDashStyle LineDashStyle { get; set; } - ArrowPathStyle RightArrowPathStyle - { - get; set; - } - ArrowSizeStyle LeftArrowSizeStyle - { - get; set; - } - ArrowSizeStyle RightArrowSizeStyle - { - get; set; - } - - double LeftArrowSize - { - get; - } - - double RightArrowSize - { - get; - } - event PropertyChangedEventHandler PropertyChanged; } } diff --git a/AIStudio.Wpf.DiagramDesigner/ViewModels/AdditionViewModel/Interface/IDiagramServiceProvider.cs b/AIStudio.Wpf.DiagramDesigner/ViewModels/AdditionViewModel/Interface/IDiagramServiceProvider.cs new file mode 100644 index 0000000..6e363f9 --- /dev/null +++ b/AIStudio.Wpf.DiagramDesigner/ViewModels/AdditionViewModel/Interface/IDiagramServiceProvider.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Text; + +namespace AIStudio.Wpf.DiagramDesigner +{ + /// + /// Simple service interface + /// + public interface IDiagramServiceProvider : INotifyPropertyChanged + { + IColorViewModel ColorViewModel + { + get; + } + IFontViewModel FontViewModel + { + get; + } + IShapeViewModel ShapeViewModel + { + get; + } + IDrawModeViewModel DrawModeViewModel + { + get; + } + IQuickThemeViewModel QuickThemeViewModel + { + get; + } + ILockObjectViewModel LockObjectViewModel + { + get; + } + SelectableDesignerItemViewModelBase SelectedItem + { + get; set; + } + IColorViewModel CopyDefaultColorViewModel(); + IFontViewModel CopyDefaultFontViewModel(); + IShapeViewModel CopyDefaultShapeViewModel(); + } +} diff --git a/AIStudio.Wpf.DiagramDesigner/ViewModels/AdditionViewModel/IDrawModeViewModel.cs b/AIStudio.Wpf.DiagramDesigner/ViewModels/AdditionViewModel/Interface/IDrawModeViewModel.cs similarity index 100% rename from AIStudio.Wpf.DiagramDesigner/ViewModels/AdditionViewModel/IDrawModeViewModel.cs rename to AIStudio.Wpf.DiagramDesigner/ViewModels/AdditionViewModel/Interface/IDrawModeViewModel.cs diff --git a/AIStudio.Wpf.DiagramDesigner/ViewModels/AdditionViewModel/IFontViewModel.cs b/AIStudio.Wpf.DiagramDesigner/ViewModels/AdditionViewModel/Interface/IFontViewModel.cs similarity index 100% rename from AIStudio.Wpf.DiagramDesigner/ViewModels/AdditionViewModel/IFontViewModel.cs rename to AIStudio.Wpf.DiagramDesigner/ViewModels/AdditionViewModel/Interface/IFontViewModel.cs diff --git a/AIStudio.Wpf.DiagramDesigner/ViewModels/AdditionViewModel/ILockObjectViewModel.cs b/AIStudio.Wpf.DiagramDesigner/ViewModels/AdditionViewModel/Interface/ILockObjectViewModel.cs similarity index 100% rename from AIStudio.Wpf.DiagramDesigner/ViewModels/AdditionViewModel/ILockObjectViewModel.cs rename to AIStudio.Wpf.DiagramDesigner/ViewModels/AdditionViewModel/Interface/ILockObjectViewModel.cs diff --git a/AIStudio.Wpf.DiagramDesigner/ViewModels/AdditionViewModel/IQuickThemeViewModel.cs b/AIStudio.Wpf.DiagramDesigner/ViewModels/AdditionViewModel/Interface/IQuickThemeViewModel.cs similarity index 100% rename from AIStudio.Wpf.DiagramDesigner/ViewModels/AdditionViewModel/IQuickThemeViewModel.cs rename to AIStudio.Wpf.DiagramDesigner/ViewModels/AdditionViewModel/Interface/IQuickThemeViewModel.cs diff --git a/AIStudio.Wpf.DiagramDesigner/ViewModels/AdditionViewModel/Interface/IShapeViewModel.cs b/AIStudio.Wpf.DiagramDesigner/ViewModels/AdditionViewModel/Interface/IShapeViewModel.cs new file mode 100644 index 0000000..98a31b3 --- /dev/null +++ b/AIStudio.Wpf.DiagramDesigner/ViewModels/AdditionViewModel/Interface/IShapeViewModel.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Text; + +namespace AIStudio.Wpf.DiagramDesigner +{ + public interface IShapeViewModel + { + ILinkMarker SourceMarker + { + get; set; + } + + ILinkMarker SinkMarker + { + get; set; + } + + event PropertyChangedEventHandler PropertyChanged; + } + + +} diff --git a/AIStudio.Wpf.DiagramDesigner/ViewModels/AdditionViewModel/ShapeViewModel.cs b/AIStudio.Wpf.DiagramDesigner/ViewModels/AdditionViewModel/ShapeViewModel.cs new file mode 100644 index 0000000..0d4b227 --- /dev/null +++ b/AIStudio.Wpf.DiagramDesigner/ViewModels/AdditionViewModel/ShapeViewModel.cs @@ -0,0 +1,201 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace AIStudio.Wpf.DiagramDesigner +{ + public class ShapeViewModel : BindableBase, IShapeViewModel + { + private ILinkMarker _sourceMarker = LinkMarker.None; + public ILinkMarker SourceMarker + { + get + { + return _sourceMarker; + } + set + { + if (_sourceMarker != value) + { + if (_sourceMarker != null && _sourceMarker is LinkMarker _linkMarker1) + { + _linkMarker1.PropertyChanged -= ShapeViewModel_PropertyChanged; + } + SetProperty(ref _sourceMarker, value); + if (_sourceMarker != null && _sourceMarker is LinkMarker _linkMarker2) + { + _linkMarker2.PropertyChanged += ShapeViewModel_PropertyChanged; + } + } + else + { + RaisePropertyChanged(nameof(SourceMarker)); + } + } + } + + private ILinkMarker _sinkMarker = LinkMarker.Arrow; + public ILinkMarker SinkMarker + { + get + { + return _sinkMarker; + } + set + { + if (_sinkMarker != value) + { + if (_sinkMarker != null && _sinkMarker is LinkMarker _linkMarker1) + { + _linkMarker1.PropertyChanged -= ShapeViewModel_PropertyChanged; + } + SetProperty(ref _sinkMarker, value); + if (_sinkMarker != null && _sinkMarker is LinkMarker _linkMarker2) + { + _linkMarker2.PropertyChanged += ShapeViewModel_PropertyChanged; + } + } + else + { + RaisePropertyChanged(nameof(SinkMarker)); + } + } + } + + private void ShapeViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) + { + if (sender == SourceMarker) + { + RaisePropertyChanged(nameof(SourceMarker)); + } + else if (sender == SinkMarker) + { + RaisePropertyChanged(nameof(SinkMarker)); + } + } + } + + public class LinkMarker : BindableBase, ILinkMarker + { + public static LinkMarker None { get; } = new LinkMarker("", 10, ArrowPathStyle.None, ArrowSizeStyle.Middle); + public static LinkMarker Arrow { get; } = new LinkMarker("M 0 -5 10 0 0 5 z", 10, ArrowPathStyle.Arrow, ArrowSizeStyle.Middle); + public static LinkMarker Circle { get; } = new LinkMarker("M 0, 0 a 5,5 0 1,0 10,0 a 5,5 0 1,0 -10,0", 10, ArrowPathStyle.Circle, ArrowSizeStyle.Middle); + public static LinkMarker Square { get; } = new LinkMarker("M 0 -5 10 -5 10 5 0 5 z", 10, ArrowPathStyle.Square, ArrowSizeStyle.Middle); + + public static readonly Dictionary ArrowDictionary = new Dictionary() + { + { ArrowPathStyle.None, None.Path }, + { ArrowPathStyle.Arrow, Arrow.Path }, + { ArrowPathStyle.Circle, Circle.Path }, + { ArrowPathStyle.Square, Square.Path }, + }; + + public LinkMarker() + { + + } + + public LinkMarker(string path, double width, ArrowPathStyle arrowPathStyle, ArrowSizeStyle arrowSizeStyle) + { + Path = path; + Width = width; + _pathStyle = arrowPathStyle; + _sizeStyle = arrowSizeStyle; + } + + private string _path; + public string Path + { + get + { + return _path; + } + set + { + SetProperty(ref _path, value); + } + } + + private double _witdh; + public double Width + { + get + { + return _witdh; + } + set + { + SetProperty(ref _witdh, value); + } + } + + private ArrowPathStyle _pathStyle = ArrowPathStyle.None; + public ArrowPathStyle PathStyle + { + get + { + return _pathStyle; + } + set + { + if (SetProperty(ref _pathStyle, value)) + { + if (ArrowDictionary.ContainsKey(_pathStyle)) + { + Path = ArrowDictionary[_pathStyle]; + } + } + } + } + + private ArrowSizeStyle _sizeStyle = ArrowSizeStyle.Middle; + public ArrowSizeStyle SizeStyle + { + get + { + return _sizeStyle; + } + set + { + if (SetProperty(ref _sizeStyle, value)) + { + Width = (double)_sizeStyle; + } + } + } + + public static LinkMarker NewArrow(double width, double height) + => new LinkMarker(FormattableString.Invariant($"M 0 -{height / 2} {width} 0 0 {height / 2}"), width, ArrowPathStyle.Arrow, (ArrowSizeStyle)width); + + public static LinkMarker NewCircle(double r) + => new LinkMarker(FormattableString.Invariant($"M 0, 0 a {r},{r} 0 1,0 {r * 2},0 a {r},{r} 0 1,0 -{r * 2},0"), r * 2, ArrowPathStyle.Circle, (ArrowSizeStyle)(r * 2)); + + public static LinkMarker NewRectangle(double width, double height) + => new LinkMarker(FormattableString.Invariant($"M 0 -{height / 2} {width} -{height / 2} {width} {height / 2} 0 {height / 2} z"), width, ArrowPathStyle.Square, (ArrowSizeStyle)width); + + public static LinkMarker NewSquare(double size) => NewRectangle(size, size); + } + + public interface ILinkMarker + { + string Path + { + get; set; + } + + double Width + { + get; set; + } + + ArrowPathStyle PathStyle + { + get; set; + } + + ArrowSizeStyle SizeStyle + { + get; set; + } + } +} diff --git a/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/ConnectionViewModel.cs b/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/ConnectionViewModel.cs index e7e4342..76137f5 100644 --- a/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/ConnectionViewModel.cs +++ b/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/ConnectionViewModel.cs @@ -53,17 +53,14 @@ namespace AIStudio.Wpf.DiagramDesigner protected virtual void Init(FullyCreatedConnectorInfo sourceConnectorInfo, ConnectorInfoBase sinkConnectorInfo) { this.Root = sourceConnectorInfo.DataItem.Root; - - if (Root != null && Root.ColorViewModel != null) - { - this.ColorViewModel = CopyHelper.Mapper(Root.ColorViewModel); - } + this.ColorViewModel.FillColor.Color = Colors.Red; if (sinkConnectorInfo is FullyCreatedConnectorInfo sink && sink.DataItem.ShowArrow == false) { - this.ColorViewModel.RightArrowPathStyle = ArrowPathStyle.None; + this.ShapeViewModel.SinkMarker = LinkMarker.None; } - ColorViewModel.PropertyChanged += ConnectorViewModel_PropertyChanged; + this.ColorViewModel.PropertyChanged += ConnectorViewModel_PropertyChanged; + this.ShapeViewModel.PropertyChanged += ConnectorViewModel_PropertyChanged; this.PropertyChanged += ConnectorViewModel_PropertyChanged; var routetype = GlobalType.AllTypes.Where(p => typeof(IRouter).IsAssignableFrom(p)).FirstOrDefault(p => p.Name == RouterMode); @@ -76,7 +73,7 @@ namespace AIStudio.Wpf.DiagramDesigner this.SinkConnectorInfo = sinkConnectorInfo; DeleteConnectionCommand = new SimpleCommand(Command_Enable, DeleteConnection); AddVertexCommand = new SimpleCommand(Command_Enable, AddVertex); - AddLabelCommand = new SimpleCommand(Command_Enable, AddLabel); + AddLabelCommand = new SimpleCommand(Command_Enable, para => AddLabel()); } protected override void LoadDesignerItemViewModel(IDiagramViewModel root, SelectableItemBase designerbase) @@ -452,12 +449,10 @@ namespace AIStudio.Wpf.DiagramDesigner } } - else if (sender is ColorViewModel) + else if (sender is ShapeViewModel) { - if (e.PropertyName == nameof(ColorViewModel.LeftArrowPathStyle) || - e.PropertyName == nameof(ColorViewModel.LeftArrowSizeStyle) || - e.PropertyName == nameof(ColorViewModel.RightArrowPathStyle) || - e.PropertyName == nameof(ColorViewModel.RightArrowSizeStyle)) + if (e.PropertyName == nameof(ShapeViewModel.SourceMarker) || + e.PropertyName == nameof(ShapeViewModel.SinkMarker)) { UpdatePathGeneratorResult(); } @@ -536,22 +531,22 @@ namespace AIStudio.Wpf.DiagramDesigner { case ConnectorOrientation.Left: { - StartPoint = new PointBase(PathGeneratorResult.SourceMarkerPosition.X, PathGeneratorResult.SourceMarkerPosition.Y - ColorViewModel.LeftArrowSize / 2); + StartPoint = new PointBase(PathGeneratorResult.SourceMarkerPosition.X, PathGeneratorResult.SourceMarkerPosition.Y - GetSourceMarkerWidth() / 2); break; } case ConnectorOrientation.Top: { - StartPoint = new PointBase(PathGeneratorResult.SourceMarkerPosition.X - ColorViewModel.LeftArrowSize / 2, PathGeneratorResult.SourceMarkerPosition.Y); + StartPoint = new PointBase(PathGeneratorResult.SourceMarkerPosition.X - GetSourceMarkerWidth() / 2, PathGeneratorResult.SourceMarkerPosition.Y); break; } case ConnectorOrientation.Right: { - StartPoint = new PointBase(PathGeneratorResult.SourceMarkerPosition.X - ColorViewModel.LeftArrowSize, PathGeneratorResult.SourceMarkerPosition.Y - ColorViewModel.LeftArrowSize / 2); + StartPoint = new PointBase(PathGeneratorResult.SourceMarkerPosition.X - GetSourceMarkerWidth(), PathGeneratorResult.SourceMarkerPosition.Y - GetSourceMarkerWidth() / 2); break; } case ConnectorOrientation.Bottom: { - StartPoint = new PointBase(PathGeneratorResult.SourceMarkerPosition.X - ColorViewModel.LeftArrowSize / 2, PathGeneratorResult.SourceMarkerPosition.Y - ColorViewModel.LeftArrowSize); + StartPoint = new PointBase(PathGeneratorResult.SourceMarkerPosition.X - GetSourceMarkerWidth() / 2, PathGeneratorResult.SourceMarkerPosition.Y - GetSourceMarkerWidth()); break; } default: @@ -566,23 +561,23 @@ namespace AIStudio.Wpf.DiagramDesigner { case ConnectorOrientation.Left: { - EndPoint = new PointBase(PathGeneratorResult.TargetMarkerPosition.X, PathGeneratorResult.TargetMarkerPosition.Y - ColorViewModel.RightArrowSize / 2); + EndPoint = new PointBase(PathGeneratorResult.TargetMarkerPosition.X, PathGeneratorResult.TargetMarkerPosition.Y - GetSinkMarkerWidth() / 2); break; } case ConnectorOrientation.Top: { - EndPoint = new PointBase(PathGeneratorResult.TargetMarkerPosition.X - ColorViewModel.RightArrowSize / 2, PathGeneratorResult.TargetMarkerPosition.Y); + EndPoint = new PointBase(PathGeneratorResult.TargetMarkerPosition.X - GetSinkMarkerWidth() / 2, PathGeneratorResult.TargetMarkerPosition.Y); break; } case ConnectorOrientation.Right: { - EndPoint = new PointBase(PathGeneratorResult.TargetMarkerPosition.X - ColorViewModel.RightArrowSize, PathGeneratorResult.TargetMarkerPosition.Y - ColorViewModel.RightArrowSize / 2); + EndPoint = new PointBase(PathGeneratorResult.TargetMarkerPosition.X - GetSinkMarkerWidth(), PathGeneratorResult.TargetMarkerPosition.Y - GetSinkMarkerWidth() / 2); break; } case ConnectorOrientation.Bottom: { - EndPoint = new PointBase(PathGeneratorResult.TargetMarkerPosition.X - ColorViewModel.RightArrowSize / 2, PathGeneratorResult.TargetMarkerPosition.Y - ColorViewModel.RightArrowSize); + EndPoint = new PointBase(PathGeneratorResult.TargetMarkerPosition.X - GetSinkMarkerWidth() / 2, PathGeneratorResult.TargetMarkerPosition.Y - GetSinkMarkerWidth()); break; } default: @@ -686,6 +681,34 @@ namespace AIStudio.Wpf.DiagramDesigner return minPoint; } + public void SetSourcePort(FullyCreatedConnectorInfo port) + { + SourceConnectorInfo = port; + } + + public void SetSinkPort(FullyCreatedConnectorInfo port) + { + SinkConnectorInfo = port; + } + + public double GetSourceMarkerWidth() + { + if (string.IsNullOrEmpty(ShapeViewModel.SourceMarker.Path)) + { + return 0; + } + return ShapeViewModel.SourceMarker.Width; + } + + public double GetSinkMarkerWidth() + { + if (string.IsNullOrEmpty(ShapeViewModel.SinkMarker.Path)) + { + return 0; + } + return ShapeViewModel.SinkMarker.Width; + } + #region 双击添加 private void AddVertex(object parameter) { @@ -708,9 +731,9 @@ namespace AIStudio.Wpf.DiagramDesigner AddLabel(); } - public void AddLabel(object text = null) + public void AddLabel(string text = null, double? distance = null, PointBase? offset = null) { - var label = new ConnectorLabelModel(this, text?.ToString()); + var label = new ConnectorLabelModel(this, text?.ToString(), distance, offset); label.PropertyChanged += new WeakINPCEventHandler(ConnectorViewModel_PropertyChanged).Handler; label.IsSelected = true; Labels.Add(label); diff --git a/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/Connector/ConnectorLabelModel.cs b/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/Connector/ConnectorLabelModel.cs index 281c3ea..038d644 100644 --- a/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/Connector/ConnectorLabelModel.cs +++ b/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/Connector/ConnectorLabelModel.cs @@ -35,6 +35,9 @@ namespace AIStudio.Wpf.DiagramDesigner { base.Init(); + ConnectorWidth = 30; + ConnectorHeight = 30; + DeleteLabelCommand = new SimpleCommand(Command_Enable, DeleteLabel); } diff --git a/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/DiagramViewModel.cs b/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/DiagramViewModel.cs index 3ac6ed9..e3fceeb 100644 --- a/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/DiagramViewModel.cs +++ b/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/DiagramViewModel.cs @@ -67,6 +67,16 @@ namespace AIStudio.Wpf.DiagramDesigner get; set; } + public IFontViewModel FontViewModel + { + get; set; + } + + public IShapeViewModel ShapeViewModel + { + get; set; + } + private PageSizeType _pageSizeType = PageSizeType.A4; public PageSizeType PageSizeType { diff --git a/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/SelectableViewModelBase.cs b/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/SelectableViewModelBase.cs index d61c81f..41e8f22 100644 --- a/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/SelectableViewModelBase.cs +++ b/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/SelectableViewModelBase.cs @@ -62,8 +62,32 @@ namespace AIStudio.Wpf.DiagramDesigner protected virtual void Init() { - ColorViewModel = _service.CopyDefaultColorViewModel(); - FontViewModel = _service.CopyDefaultFontViewModel(); + if (Root?.ColorViewModel != null) + { + this.ColorViewModel = CopyHelper.Mapper(Root.ColorViewModel); + } + else + { + this.ColorViewModel = _service.CopyDefaultColorViewModel(); + } + + if (Root?.FontViewModel != null) + { + this.FontViewModel = CopyHelper.Mapper(Root.FontViewModel); + } + else + { + this.FontViewModel = _service.CopyDefaultFontViewModel(); + } + + if (Root?.ShapeViewModel != null) + { + this.ShapeViewModel = CopyHelper.Mapper(Root.ShapeViewModel); + } + else + { + this.ShapeViewModel = _service.CopyDefaultShapeViewModel(); + } LockObjectViewModel = new LockObjectViewModel(); } @@ -80,6 +104,7 @@ namespace AIStudio.Wpf.DiagramDesigner ColorViewModel = CopyHelper.Mapper(designerbase.ColorItem); FontViewModel = CopyHelper.Mapper(designerbase.FontItem); + ShapeViewModel = CopyHelper.Mapper(designerbase.SharpItem); } public IDiagramViewModel Root @@ -220,6 +245,19 @@ namespace AIStudio.Wpf.DiagramDesigner } } + private IShapeViewModel _shapeViewModel; + public IShapeViewModel ShapeViewModel + { + get + { + return _shapeViewModel; + } + set + { + SetProperty(ref _shapeViewModel, value); + } + } + public ILockObjectViewModel LockObjectViewModel { get; set; diff --git a/AIStudio.Wpf.DiagramDesigner/ViewModels/IDiagramViewModel.cs b/AIStudio.Wpf.DiagramDesigner/ViewModels/IDiagramViewModel.cs index 8f9dd2c..fc613a9 100644 --- a/AIStudio.Wpf.DiagramDesigner/ViewModels/IDiagramViewModel.cs +++ b/AIStudio.Wpf.DiagramDesigner/ViewModels/IDiagramViewModel.cs @@ -258,6 +258,14 @@ namespace AIStudio.Wpf.DiagramDesigner { get; set; } + IFontViewModel FontViewModel + { + get; set; + } + IShapeViewModel ShapeViewModel + { + get; set; + } #endregion //用于wpf大小与物理像素之间转换 double ScreenScale