mirror of
https://gitee.com/akwkevin/aistudio.-wpf.-diagram
synced 2026-03-03 00:00:57 +08:00
431 lines
14 KiB
C#
431 lines
14 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Linq;
|
|
using System.Windows;
|
|
using System.Windows.Media;
|
|
using AIStudio.Wpf.DiagramDesigner.Helpers;
|
|
|
|
namespace AIStudio.Wpf.DiagramDesigner
|
|
{
|
|
public class ConnectorViewModel : SelectableDesignerItemViewModelBase
|
|
{
|
|
public ConnectorViewModel(IDiagramViewModel parent, FullyCreatedConnectorInfo sourceConnectorInfo, FullyCreatedConnectorInfo sinkConnectorInfo,
|
|
SelectableDesignerItemBase designer, DrawMode vectorLineDrawMode) : base(parent, designer)
|
|
{
|
|
VectorLineDrawMode = vectorLineDrawMode;
|
|
Init(sourceConnectorInfo, sinkConnectorInfo);
|
|
|
|
}
|
|
|
|
public ConnectorViewModel(IDiagramViewModel parent, FullyCreatedConnectorInfo sourceConnectorInfo, ConnectorInfoBase sinkConnectorInfo, DrawMode vectorLineDrawMode)
|
|
{
|
|
Parent = parent;
|
|
VectorLineDrawMode = vectorLineDrawMode;
|
|
Init(sourceConnectorInfo, sinkConnectorInfo);
|
|
}
|
|
|
|
public ConnectorViewModel( FullyCreatedConnectorInfo sourceConnectorInfo, ConnectorInfoBase sinkConnectorInfo, DrawMode vectorLineDrawMode):this(null, sourceConnectorInfo, sinkConnectorInfo, vectorLineDrawMode)
|
|
{
|
|
|
|
}
|
|
|
|
public override SelectableDesignerItemBase ToXmlObject()
|
|
{
|
|
if (SinkConnectorInfo is FullyCreatedConnectorInfo sinkConnector)
|
|
{
|
|
ConnectionItem connection = new ConnectionItem(
|
|
SourceConnectorInfo.DataItem.Id,
|
|
SourceConnectorInfo.Orientation,
|
|
SourceConnectorInfo.DataItem.GetType(),
|
|
GetXRatioFromConnector(SourceConnectorInfo),
|
|
GetYRatioFromConnector(SourceConnectorInfo),
|
|
SourceConnectorInfo.IsInnerPoint,
|
|
sinkConnector.DataItem.Id,
|
|
sinkConnector.Orientation,
|
|
sinkConnector.DataItem.GetType(),
|
|
GetXRatioFromConnector(sinkConnector),
|
|
GetYRatioFromConnector(sinkConnector),
|
|
sinkConnector.IsInnerPoint,
|
|
this);
|
|
|
|
return connection;
|
|
}
|
|
else
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public override Type ToXmlType()
|
|
{
|
|
return typeof(ConnectionItem);
|
|
}
|
|
|
|
public IPathFinder PathFinder
|
|
{
|
|
get; set;
|
|
}
|
|
|
|
public bool IsFullConnection
|
|
{
|
|
get
|
|
{
|
|
return _sinkConnectorInfo is FullyCreatedConnectorInfo;
|
|
}
|
|
}
|
|
|
|
private Point _sourceA;
|
|
public Point SourceA
|
|
{
|
|
get
|
|
{
|
|
return _sourceA;
|
|
}
|
|
set
|
|
{
|
|
if (SetProperty(ref _sourceA, value))
|
|
{
|
|
UpdateArea();
|
|
}
|
|
}
|
|
}
|
|
|
|
private Point _sourceB;
|
|
public Point SourceB
|
|
{
|
|
get
|
|
{
|
|
return _sourceB;
|
|
}
|
|
set
|
|
{
|
|
if (SetProperty(ref _sourceB, value))
|
|
{
|
|
UpdateArea();
|
|
}
|
|
}
|
|
}
|
|
|
|
private List<PointInfoBase> _connectionPoints;
|
|
public List<PointInfoBase> ConnectionPoints
|
|
{
|
|
get
|
|
{
|
|
return _connectionPoints;
|
|
}
|
|
private set
|
|
{
|
|
if (_connectionPoints != null)
|
|
{
|
|
_connectionPoints.ForEach(p => p.PropertyChanged -= new WeakINPCEventHandler(ConnectionPoint_PropertyChanged).Handler);
|
|
}
|
|
SetProperty(ref _connectionPoints, value);
|
|
if (_connectionPoints != null)
|
|
{
|
|
_connectionPoints.ForEach(p => p.PropertyChanged += new WeakINPCEventHandler(ConnectionPoint_PropertyChanged).Handler);
|
|
}
|
|
}
|
|
}
|
|
|
|
private Point _startPoint;
|
|
public Point StartPoint
|
|
{
|
|
get
|
|
{
|
|
return _startPoint;
|
|
}
|
|
private set
|
|
{
|
|
SetProperty(ref _startPoint, value);
|
|
}
|
|
}
|
|
|
|
private Point _endPoint;
|
|
public Point EndPoint
|
|
{
|
|
get
|
|
{
|
|
return _endPoint;
|
|
}
|
|
private set
|
|
{
|
|
SetProperty(ref _endPoint, value);
|
|
}
|
|
}
|
|
|
|
private Rect _area;
|
|
public Rect Area
|
|
{
|
|
get
|
|
{
|
|
return _area;
|
|
}
|
|
private set
|
|
{
|
|
Rect oldarea = _area;
|
|
if (SetProperty(ref _area, value))
|
|
{
|
|
UpdateConnectionPoints();
|
|
OutTextItemLocation(oldarea, value);
|
|
}
|
|
}
|
|
}
|
|
|
|
public DrawMode VectorLineDrawMode
|
|
{
|
|
get; set;
|
|
}
|
|
|
|
public virtual Dictionary<string, string> PropertiesSetting
|
|
{
|
|
get
|
|
{
|
|
return new Dictionary<string, string>()
|
|
{
|
|
{ "Text","文本" },
|
|
};
|
|
}
|
|
}
|
|
|
|
public ConnectorInfo ConnectorInfo(ConnectorOrientation orientation, double left, double top, double width, double height, Point position)
|
|
{
|
|
|
|
return new ConnectorInfo()
|
|
{
|
|
Orientation = orientation,
|
|
DesignerItemSize = new Size(width, height),
|
|
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
|
|
{
|
|
SourceB = ((PartCreatedConnectionInfo)SinkConnectorInfo).CurrentLocation;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void UpdateArea()
|
|
{
|
|
Area = new Rect(SourceA, SourceB);
|
|
}
|
|
|
|
private void UpdateConnectionPoints()
|
|
{
|
|
ConnectionPoints = PathFinder.UpdateConnectionPoints(Parent, SourceA, SourceB, SourceConnectorInfo, SinkConnectorInfo);
|
|
StartPoint = ConnectionPoints.First();
|
|
EndPoint = ConnectionPoints.Last();
|
|
|
|
}
|
|
|
|
private void ConnectorViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
{
|
|
switch (e.PropertyName)
|
|
{
|
|
case "ItemHeight":
|
|
case "ItemWidth":
|
|
case "Left":
|
|
case "Top":
|
|
SourceA = PointHelper.GetPointForConnector(this.SourceConnectorInfo);
|
|
if (this.SinkConnectorInfo is FullyCreatedConnectorInfo)
|
|
{
|
|
SourceB = PointHelper.GetPointForConnector((FullyCreatedConnectorInfo)this.SinkConnectorInfo);
|
|
}
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
private void ConnectionPoint_PropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
{
|
|
switch (e.PropertyName)
|
|
{
|
|
case "Left":
|
|
case "Top":
|
|
RaisePropertyChanged(nameof(ConnectionPoints));
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
private void Init(FullyCreatedConnectorInfo sourceConnectorInfo, ConnectorInfoBase sinkConnectorInfo)
|
|
{
|
|
this.Parent = sourceConnectorInfo.DataItem.Parent;
|
|
if (VectorLineDrawMode == DrawMode.ConnectingLine)
|
|
{
|
|
PathFinder = new StraightLinePathFinder();
|
|
}
|
|
else if (VectorLineDrawMode == DrawMode.BoundaryConnectingLine)
|
|
{
|
|
PathFinder = new BoundaryPathFinder();
|
|
}
|
|
else
|
|
{
|
|
PathFinder = new OrthogonalPathFinder();
|
|
}
|
|
this.SourceConnectorInfo = sourceConnectorInfo;
|
|
this.SinkConnectorInfo = sinkConnectorInfo;
|
|
DeleteConnectionCommand = new SimpleCommand(DeleteConnection);
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
public SimpleCommand DeleteConnectionCommand
|
|
{
|
|
get; set;
|
|
}
|
|
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);
|
|
var p = BoundaryPathFinder.SegmentMiddlePoint(ConnectionPoints[mid - 1], ConnectionPoints[mid]);
|
|
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;
|
|
}
|
|
}
|
|
|
|
public void OutTextItemLocation(Rect oldArea, Rect newArea)
|
|
{
|
|
if (this.OutTextItem is TextDesignerItemViewModel text)
|
|
{
|
|
var oldpoint = new Point(oldArea.Left + oldArea.Width / 2, oldArea.Top + oldArea.Height / 2);
|
|
var newpoint = new Point(newArea.Left + newArea.Width / 2, newArea.Top + newArea.Height / 2);
|
|
|
|
text.Left = text.Left + newpoint.X - oldpoint.X;
|
|
text.Top = text.Top + newpoint.Y - oldpoint.Y;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|