Files
aistudio-wpf-diagram/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/ConnectorViewModel.cs

495 lines
17 KiB
C#
Raw Normal View History

2021-07-23 09:42:22 +08:00
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
2023-01-08 09:22:37 +08:00
//using System.Windows;
2021-07-23 09:42:22 +08:00
using System.Windows.Media;
2023-01-08 09:22:37 +08:00
using AIStudio.Wpf.DiagramDesigner.Geometry;
2022-10-28 22:45:39 +08:00
using AIStudio.Wpf.DiagramDesigner.Helpers;
2021-07-23 09:42:22 +08:00
2022-10-28 22:45:39 +08:00
namespace AIStudio.Wpf.DiagramDesigner
2021-07-23 09:42:22 +08:00
{
public class ConnectorViewModel : SelectableDesignerItemViewModelBase
{
public ConnectorViewModel(IDiagramViewModel parent, FullyCreatedConnectorInfo sourceConnectorInfo, FullyCreatedConnectorInfo sinkConnectorInfo,
SelectableDesignerItemBase designer, DrawMode vectorLineDrawMode) : base(parent, designer)
2021-07-23 09:42:22 +08:00
{
VectorLineDrawMode = vectorLineDrawMode;
2021-07-23 09:42:22 +08:00
Init(sourceConnectorInfo, sinkConnectorInfo);
2022-11-30 22:28:22 +08:00
2021-07-23 09:42:22 +08:00
}
2022-12-06 21:28:42 +08:00
public ConnectorViewModel(IDiagramViewModel parent, FullyCreatedConnectorInfo sourceConnectorInfo, ConnectorInfoBase sinkConnectorInfo, DrawMode vectorLineDrawMode)
2021-07-23 09:42:22 +08:00
{
2022-12-06 21:28:42 +08:00
Parent = parent;
VectorLineDrawMode = vectorLineDrawMode;
2021-07-23 09:42:22 +08:00
Init(sourceConnectorInfo, sinkConnectorInfo);
}
public ConnectorViewModel( FullyCreatedConnectorInfo sourceConnectorInfo, ConnectorInfoBase sinkConnectorInfo, DrawMode vectorLineDrawMode):this(null, sourceConnectorInfo, sinkConnectorInfo, vectorLineDrawMode)
{
}
public override SelectableDesignerItemBase ToXmlObject()
{
2023-01-08 09:22:37 +08:00
if (IsFullConnection)
{
ConnectionItem connection = new ConnectionItem(
SourceConnectorInfo.DataItem.Id,
SourceConnectorInfo.Orientation,
SourceConnectorInfo.DataItem.GetType(),
GetXRatioFromConnector(SourceConnectorInfo),
GetYRatioFromConnector(SourceConnectorInfo),
SourceConnectorInfo.IsInnerPoint,
2023-01-08 09:22:37 +08:00
SinkConnectorInfoFully.DataItem.Id,
SinkConnectorInfoFully.Orientation,
SinkConnectorInfoFully.DataItem.GetType(),
GetXRatioFromConnector(SinkConnectorInfoFully),
GetYRatioFromConnector(SinkConnectorInfoFully),
SinkConnectorInfoFully.IsInnerPoint,
this);
return connection;
}
else
{
return null;
}
}
public override Type ToXmlType()
{
return typeof(ConnectionItem);
}
2021-07-23 09:42:22 +08:00
2022-11-30 22:28:22 +08:00
public IPathFinder PathFinder
{
get; set;
}
2021-07-23 09:42:22 +08:00
2023-01-08 09:22:37 +08:00
private PointBase _sourceA;
public PointBase SourceA
2021-07-23 09:42:22 +08:00
{
get
{
return _sourceA;
}
set
{
if (SetProperty(ref _sourceA, value))
{
UpdateArea();
}
}
}
2023-01-08 09:22:37 +08:00
private PointBase _sourceB;
public PointBase SourceB
2021-07-23 09:42:22 +08:00
{
get
{
return _sourceB;
}
set
{
if (SetProperty(ref _sourceB, value))
{
UpdateArea();
}
}
}
2023-01-08 09:22:37 +08:00
private List<ConnectorPoint> _connectionPoints;
public List<ConnectorPoint> ConnectionPoints
2021-07-23 09:42:22 +08:00
{
get
{
return _connectionPoints;
}
private set
{
if (_connectionPoints != null)
{
_connectionPoints.ForEach(p => p.PropertyChanged -= new WeakINPCEventHandler(ConnectionPoint_PropertyChanged).Handler);
}
2021-07-23 09:42:22 +08:00
SetProperty(ref _connectionPoints, value);
if (_connectionPoints != null)
{
_connectionPoints.ForEach(p => p.PropertyChanged += new WeakINPCEventHandler(ConnectionPoint_PropertyChanged).Handler);
}
2021-07-23 09:42:22 +08:00
}
}
2023-01-08 09:22:37 +08:00
private PointBase _startPoint;
public PointBase StartPoint
2021-07-23 09:42:22 +08:00
{
get
{
return _startPoint;
}
private set
{
SetProperty(ref _startPoint, value);
}
}
2023-01-08 09:22:37 +08:00
private PointBase _endPoint;
public PointBase EndPoint
2021-07-23 09:42:22 +08:00
{
get
{
return _endPoint;
}
private set
{
SetProperty(ref _endPoint, value);
}
}
2023-01-08 09:22:37 +08:00
private RectangleBase _area;
public RectangleBase Area
2021-07-23 09:42:22 +08:00
{
get
{
return _area;
}
private set
{
2023-01-08 09:22:37 +08:00
RectangleBase oldarea = _area;
2021-07-23 09:42:22 +08:00
if (SetProperty(ref _area, value))
{
2021-07-23 09:42:22 +08:00
UpdateConnectionPoints();
2022-12-06 21:28:42 +08:00
OutTextItemLocation(oldarea, value);
2021-07-23 09:42:22 +08:00
}
}
}
2022-11-30 22:28:22 +08:00
public DrawMode VectorLineDrawMode
{
get; set;
}
2023-01-08 09:22:37 +08:00
//待完善这两处
public List<LinkVertexModel> Vertices { get; } = new List<LinkVertexModel>();
public List<LinkLabelModel> Labels { get; set; } = new List<LinkLabelModel>();
2022-12-06 21:28:42 +08:00
public virtual Dictionary<string, string> PropertiesSetting
{
get
{
return new Dictionary<string, string>()
{
{ "Text","文本" },
};
}
}
2023-01-08 09:22:37 +08:00
public ConnectorInfo ConnectorInfo(ConnectorOrientation orientation, double left, double top, double width, double height, PointBase position)
2021-07-23 09:42:22 +08:00
{
return new ConnectorInfo()
{
Orientation = orientation,
2023-01-08 09:22:37 +08:00
DesignerItemSize = new SizeBase(width, height),
2021-07-23 09:42:22 +08:00
DesignerItemLeft = left,
DesignerItemTop = top,
Position = position
};
}
private FullyCreatedConnectorInfo _sourceConnectorInfo;
public FullyCreatedConnectorInfo SourceConnectorInfo
{
get
{
return _sourceConnectorInfo;
}
set
{
if (SetProperty(ref _sourceConnectorInfo, value))
{
SourceA = PointHelper.GetPointForConnector(_sourceConnectorInfo);
(_sourceConnectorInfo.DataItem as INotifyPropertyChanged).PropertyChanged += new WeakINPCEventHandler(ConnectorViewModel_PropertyChanged).Handler;
}
}
}
private ConnectorInfoBase _sinkConnectorInfo;
public ConnectorInfoBase SinkConnectorInfo
{
get
{
return _sinkConnectorInfo;
}
set
{
if (SetProperty(ref _sinkConnectorInfo, value))
{
if (_sinkConnectorInfo is FullyCreatedConnectorInfo)
{
SourceB = PointHelper.GetPointForConnector((FullyCreatedConnectorInfo)_sinkConnectorInfo);
(((FullyCreatedConnectorInfo)_sinkConnectorInfo).DataItem as INotifyPropertyChanged).PropertyChanged += new WeakINPCEventHandler(ConnectorViewModel_PropertyChanged).Handler;
}
else
{
2023-01-08 09:22:37 +08:00
SourceB = SinkConnectorInfoPart.Position;
2021-07-23 09:42:22 +08:00
}
}
}
}
2023-01-08 09:22:37 +08:00
public FullyCreatedConnectorInfo SinkConnectorInfoFully
{
get
{
return SinkConnectorInfo as FullyCreatedConnectorInfo;
}
}
public PartCreatedConnectionInfo SinkConnectorInfoPart
{
get
{
return SinkConnectorInfo as PartCreatedConnectionInfo;
}
}
public ConnectorPoint OnGoingPosition
{
get
{
return SinkConnectorInfoPart?.Position;
}
}
public bool IsFullConnection
{
get
{
return SinkConnectorInfoFully != null;
}
}
public bool IsPortless => SourceConnectorInfo?.DataItem?.Connectors?.Count() == 0;
public double GetXRatioFromConnector(FullyCreatedConnectorInfo info)
{
if (info.IsInnerPoint)
{
return info.XRatio;
}
else
{
switch (info.Orientation)
{
case ConnectorOrientation.Top:
return 0.5;
case ConnectorOrientation.Left:
return 0;
case ConnectorOrientation.Bottom:
return 0.5;
case ConnectorOrientation.Right:
return 1;
default: return info.XRatio;
}
}
}
public double GetYRatioFromConnector(FullyCreatedConnectorInfo info)
{
if (info.IsInnerPoint)
{
return info.YRatio;
}
else
{
switch (info.Orientation)
{
case ConnectorOrientation.Top:
return 0;
case ConnectorOrientation.Left:
return 0.5;
case ConnectorOrientation.Bottom:
return 1;
case ConnectorOrientation.Right:
return 0.5;
default: return info.YRatio;
}
}
}
2021-07-23 09:42:22 +08:00
private void UpdateArea()
{
2023-01-08 09:22:37 +08:00
Area = new RectangleBase(SourceA, SourceB);
2021-07-23 09:42:22 +08:00
}
private void UpdateConnectionPoints()
{
2022-11-30 22:28:22 +08:00
ConnectionPoints = PathFinder.UpdateConnectionPoints(Parent, SourceA, SourceB, SourceConnectorInfo, SinkConnectorInfo);
StartPoint = ConnectionPoints.First();
2021-07-23 09:42:22 +08:00
EndPoint = ConnectionPoints.Last();
2023-01-08 09:22:37 +08:00
//var router = Routers.Normal(Parent, this);
//var pathGenerator = PathGenerators.Smooth(Parent, this, router, SourceA, SourceB);
2022-11-30 22:28:22 +08:00
}
2021-07-23 09:42:22 +08:00
private void ConnectorViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case "ItemHeight":
case "ItemWidth":
case "Left":
case "Top":
SourceA = PointHelper.GetPointForConnector(this.SourceConnectorInfo);
2023-01-08 09:22:37 +08:00
if (IsFullConnection)
2021-07-23 09:42:22 +08:00
{
2023-01-08 09:22:37 +08:00
SourceB = PointHelper.GetPointForConnector(this.SinkConnectorInfoFully);
2021-07-23 09:42:22 +08:00
}
break;
}
}
private void ConnectionPoint_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case "Left":
case "Top":
RaisePropertyChanged(nameof(ConnectionPoints));
break;
}
}
2021-07-23 09:42:22 +08:00
private void Init(FullyCreatedConnectorInfo sourceConnectorInfo, ConnectorInfoBase sinkConnectorInfo)
{
this.Parent = sourceConnectorInfo.DataItem.Parent;
2022-11-30 22:28:22 +08:00
if (VectorLineDrawMode == DrawMode.ConnectingLine)
{
PathFinder = new StraightLinePathFinder();
}
else if (VectorLineDrawMode == DrawMode.BoundaryConnectingLine)
{
PathFinder = new BoundaryPathFinder();
}
else
{
PathFinder = new OrthogonalPathFinder();
}
2021-07-23 09:42:22 +08:00
this.SourceConnectorInfo = sourceConnectorInfo;
2022-11-30 22:28:22 +08:00
this.SinkConnectorInfo = sinkConnectorInfo;
2021-07-23 09:42:22 +08:00
DeleteConnectionCommand = new SimpleCommand(DeleteConnection);
2022-12-06 21:28:42 +08:00
if (Parent != null && Parent.ColorViewModel != null)
{
this.ColorViewModel = CopyHelper.Mapper(Parent.ColorViewModel);
}
if (sinkConnectorInfo is FullyCreatedConnectorInfo sink && sink.DataItem.ShowArrow == false)
{
this.ColorViewModel.RightArrowPathStyle = ArrowPathStyle.None;
}
2021-07-23 09:42:22 +08:00
}
2022-11-30 22:28:22 +08:00
public SimpleCommand DeleteConnectionCommand
{
get; set;
}
2023-01-08 09:22:37 +08:00
2021-07-23 09:42:22 +08:00
private void DeleteConnection(object args)
{
if (this.Parent is IDiagramViewModel)
{
var diagramVM = this.Parent as IDiagramViewModel;
diagramVM.RemoveItemCommand.Execute(this);
}
}
protected override void ExecuteEditCommand(object param)
{
if (this.OutTextItem != null) return;
AddText("");
}
public void AddText(string text)
{
if (this.Parent is IDiagramViewModel)
{
var diagramVM = this.Parent as IDiagramViewModel;
TextDesignerItemViewModel textitem = new TextDesignerItemViewModel();
textitem.ItemWidth = Double.NaN;
textitem.ItemHeight = double.NaN;
if (diagramVM.DiagramType == DiagramType.FlowChart)
{
var mid = (int)(ConnectionPoints.Count / 2);
2022-11-30 22:28:22 +08:00
var p = BoundaryPathFinder.SegmentMiddlePoint(ConnectionPoints[mid - 1], ConnectionPoints[mid]);
2021-07-23 09:42:22 +08:00
textitem.Left = this.Area.Left + p.X + 2;
textitem.Top = this.Area.Top + p.Y - 15;
}
else
{
textitem.Left = this.Area.Left + this.Area.Width / 2 - 16;
textitem.Top = this.Area.Top + this.Area.Height / 2 - 5;
}
textitem.Watermark = null;
textitem.ZIndex = diagramVM.Items.Count;
textitem.ParentId = this.Id;
textitem.ParentItem = this;
textitem.ColorViewModel.FillColor = new ColorObject() { Color = Colors.White };
textitem.Text = text;
diagramVM.DirectAddItemCommand.Execute(textitem);
this.OutTextItem = textitem;
}
}
2023-01-08 09:22:37 +08:00
public void OutTextItemLocation(RectangleBase oldArea, RectangleBase newArea)
2021-07-23 09:42:22 +08:00
{
if (this.OutTextItem is TextDesignerItemViewModel text)
{
2023-01-08 09:22:37 +08:00
var oldpoint = new PointBase(oldArea.Left + oldArea.Width / 2, oldArea.Top + oldArea.Height / 2);
var newpoint = new PointBase(newArea.Left + newArea.Width / 2, newArea.Top + newArea.Height / 2);
2021-07-23 09:42:22 +08:00
text.Left = text.Left + newpoint.X - oldpoint.X;
text.Top = text.Top + newpoint.Y - oldpoint.Y;
}
}
2023-01-08 09:22:37 +08:00
//private (PointInfoBase source, PointInfoBase target) FindConnectionPoints(PointInfoBase[] route)
//{
// if (IsPortless) // Portless
// {
// if (SourceConnectorInfo.DataItem == null || (IsFullConnection && SinkConnectorInfoFully.DataItem == null))
// return (null, null);
// var sourceCenter = SourceConnectorInfo.DataItem.GetBounds().Center;
// var targetCenter = SinkConnectorInfoFully?.DataItem?.GetBounds().Center ?? SinkConnectorInfoFully.Position;
// var firstPt = route.Length > 0 ? route[0] : targetCenter;
// var secondPt = route.Length > 0 ? route[0] : sourceCenter;
// var sourceLine = new Line(firstPt, sourceCenter);
// var targetLine = new Line(secondPt, targetCenter);
// var sourceIntersections = Link.SourceNode.GetShape().GetIntersectionsWithLine(sourceLine);
// var targetIntersections = Link.TargetNode.GetShape().GetIntersectionsWithLine(targetLine);
// var sourceIntersection = GetClosestPointTo(sourceIntersections, firstPt);
// var targetIntersection = GetClosestPointTo(targetIntersections, secondPt);
// return (sourceIntersection ?? sourceCenter, targetIntersection ?? targetCenter);
// }
// else
// {
// if (!Link.SourcePort.Initialized || Link.TargetPort?.Initialized == false)
// return (null, null);
// var source = GetPortPositionBasedOnAlignment(Link.SourcePort, Link.SourceMarker);
// var target = GetPortPositionBasedOnAlignment(Link.TargetPort, Link.TargetMarker);
// return (source, target ?? Link.OnGoingPosition);
// }
//}
2021-07-23 09:42:22 +08:00
}
}