可以把连线从节点上拖下来,并且依附上去。

This commit is contained in:
艾竹
2023-05-03 13:28:16 +08:00
parent 1536e5018d
commit ed22b9daa3
13 changed files with 352 additions and 79 deletions

View File

@@ -5,6 +5,7 @@ using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using AIStudio.Wpf.DiagramDesigner.Controls;
@@ -480,7 +481,7 @@ namespace AIStudio.Wpf.DiagramDesigner
protected override void Item_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (IsLoaded == false) return;
if (IsLoaded == false || IsInternalChanged == true ) return;
if (sender is ConnectionViewModel)
{
@@ -513,10 +514,6 @@ namespace AIStudio.Wpf.DiagramDesigner
{
SourceConnectorInfoFully.DataItem.PropertyChanged += new WeakINPCEventHandler(Item_PropertyChanged).Handler;
}
//else if (SourceConnectorInfoPart != null)
//{
// SourceConnectorInfoPart.PropertyChanged += new WeakINPCEventHandler(Item_PropertyChanged).Handler;
//}
}
break;
case nameof(SinkConnectorInfo):
@@ -527,10 +524,6 @@ namespace AIStudio.Wpf.DiagramDesigner
{
SinkConnectorInfoFully.DataItem.PropertyChanged += new WeakINPCEventHandler(Item_PropertyChanged).Handler;
}
//else if (SinkConnectorInfoPart != null)
//{
// SinkConnectorInfoPart.PropertyChanged += new WeakINPCEventHandler(Item_PropertyChanged).Handler;
//}
}
break;
case nameof(IsSelected):
@@ -580,15 +573,48 @@ namespace AIStudio.Wpf.DiagramDesigner
break;
}
}
else if (sender is ConnectorVertexModel)
else if (sender is ConnectorVertexModel connectorVertexModel)
{
switch (e.PropertyName)
{
case nameof(ConnectorPointModel.X):
case nameof(ConnectorPointModel.Y):
UpdatePathGeneratorResult();
if (connectorVertexModel.ConnectorVertexType == ConnectorVertexType.None)
{
UpdatePathGeneratorResult();
}
else if(connectorVertexModel.ConnectorVertexType == ConnectorVertexType.Start)
{
SetSourcePort(new PartCreatedConnectorInfo(connectorVertexModel.Position.X, connectorVertexModel.Position.Y));
this.ZIndex = -1;
}
else if (connectorVertexModel.ConnectorVertexType == ConnectorVertexType.End)
{
SetSinkPort(new PartCreatedConnectorInfo(connectorVertexModel.Position.X, connectorVertexModel.Position.Y));
this.ZIndex = -1;
}
break;
case nameof(ConnectorPointModel.DragStart):
if (connectorVertexModel.DragStart == false)
{
if (connectorVertexModel.ConnectorVertexType == ConnectorVertexType.Start)
{
var nearPort = Root.FindNearPortToAttachTo(this, ConnectorVertexType.Start);
if (nearPort != null)
{
SetSourcePort(nearPort);
}
}
else if (connectorVertexModel.ConnectorVertexType == ConnectorVertexType.End)
{
var nearPort = Root.FindNearPortToAttachTo(this, ConnectorVertexType.End);
if (nearPort != null)
{
SetSinkPort(nearPort);
}
}
}
break;
}
}
else if (sender is ConnectorLabelModel linkLabelModel)
@@ -613,21 +639,6 @@ namespace AIStudio.Wpf.DiagramDesigner
}
}
}
//else if (sender is PartCreatedConnectorInfo)
//{
// if (e.PropertyName == "Position")
// {
// if (sender == SourceConnectorInfoPart)
// {
// SourceA = SourceConnectorInfo.Position;
// }
// else if (sender == SinkConnectorInfoPart)
// {
// SourceB = SinkConnectorInfo.Position;
// }
// UpdatePathGeneratorResult();
// }
//}
else if (sender is ColorViewModel)
{
@@ -679,29 +690,31 @@ namespace AIStudio.Wpf.DiagramDesigner
var startVertice = Vertices.FirstOrDefault(p => p.ConnectorVertexType == ConnectorVertexType.Start);
if (startVertice == null)
{
startVertice = new ConnectorVertexModel(this, StartPoint) { ConnectorVertexType = ConnectorVertexType.Start };
startVertice.ColorViewModel.FillColor.Color = Colors.DarkRed;
startVertice.ColorViewModel.LineColor.Color = Colors.DarkRed;
Vertices.Add(startVertice);
{
startVertice = AddEndsVertex(StartPoint, ConnectorVertexType.Start);
}
else
{
IsInternalChanged = true;
startVertice.SetPosition(StartPoint);
IsInternalChanged = true;
}
startVertice.ColorViewModel.FillColor.Color = SourceConnectorInfoFully != null? Colors.DarkRed : Colors.Blue;
startVertice.ColorViewModel.LineColor.Color = SourceConnectorInfoFully != null ? Colors.DarkRed : Colors.Blue;
var endVertice = Vertices.FirstOrDefault(p => p.ConnectorVertexType == ConnectorVertexType.End);
if (endVertice == null)
{
endVertice = new ConnectorVertexModel(this, EndPoint) { ConnectorVertexType = ConnectorVertexType.End };
endVertice.ColorViewModel.FillColor.Color = Colors.DarkRed;
endVertice.ColorViewModel.LineColor.Color = Colors.DarkRed;
Vertices.Add(endVertice);
endVertice = AddEndsVertex(EndPoint, ConnectorVertexType.End);
}
else
{
IsInternalChanged = true;
endVertice.SetPosition(EndPoint);
IsInternalChanged = false;
}
endVertice.ColorViewModel.FillColor.Color = SinkConnectorInfoFully != null ? Colors.DarkRed : Colors.Blue;
endVertice.ColorViewModel.LineColor.Color = SinkConnectorInfoFully != null ? Colors.DarkRed : Colors.Blue;
var paths = Labels.Count > 0 ? PathGeneratorResult.Paths.Select(p => new SvgPath(p)).ToArray() : Array.Empty<SvgPath>();
foreach (var label in Labels)
@@ -809,12 +822,12 @@ namespace AIStudio.Wpf.DiagramDesigner
return minPoint;
}
public void SetSourcePort(FullyCreatedConnectorInfo port)
public void SetSourcePort(ConnectorInfoBase port)
{
SourceConnectorInfo = port;
}
public void SetSinkPort(FullyCreatedConnectorInfo port)
public void SetSinkPort(ConnectorInfoBase port)
{
SinkConnectorInfo = port;
}
@@ -943,6 +956,16 @@ namespace AIStudio.Wpf.DiagramDesigner
UpdatePathGeneratorResult();
}
public ConnectorVertexModel AddEndsVertex(PointBase pointBase, ConnectorVertexType connectorVertexType)
{
var vertice = new ConnectorVertexModel(this, pointBase);
vertice.ConnectorVertexType= connectorVertexType;
vertice.PropertyChanged += new WeakINPCEventHandler(Item_PropertyChanged).Handler;
Vertices.Add(vertice);
return vertice;
}
public void RemoveVertex(ConnectorVertexModel vertice)
{
Vertices.Remove(vertice);

View File

@@ -143,7 +143,10 @@ namespace AIStudio.Wpf.DiagramDesigner
{
ConnectorHeight = ScreenHelper.MmToWidth(value);
}
}
}
public virtual bool CanAttachTo(ConnectorInfoBase port)
=> port != this && !port.IsReadOnly;
#endregion
}
}

View File

@@ -144,29 +144,48 @@ namespace AIStudio.Wpf.DiagramDesigner
}
public virtual PointBase MiddlePosition => new PointBase(X, Y);
private double connectorWidth = 8;
private double _connectorWidth = 8;
public double ConnectorWidth
{
get
{
return connectorWidth;
return _connectorWidth;
}
set
{
connectorWidth = value;
_connectorWidth = value;
}
}
private double connectorHeight = 8;
private double _connectorHeight = 8;
public double ConnectorHeight
{
get
{
return connectorHeight;
return _connectorHeight;
}
set
{
connectorHeight = value;
_connectorHeight = value;
}
}
public void SetPosition(PointBase position)
{
X = position.X;
Y = position.Y;
}
private bool _dragStart;
public bool DragStart
{
get
{
return _dragStart;
}
set
{
SetProperty(ref _dragStart, value);
}
}

View File

@@ -86,13 +86,6 @@ namespace AIStudio.Wpf.DiagramDesigner
Connector.RemoveVertex(this);
}
}
public void SetPosition(PointBase position)
{
X = position.X;
Y = position.Y;
}
}
public enum ConnectorVertexType

View File

@@ -316,8 +316,17 @@ namespace AIStudio.Wpf.DiagramDesigner
}
}
public virtual bool CanAttachTo(FullyCreatedConnectorInfo port)
=> port != this && !port.IsReadOnly && DataItem != port.DataItem;
public override bool CanAttachTo(ConnectorInfoBase port)
{
if (port is FullyCreatedConnectorInfo fullyCreatedConnectorInfo)
{
return port != this && !port.IsReadOnly && DataItem != fullyCreatedConnectorInfo.DataItem;
}
else
{
return base.CanAttachTo(port);
}
}
public override string ToString()
{

View File

@@ -136,7 +136,7 @@ namespace AIStudio.Wpf.DiagramDesigner
}
public override bool CanAttachTo(FullyCreatedConnectorInfo port)
public override bool CanAttachTo(ConnectorInfoBase port)
{
if (!base.CanAttachTo(port))
{

View File

@@ -17,6 +17,11 @@ namespace AIStudio.Wpf.DiagramDesigner
{
get; set;
} = new ShortcutOption();
public SnappingOption SnappingOption
{
get; set;
} = new SnappingOption();
}
public class LayoutOption
@@ -24,6 +29,22 @@ namespace AIStudio.Wpf.DiagramDesigner
}
public class SnappingOption
{
public bool EnableSnapping
{
get; set;
}
public double SnappingRadius
{
get; set;
} = 50;
public double HittingRadius
{
get; set;
} = 20;
}
public class ShortcutOption
{
[Description("Select All shortcut (CTRL+A by default)")]

View File

@@ -3350,5 +3350,46 @@ namespace AIStudio.Wpf.DiagramDesigner
}
}
#endregion
#region
public FullyCreatedConnectorInfo FindNearPortToAttachTo(ConnectionViewModel partialConnection, ConnectorVertexType connectorVertexType)
{
if (partialConnection == null)
return null;
foreach (var port in Items.OfType<DesignerItemViewModelBase>().ToList().SelectMany(n => n.Connectors))
{
if (connectorVertexType == ConnectorVertexType.Start)
{
if (partialConnection.SourceConnectorInfo.Position.DistanceTo(port.Position) < DiagramOption.SnappingOption.HittingRadius &&
partialConnection.SinkConnectorInfo?.CanAttachTo(port) == true)
return port;
}
else if (connectorVertexType == ConnectorVertexType.End)
{
if (partialConnection.SinkConnectorInfo.Position.DistanceTo(port.Position) < DiagramOption.SnappingOption.HittingRadius &&
partialConnection.SourceConnectorInfo?.CanAttachTo(port) == true)
return port;
}
}
return null;
}
public FullyCreatedConnectorInfo FindNearPortToAttachTo(ConnectionViewModel partialConnection)
{
if (partialConnection == null)
return null;
foreach (var port in Items.OfType<DesignerItemViewModelBase>().ToList().SelectMany(n => n.Connectors))
{
if (partialConnection.OnGoingPosition.DistanceTo(port.Position) < DiagramOption.SnappingOption.SnappingRadius &&
partialConnection.SourceConnectorInfoFully?.CanAttachTo(port) == true)
return port;
}
return null;
}
#endregion
}
}

View File

@@ -147,6 +147,11 @@ namespace AIStudio.Wpf.DiagramDesigner
get;set;
}
public bool IsInternalChanged
{
get; set;
}
public IDiagramViewModel Root
{
get; set;
@@ -461,12 +466,12 @@ namespace AIStudio.Wpf.DiagramDesigner
protected virtual void Item_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (IsLoaded == false) { return; }
if (IsLoaded == false || IsInternalChanged == true) { return; }
}
protected void FontViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (IsLoaded == false) { return; }
if (IsLoaded == false || IsInternalChanged == true) { return; }
if (e.PropertyName == nameof(FontViewModel.FontCase))
{
@@ -478,21 +483,21 @@ namespace AIStudio.Wpf.DiagramDesigner
protected void ColorViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (IsLoaded == false) { return; }
if (IsLoaded == false || IsInternalChanged == true ) { return; }
RaisePropertyChanged(sender, e);
}
protected void ShapeViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (IsLoaded == false) { return; }
if (IsLoaded == false || IsInternalChanged == true) { return; }
RaisePropertyChanged(sender, e);
}
protected void AnimationViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (IsLoaded == false) { return; }
if (IsLoaded == false || IsInternalChanged == true) { return; }
RaisePropertyChanged(sender, e);
}