diff --git a/AIStudio.Wpf.DiagramDesigner/AIStudio.Wpf.DiagramDesigner.csproj b/AIStudio.Wpf.DiagramDesigner/AIStudio.Wpf.DiagramDesigner.csproj
index 81ea81a..0868aa8 100644
--- a/AIStudio.Wpf.DiagramDesigner/AIStudio.Wpf.DiagramDesigner.csproj
+++ b/AIStudio.Wpf.DiagramDesigner/AIStudio.Wpf.DiagramDesigner.csproj
@@ -8,7 +8,7 @@
A.png
- 1.1.9
+ 1.2.0
一个Wpf的Diagram控件基础库
diff --git a/AIStudio.Wpf.DiagramDesigner/Adorners/DrawingRubberbandAdorner.cs b/AIStudio.Wpf.DiagramDesigner/Adorners/DrawingRubberbandAdorner.cs
index 66319ec..06fe7b8 100644
--- a/AIStudio.Wpf.DiagramDesigner/Adorners/DrawingRubberbandAdorner.cs
+++ b/AIStudio.Wpf.DiagramDesigner/Adorners/DrawingRubberbandAdorner.cs
@@ -36,6 +36,21 @@ namespace AIStudio.Wpf.DiagramDesigner
}
}
+ private IDrawModeViewModel DrawModeViewModel
+ {
+ get
+ {
+ if (_viewModel.DrawModeViewModel != null)
+ {
+ return _viewModel.DrawModeViewModel;
+ }
+ else
+ {
+ return _service.DrawModeViewModel;
+ }
+ }
+ }
+
private DrawMode DrawMode
{
get
diff --git a/AIStudio.Wpf.DiagramDesigner/Adorners/RubberbandAdorner.cs b/AIStudio.Wpf.DiagramDesigner/Adorners/RubberbandAdorner.cs
index d2c62fd..015c7ee 100644
--- a/AIStudio.Wpf.DiagramDesigner/Adorners/RubberbandAdorner.cs
+++ b/AIStudio.Wpf.DiagramDesigner/Adorners/RubberbandAdorner.cs
@@ -36,6 +36,21 @@ namespace AIStudio.Wpf.DiagramDesigner
}
}
+ private IDrawModeViewModel DrawModeViewModel
+ {
+ get
+ {
+ if (_viewModel.DrawModeViewModel != null)
+ {
+ return _viewModel.DrawModeViewModel;
+ }
+ else
+ {
+ return _service.DrawModeViewModel;
+ }
+ }
+ }
+
public RubberbandAdorner(DesignerCanvas designerCanvas, Point? dragStartPoint)
: base(designerCanvas)
{
@@ -77,11 +92,11 @@ namespace AIStudio.Wpf.DiagramDesigner
if (adornerLayer != null)
adornerLayer.Remove(this);
- if (this._service.DrawModeViewModel.GetDrawMode() == DrawMode.Text)
+ if (this.DrawModeViewModel.GetDrawMode() == DrawMode.Text)
{
if (this.startPoint.HasValue && this.endPoint.HasValue)
{
- if (this._service.DrawModeViewModel.GetDrawMode() == DrawMode.Text)
+ if (this.DrawModeViewModel.GetDrawMode() == DrawMode.Text)
{
TextDesignerItemViewModel itemBase = new TextDesignerItemViewModel();
Point position = e.GetPosition(this);
@@ -93,7 +108,7 @@ namespace AIStudio.Wpf.DiagramDesigner
_viewModel.AddCommand.Execute(itemBase);
}
}
- this._service.DrawModeViewModel.ResetDrawMode();
+ this.DrawModeViewModel.ResetDrawMode();
}
e.Handled = true;
diff --git a/AIStudio.Wpf.DiagramDesigner/AttachedProperties/DragAndDropProps.cs b/AIStudio.Wpf.DiagramDesigner/AttachedProperties/DragAndDropProps.cs
index 8c59fdf..d927628 100644
--- a/AIStudio.Wpf.DiagramDesigner/AttachedProperties/DragAndDropProps.cs
+++ b/AIStudio.Wpf.DiagramDesigner/AttachedProperties/DragAndDropProps.cs
@@ -83,9 +83,11 @@ namespace AIStudio.Wpf.DiagramDesigner
dataObject.ContentType = toolBoxData.Type;
dataObject.DesiredSize = toolBoxData.DesiredSize;
dataObject.DesiredMinSize = toolBoxData.DesiredMinSize;
+ dataObject.ConnectorInfo = toolBoxData.ConnectorInfo;
dataObject.Icon = toolBoxData.Icon;
dataObject.Text = toolBoxData.Text;
dataObject.ColorViewModel = toolBoxData.ColorViewModel;
+ dataObject.FontViewModel = toolBoxData.FontViewModel;
if (toolBoxData.Addition is DesignerItemViewModelBase designerItemViewModelBase)
{
dataObject.DesignerItem = designerItemViewModelBase.ToSerializableItem();
diff --git a/AIStudio.Wpf.DiagramDesigner/Common/BindableBase.cs b/AIStudio.Wpf.DiagramDesigner/Common/BindableBase.cs
index 1b13bc1..90209d8 100644
--- a/AIStudio.Wpf.DiagramDesigner/Common/BindableBase.cs
+++ b/AIStudio.Wpf.DiagramDesigner/Common/BindableBase.cs
@@ -66,7 +66,7 @@ namespace AIStudio.Wpf.DiagramDesigner
if (EqualityComparer.Default.Equals(storage, value))
return false;
- if (propertyName == "IsSelected")
+ if (propertyName == "IsSelected" || propertyName == "IsReadOnly")
{
}
@@ -100,7 +100,7 @@ namespace AIStudio.Wpf.DiagramDesigner
{
if (EqualityComparer.Default.Equals(storage, value)) return false;
- if (propertyName == "IsSelected")
+ if (propertyName == "IsSelected" || propertyName == "IsReadOnly")
{
}
diff --git a/AIStudio.Wpf.DiagramDesigner/Controls/DesignerCanvas.cs b/AIStudio.Wpf.DiagramDesigner/Controls/DesignerCanvas.cs
index 87ad511..a8ad819 100644
--- a/AIStudio.Wpf.DiagramDesigner/Controls/DesignerCanvas.cs
+++ b/AIStudio.Wpf.DiagramDesigner/Controls/DesignerCanvas.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
@@ -57,7 +58,7 @@ namespace AIStudio.Wpf.DiagramDesigner
Point point = sourceDataItem.MiddlePosition;
- _partialConnection = new ConnectionViewModel(_viewModel, sourceDataItem, new PartCreatedConnectorInfo(point.X, point.Y), LineDrawMode, RouterMode);
+ _partialConnection = new ConnectionViewModel(_viewModel, sourceDataItem, new PartCreatedConnectorInfo(point.X, point.Y), DrawModeViewModel.LineDrawMode, DrawModeViewModel.LineRouterMode);
_viewModel.Add(_partialConnection);
_partialConnection.ZIndex = -1;
@@ -110,6 +111,20 @@ namespace AIStudio.Wpf.DiagramDesigner
}
}
+ private IDrawModeViewModel DrawModeViewModel
+ {
+ get
+ {
+ if (_viewModel.DrawModeViewModel != null)
+ {
+ return _viewModel.DrawModeViewModel;
+ }
+ else
+ {
+ return _service.DrawModeViewModel;
+ }
+ }
+ }
private DrawMode DrawMode
{
get
@@ -125,36 +140,6 @@ namespace AIStudio.Wpf.DiagramDesigner
}
}
- private DrawMode LineDrawMode
- {
- get
- {
- if (_viewModel.DrawModeViewModel != null)
- {
- return _viewModel.DrawModeViewModel.LineDrawMode;
- }
- else
- {
- return _service.DrawModeViewModel.LineDrawMode;
- }
- }
- }
-
- private RouterMode RouterMode
- {
- get
- {
- if (_viewModel.DrawModeViewModel != null)
- {
- return _viewModel.DrawModeViewModel.LineRouterMode;
- }
- else
- {
- return _service.DrawModeViewModel.LineRouterMode;
- }
- }
- }
-
#region GridCellSize
public static readonly DependencyProperty GridCellSizeProperty =
@@ -511,22 +496,22 @@ namespace AIStudio.Wpf.DiagramDesigner
{
if (e.PropertyName == nameof(CursorMode))
{
- if (_service.DrawModeViewModel.CursorMode == CursorMode.Format)
+ if (DrawModeViewModel.CursorMode == CursorMode.Format)
{
EnterFormat();
}
- else if (_service.DrawModeViewModel.CursorMode == CursorMode.Move)
+ else if (DrawModeViewModel.CursorMode == CursorMode.Move)
{
EnterMove();
}
- else if (_service.DrawModeViewModel.CursorMode == CursorMode.Exit)
+ else if (DrawModeViewModel.CursorMode == CursorMode.Exit)
{
ExitCursor();
}
}
- else if (e.PropertyName == nameof(_service.DrawModeViewModel.DrawingDrawMode))
+ else if (e.PropertyName == nameof(DrawModeViewModel.DrawingDrawMode))
{
- if (_service.DrawModeViewModel.DrawingDrawMode == DrawMode.ColorPicker)
+ if (DrawModeViewModel.DrawingDrawMode == DrawMode.ColorPicker)
{
EnterColorPicker();
}
@@ -576,7 +561,7 @@ namespace AIStudio.Wpf.DiagramDesigner
{
item.IsHitTestVisible = true;
}
- _service.DrawModeViewModel.CursorMode = CursorMode.Normal;
+ DrawModeViewModel.CursorMode = CursorMode.Normal;
}
private void Format(SelectableDesignerItemViewModelBase source, SelectableDesignerItemViewModelBase target)
@@ -596,7 +581,7 @@ namespace AIStudio.Wpf.DiagramDesigner
- if (_service.DrawModeViewModel.CursorMode == CursorMode.Format)
+ if (DrawModeViewModel.CursorMode == CursorMode.Format)
{
var element = (e.OriginalSource as FrameworkElement);
if (element.DataContext is SelectableDesignerItemViewModelBase target)
@@ -607,7 +592,7 @@ namespace AIStudio.Wpf.DiagramDesigner
ExitCursor();
}
- else if (_service.DrawModeViewModel.CursorMode == CursorMode.Move)
+ else if (DrawModeViewModel.CursorMode == CursorMode.Move)
{
ExitCursor();
return;
@@ -629,8 +614,8 @@ namespace AIStudio.Wpf.DiagramDesigner
}
- if (_service.DrawModeViewModel.SharpDrawModeSelected ||
- (_service.DrawModeViewModel.DrawingDrawModeSelected && _service.DrawModeViewModel.DrawingDrawMode != DrawMode.Select))
+ if (DrawModeViewModel.SharpDrawModeSelected ||
+ (DrawModeViewModel.DrawingDrawModeSelected && DrawModeViewModel.DrawingDrawMode != DrawMode.Select))
{
// create rubberband adorner
AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this);
@@ -643,7 +628,7 @@ namespace AIStudio.Wpf.DiagramDesigner
}
}
}
- else if (_service.DrawModeViewModel.LineDrawModeSelected)//画线模式,可以不命中实体
+ else if (DrawModeViewModel.LineDrawModeSelected)//画线模式,可以不命中实体
{
if (SourceConnector == null)
{
@@ -676,7 +661,7 @@ namespace AIStudio.Wpf.DiagramDesigner
_viewModel.CurrentColor = ColorPickerManager.GetColor(point.X, point.Y);
//移动
- if (_service.DrawModeViewModel.CursorMode == CursorMode.Move)
+ if (DrawModeViewModel.CursorMode == CursorMode.Move)
{
_viewModel.SelectedItems.OfType().ToList().ForEach(p => {
p.Left = currentPoint.X;
@@ -692,7 +677,7 @@ namespace AIStudio.Wpf.DiagramDesigner
_partialConnection.SinkConnectorInfo = new PartCreatedConnectorInfo(currentPoint.X, currentPoint.Y);
SinkConnector = HitTesting(currentPoint);
- if (SinkConnector?.Info?.CanAttachTo(SourceConnector?.Info) == false)
+ if (SinkConnector != SourceConnector && SinkConnector?.Info?.CanAttachTo(SourceConnector?.Info) == false)
{
SinkConnector.Info.DisableAttachTo = true;
}
@@ -759,19 +744,19 @@ namespace AIStudio.Wpf.DiagramDesigner
ConnectorInfoBase sinkDataItem = SinkConnector.Info;
_viewModel.Delete(_partialConnection);
- _viewModel.AddCommand.Execute(new ConnectionViewModel(_viewModel, sourceDataItem, sinkDataItem, LineDrawMode, RouterMode));
+ _viewModel.AddCommand.Execute(new ConnectionViewModel(_viewModel, sourceDataItem, sinkDataItem, DrawModeViewModel.LineDrawMode, DrawModeViewModel.LineRouterMode));
}
else if (_partialConnection.IsFullConnection)//自动连接模式
{
_viewModel.ClearAttachTo();
}
- else if (_service.DrawModeViewModel.LineDrawModeSelected)
+ else if (DrawModeViewModel.LineDrawModeSelected)
{
Point currentPoint = e.GetPosition(this);
ConnectorInfoBase sinkDataItem = new PartCreatedConnectorInfo(currentPoint.X, currentPoint.Y);
_viewModel.Delete(_partialConnection);
- _viewModel.AddCommand.Execute(new ConnectionViewModel(_viewModel, sourceDataItem, sinkDataItem, LineDrawMode, RouterMode));
+ _viewModel.AddCommand.Execute(new ConnectionViewModel(_viewModel, sourceDataItem, sinkDataItem, DrawModeViewModel.LineDrawMode, DrawModeViewModel.LineRouterMode));
}
else
{
@@ -791,7 +776,7 @@ namespace AIStudio.Wpf.DiagramDesigner
SourceItemsContainer = null;
- _service.DrawModeViewModel.ResetDrawMode();
+ DrawModeViewModel.ResetDrawMode();
}
protected override void OnPreviewKeyDown(KeyEventArgs e)
@@ -944,6 +929,10 @@ namespace AIStudio.Wpf.DiagramDesigner
itemBase.MinItemWidth = dragObject.DesiredMinSize.Value.Width;
itemBase.MinItemHeight = dragObject.DesiredMinSize.Value.Height;
}
+ if (dragObject.ConnectorInfo != null)
+ {
+ InitConnectorInfo(itemBase, dragObject.ConnectorInfo);
+ }
_viewModel.AddCommand.Execute(itemBase);
if (itemBase is BlockDesignerItemViewModel block)
@@ -966,6 +955,7 @@ namespace AIStudio.Wpf.DiagramDesigner
if (!string.IsNullOrEmpty(dragObject.Icon))
itemBase.Icon = dragObject.Icon;
itemBase.ColorViewModel = CopyHelper.Mapper(dragObject.ColorViewModel);
+ itemBase.FontViewModel = CopyHelper.Mapper(dragObject.FontViewModel);
if (dragObject.DesiredSize != null)
{
itemBase.ItemWidth = dragObject.DesiredSize.Value.Width;
@@ -976,7 +966,10 @@ namespace AIStudio.Wpf.DiagramDesigner
itemBase.MinItemWidth = dragObject.DesiredMinSize.Value.Width;
itemBase.MinItemHeight = dragObject.DesiredMinSize.Value.Height;
}
-
+ if (dragObject.ConnectorInfo != null)
+ {
+ InitConnectorInfo(itemBase, dragObject.ConnectorInfo);
+ }
}
itemBase.Left = Math.Max(0, position.X - itemBase.GetItemWidth() / 2);
itemBase.Top = Math.Max(0, position.Y - itemBase.GetItemHeight() / 2);
@@ -1013,5 +1006,14 @@ namespace AIStudio.Wpf.DiagramDesigner
this.Focus();
}
+
+ private void InitConnectorInfo(DesignerItemViewModelBase itemBase, List connectorInfos)
+ {
+ itemBase.ClearConnectors();
+ foreach (var connectorInfo in connectorInfos)
+ {
+ itemBase.AddConnector(new FullyCreatedConnectorInfo(itemBase, connectorInfo.Orientation, connectorInfo.IsInnerPoint, connectorInfo.IsPortless) { XRatio = connectorInfo.XRatio, YRatio = connectorInfo.YRatio });
+ }
+ }
}
}
\ No newline at end of file
diff --git a/AIStudio.Wpf.DiagramDesigner/Helpers/CopyHelper.cs b/AIStudio.Wpf.DiagramDesigner/Helpers/CopyHelper.cs
index 7334b74..13516bb 100644
--- a/AIStudio.Wpf.DiagramDesigner/Helpers/CopyHelper.cs
+++ b/AIStudio.Wpf.DiagramDesigner/Helpers/CopyHelper.cs
@@ -90,15 +90,18 @@ namespace AIStudio.Wpf.DiagramDesigner
D d = Activator.CreateInstance(); //构造新实例
try
{
- var Types = s.GetType();//获得类型
- var Typed = typeof(D);
- foreach (PropertyInfo sp in Types.GetProperties().Where(p => p.CanRead))//获得类型的属性字段
+ if (s != null)
{
- foreach (PropertyInfo dp in Typed.GetProperties().Where(p => p.CanWrite))
+ var Types = s.GetType();//获得类型
+ var Typed = typeof(D);
+ foreach (PropertyInfo sp in Types.GetProperties().Where(p => p.CanRead))//获得类型的属性字段
{
- if (dp.Name == sp.Name && dp.PropertyType == sp.PropertyType)//判断属性名是否相同
+ foreach (PropertyInfo dp in Typed.GetProperties().Where(p => p.CanWrite))
{
- dp.SetValue(d, sp.GetValue(s, null), null);//获得s对象属性的值复制给d对象的属性
+ if (dp.Name == sp.Name && dp.PropertyType == sp.PropertyType)//判断属性名是否相同
+ {
+ dp.SetValue(d, sp.GetValue(s, null), null);//获得s对象属性的值复制给d对象的属性
+ }
}
}
}
diff --git a/AIStudio.Wpf.DiagramDesigner/Models/DragObject.cs b/AIStudio.Wpf.DiagramDesigner/Models/DragObject.cs
index 74720f2..4d30b99 100644
--- a/AIStudio.Wpf.DiagramDesigner/Models/DragObject.cs
+++ b/AIStudio.Wpf.DiagramDesigner/Models/DragObject.cs
@@ -17,6 +17,10 @@ namespace AIStudio.Wpf.DiagramDesigner
{
get; set;
}
+ public List ConnectorInfo
+ {
+ get; set;
+ }
public Type ContentType
{
get; set;
@@ -33,9 +37,16 @@ namespace AIStudio.Wpf.DiagramDesigner
{
get; set;
}
+
+ public IFontViewModel FontViewModel
+ {
+ get; set;
+ }
public object DesignerItem
{
get; set;
}
+
+
}
}
diff --git a/AIStudio.Wpf.DiagramDesigner/Models/ToolBoxData.cs b/AIStudio.Wpf.DiagramDesigner/Models/ToolBoxData.cs
index d18a121..9466fcf 100644
--- a/AIStudio.Wpf.DiagramDesigner/Models/ToolBoxData.cs
+++ b/AIStudio.Wpf.DiagramDesigner/Models/ToolBoxData.cs
@@ -25,6 +25,10 @@ namespace AIStudio.Wpf.DiagramDesigner
{
get; set;
}
+ public IFontViewModel FontViewModel
+ {
+ get; set;
+ }
public double Width
{
get; set;
@@ -41,6 +45,10 @@ namespace AIStudio.Wpf.DiagramDesigner
{
get; set;
}
+ public List ConnectorInfo
+ {
+ get; set;
+ }
public string Description
{
get; set;
diff --git a/AIStudio.Wpf.DiagramDesigner/Routers/Pather.cs b/AIStudio.Wpf.DiagramDesigner/Routers/Pather.cs
new file mode 100644
index 0000000..bb65477
--- /dev/null
+++ b/AIStudio.Wpf.DiagramDesigner/Routers/Pather.cs
@@ -0,0 +1,727 @@
+using System;
+using System.Collections.Generic;
+using System.Windows;
+using System.Windows.Documents;
+using AIStudio.Wpf.DiagramDesigner.Geometrys;
+
+namespace AIStudio.Wpf.DiagramDesigner
+{
+ internal class PathFinder
+ {
+ const int margin = 8;
+ const double CORNER = 6;
+
+ private static List AddCornerPoints(List linePoints)
+ {
+ if (linePoints.Count < 3 || CORNER <= 0) return linePoints;
+ List points = new List();
+ points.Add(linePoints[0]);
+ for (int i = 1; i < linePoints.Count - 1; i++)
+ {
+ double x1 = linePoints[i].X;
+ double x0 = linePoints[i - 1].X;
+ double y1 = linePoints[i].Y;
+ double y0 = linePoints[i - 1].Y;
+ if (x1 == x0)
+ {
+ double x2 = linePoints[i + 1].X;
+ if (y1 > y0)
+ {
+ if (y1 - y0 > CORNER && Math.Abs(x2 - x1) > CORNER)
+ {
+ points.Add(new PointBase(x1, y1 - CORNER));
+ points.Add(new PointBase(x2 > x1 ? x1 + CORNER : x1 - CORNER, y1));
+ }
+ }
+ else
+ {
+ if (y0 - y1 > CORNER && Math.Abs(x2 - x1) > CORNER)
+ {
+ points.Add(new PointBase(x1, y1 + CORNER));
+ points.Add(new PointBase(x2 > x1 ? x1 + CORNER : x1 - CORNER, y1));
+ }
+ }
+ }
+ else if (y1 == y0)
+ {
+ double y2 = linePoints[i + 1].Y;
+ if (x1 > x0)
+ {
+ if (x1 - x0 > CORNER && Math.Abs(y2 - y1) > CORNER)
+ {
+ points.Add(new PointBase(x1 - CORNER, y1));
+ points.Add(new PointBase(x1, y2 > y1 ? y1 + CORNER : y1 - CORNER));
+ }
+ }
+ else
+ {
+ if (x0 - x1 > CORNER && Math.Abs(y2 - y1) > CORNER)
+ {
+ points.Add(new PointBase(x1 + CORNER, y1));
+ points.Add(new PointBase(x1, y2 > y1 ? y1 + CORNER : y1 - CORNER));
+ }
+ }
+ }
+ }
+ points.Add(linePoints[linePoints.Count - 1]);
+ return points.Count % 2 == 0 ? points : linePoints;
+ }
+
+ internal static List GetDirectLine(ConnectorInfoBase source, ConnectorInfoBase sink)
+ {
+ List linePoints = new List();
+ linePoints.Add(source.MiddlePosition);
+ linePoints.Add(sink.MiddlePosition);
+ return linePoints;
+ }
+
+ internal static List GetConnectionLine(ConnectorInfoBase source, ConnectorInfoBase sink, bool showLastLine)
+ {
+ List linePoints = new List();
+
+ RectangleBase rectSource = GetRectWithMargin(source, margin);
+ RectangleBase rectSink = GetRectWithMargin(sink, margin);
+
+ PointBase startPoint = GetOffsetPoint(source, rectSource);
+ PointBase endPoint = GetOffsetPoint(sink, rectSink);
+
+ linePoints.Add(startPoint);
+ PointBase currentPoint = startPoint;
+
+ if (!rectSink.Contains(currentPoint) && !rectSource.Contains(endPoint))
+ {
+ while (true)
+ {
+ #region source node
+
+ if (IsPointVisible(currentPoint, endPoint, new RectangleBase[] { rectSource, rectSink }))
+ {
+ linePoints.Add(endPoint);
+ currentPoint = endPoint;
+ break;
+ }
+
+ PointBase neighbour = GetNearestVisibleNeighborSink(currentPoint, endPoint, sink, rectSource, rectSink);
+ if (!double.IsNaN(neighbour.X))
+ {
+ linePoints.Add(neighbour);
+ linePoints.Add(endPoint);
+ currentPoint = endPoint;
+ break;
+ }
+
+ if (currentPoint == startPoint)
+ {
+ bool flag;
+ PointBase n = GetNearestNeighborSource(source, endPoint, rectSource, rectSink, out flag);
+ linePoints.Add(n);
+ currentPoint = n;
+
+ if (!IsRectVisible(currentPoint, rectSink, new RectangleBase[] { rectSource }))
+ {
+ PointBase n1, n2;
+ GetOppositeCorners(source.Orientation, rectSource, out n1, out n2);
+ if (flag)
+ {
+ linePoints.Add(n1);
+ currentPoint = n1;
+ }
+ else
+ {
+ linePoints.Add(n2);
+ currentPoint = n2;
+ }
+ if (!IsRectVisible(currentPoint, rectSink, new RectangleBase[] { rectSource }))
+ {
+ if (flag)
+ {
+ linePoints.Add(n2);
+ currentPoint = n2;
+ }
+ else
+ {
+ linePoints.Add(n1);
+ currentPoint = n1;
+ }
+ }
+ }
+ }
+ #endregion
+
+ #region sink node
+
+ else // from here on we jump to the sink node
+ {
+ PointBase n1, n2; // neighbour corner
+ PointBase s1, s2; // opposite corner
+ GetNeighborCorners(sink.Orientation, rectSink, out s1, out s2);
+ GetOppositeCorners(sink.Orientation, rectSink, out n1, out n2);
+
+ bool n1Visible = IsPointVisible(currentPoint, n1, new RectangleBase[] { rectSource, rectSink });
+ bool n2Visible = IsPointVisible(currentPoint, n2, new RectangleBase[] { rectSource, rectSink });
+
+ if (n1Visible && n2Visible)
+ {
+ if (rectSource.Contains(n1))
+ {
+ linePoints.Add(n2);
+ if (rectSource.Contains(s2))
+ {
+ linePoints.Add(n1);
+ linePoints.Add(s1);
+ }
+ else
+ linePoints.Add(s2);
+
+ linePoints.Add(endPoint);
+ currentPoint = endPoint;
+ break;
+ }
+
+ if (rectSource.Contains(n2))
+ {
+ linePoints.Add(n1);
+ if (rectSource.Contains(s1))
+ {
+ linePoints.Add(n2);
+ linePoints.Add(s2);
+ }
+ else
+ linePoints.Add(s1);
+
+ linePoints.Add(endPoint);
+ currentPoint = endPoint;
+ break;
+ }
+
+ if ((Distance(n1, endPoint) <= Distance(n2, endPoint)))
+ {
+ linePoints.Add(n1);
+ if (rectSource.Contains(s1))
+ {
+ linePoints.Add(n2);
+ linePoints.Add(s2);
+ }
+ else
+ linePoints.Add(s1);
+ linePoints.Add(endPoint);
+ currentPoint = endPoint;
+ break;
+ }
+ else
+ {
+ linePoints.Add(n2);
+ if (rectSource.Contains(s2))
+ {
+ linePoints.Add(n1);
+ linePoints.Add(s1);
+ }
+ else
+ linePoints.Add(s2);
+ linePoints.Add(endPoint);
+ currentPoint = endPoint;
+ break;
+ }
+ }
+ else if (n1Visible)
+ {
+ linePoints.Add(n1);
+ if (rectSource.Contains(s1))
+ {
+ linePoints.Add(n2);
+ linePoints.Add(s2);
+ }
+ else
+ linePoints.Add(s1);
+ linePoints.Add(endPoint);
+ currentPoint = endPoint;
+ break;
+ }
+ else
+ {
+ linePoints.Add(n2);
+ if (rectSource.Contains(s2))
+ {
+ linePoints.Add(n1);
+ linePoints.Add(s1);
+ }
+ else
+ linePoints.Add(s2);
+ linePoints.Add(endPoint);
+ currentPoint = endPoint;
+ break;
+ }
+ }
+ #endregion
+ }
+ }
+ else
+ {
+ linePoints.Add(endPoint);
+ }
+
+ linePoints = OptimizeLinePoints(linePoints, new RectangleBase[] { rectSource, rectSink }, source.Orientation, sink.Orientation);
+
+ CheckPathEnd(source, sink, showLastLine, linePoints);
+ //return linePoints;
+ return AddCornerPoints(linePoints);
+ }
+
+ internal static List GetConnectionLine(ConnectorInfoBase source, PointBase sinkPoint, ConnectorOrientation preferredOrientation)
+ {
+ List linePoints = new List();
+ RectangleBase rectSource = GetRectWithMargin(source, 5);
+ PointBase startPoint = GetOffsetPoint(source, rectSource);
+ PointBase endPoint = sinkPoint;
+
+ linePoints.Add(startPoint);
+ PointBase currentPoint = startPoint;
+
+ if (!rectSource.Contains(endPoint))
+ {
+ while (true)
+ {
+ if (IsPointVisible(currentPoint, endPoint, new RectangleBase[] { rectSource }))
+ {
+ linePoints.Add(endPoint);
+ break;
+ }
+
+ bool sideFlag;
+ PointBase n = GetNearestNeighborSource(source, endPoint, rectSource, out sideFlag);
+ linePoints.Add(n);
+ currentPoint = n;
+
+ if (IsPointVisible(currentPoint, endPoint, new RectangleBase[] { rectSource }))
+ {
+ linePoints.Add(endPoint);
+ break;
+ }
+ else
+ {
+ PointBase n1, n2;
+ GetOppositeCorners(source.Orientation, rectSource, out n1, out n2);
+ if (sideFlag)
+ linePoints.Add(n1);
+ else
+ linePoints.Add(n2);
+
+ linePoints.Add(endPoint);
+ break;
+ }
+ }
+ }
+ else
+ {
+ linePoints.Add(endPoint);
+ }
+
+ if (preferredOrientation != ConnectorOrientation.None)
+ linePoints = OptimizeLinePoints(linePoints, new RectangleBase[] { rectSource }, source.Orientation, preferredOrientation);
+ else
+ linePoints = OptimizeLinePoints(linePoints, new RectangleBase[] { rectSource }, source.Orientation, GetOpositeOrientation(source.Orientation));
+
+ return linePoints;
+ }
+
+ private static List OptimizeLinePoints(List linePoints, RectangleBase[] rectangles, ConnectorOrientation sourceOrientation, ConnectorOrientation sinkOrientation)
+ {
+ List points = new List();
+ int cut = 0;
+
+ for (int i = 0; i < linePoints.Count; i++)
+ {
+ if (i >= cut)
+ {
+ for (int k = linePoints.Count - 1; k > i; k--)
+ {
+ if (IsPointVisible(linePoints[i], linePoints[k], rectangles))
+ {
+ cut = k;
+ break;
+ }
+ }
+ points.Add(linePoints[i]);
+ }
+ }
+
+ #region Line
+ for (int j = 0; j < points.Count - 1; j++)
+ {
+ if (points[j].X != points[j + 1].X && points[j].Y != points[j + 1].Y)
+ {
+ ConnectorOrientation orientationFrom;
+ ConnectorOrientation orientationTo;
+
+ // orientation from point
+ if (j == 0)
+ orientationFrom = sourceOrientation;
+ else
+ orientationFrom = GetOrientation(points[j], points[j - 1]);
+
+ // orientation to pint
+ if (j == points.Count - 2)
+ orientationTo = sinkOrientation;
+ else
+ orientationTo = GetOrientation(points[j + 1], points[j + 2]);
+
+
+ if ((orientationFrom == ConnectorOrientation.Left || orientationFrom == ConnectorOrientation.Right) &&
+ (orientationTo == ConnectorOrientation.Left || orientationTo == ConnectorOrientation.Right))
+ {
+ double centerX = Math.Min(points[j].X, points[j + 1].X) + Math.Abs(points[j].X - points[j + 1].X) / 2;
+ points.Insert(j + 1, new PointBase(centerX, points[j].Y));
+ points.Insert(j + 2, new PointBase(centerX, points[j + 2].Y));
+ if (points.Count - 1 > j + 3)
+ points.RemoveAt(j + 3);
+ return points;
+ }
+
+ if ((orientationFrom == ConnectorOrientation.Top || orientationFrom == ConnectorOrientation.Bottom) &&
+ (orientationTo == ConnectorOrientation.Top || orientationTo == ConnectorOrientation.Bottom))
+ {
+ double centerY = Math.Min(points[j].Y, points[j + 1].Y) + Math.Abs(points[j].Y - points[j + 1].Y) / 2;
+ points.Insert(j + 1, new PointBase(points[j].X, centerY));
+ points.Insert(j + 2, new PointBase(points[j + 2].X, centerY));
+ if (points.Count - 1 > j + 3)
+ points.RemoveAt(j + 3);
+ return points;
+ }
+
+ if ((orientationFrom == ConnectorOrientation.Left || orientationFrom == ConnectorOrientation.Right) &&
+ (orientationTo == ConnectorOrientation.Top || orientationTo == ConnectorOrientation.Bottom))
+ {
+ points.Insert(j + 1, new PointBase(points[j + 1].X, points[j].Y));
+ return points;
+ }
+
+ if ((orientationFrom == ConnectorOrientation.Top || orientationFrom == ConnectorOrientation.Bottom) &&
+ (orientationTo == ConnectorOrientation.Left || orientationTo == ConnectorOrientation.Right))
+ {
+ points.Insert(j + 1, new PointBase(points[j].X, points[j + 1].Y));
+ return points;
+ }
+ }
+ }
+ #endregion
+
+ return points;
+ }
+
+ private static ConnectorOrientation GetOrientation(PointBase p1, PointBase p2)
+ {
+ if (p1.X == p2.X)
+ {
+ if (p1.Y >= p2.Y)
+ return ConnectorOrientation.Bottom;
+ else
+ return ConnectorOrientation.Top;
+ }
+ else if (p1.Y == p2.Y)
+ {
+ if (p1.X >= p2.X)
+ return ConnectorOrientation.Right;
+ else
+ return ConnectorOrientation.Left;
+ }
+ throw new Exception("Failed to retrieve orientation");
+ }
+ /*
+ private static Orientation GetOrientation(ConnectorOrientation sourceOrientation)
+ {
+ switch (sourceOrientation)
+ {
+ case ConnectorOrientation.Left:
+ return Orientation.Horizontal;
+ case ConnectorOrientation.Top:
+ return Orientation.Vertical;
+ case ConnectorOrientation.Right:
+ return Orientation.Horizontal;
+ case ConnectorOrientation.Bottom:
+ return Orientation.Vertical;
+ default:
+ throw new Exception("Unknown ConnectorOrientation");
+ }
+ }*/
+
+ private static PointBase GetNearestNeighborSource(ConnectorInfoBase source, PointBase endPoint, RectangleBase rectSource, RectangleBase rectSink, out bool flag)
+ {
+ PointBase n1, n2; // neighbors
+ GetNeighborCorners(source.Orientation, rectSource, out n1, out n2);
+
+ if (rectSink.Contains(n1))
+ {
+ flag = false;
+ return n2;
+ }
+
+ if (rectSink.Contains(n2))
+ {
+ flag = true;
+ return n1;
+ }
+
+ if ((Distance(n1, endPoint) <= Distance(n2, endPoint)))
+ {
+ flag = true;
+ return n1;
+ }
+ else
+ {
+ flag = false;
+ return n2;
+ }
+ }
+
+ private static PointBase GetNearestNeighborSource(ConnectorInfoBase source, PointBase endPoint, RectangleBase rectSource, out bool flag)
+ {
+ PointBase n1, n2; // neighbors
+ GetNeighborCorners(source.Orientation, rectSource, out n1, out n2);
+
+ if ((Distance(n1, endPoint) <= Distance(n2, endPoint)))
+ {
+ flag = true;
+ return n1;
+ }
+ else
+ {
+ flag = false;
+ return n2;
+ }
+ }
+
+ private static PointBase GetNearestVisibleNeighborSink(PointBase currentPoint, PointBase endPoint, ConnectorInfoBase sink, RectangleBase rectSource, RectangleBase rectSink)
+ {
+ PointBase s1, s2; // neighbors on sink side
+ GetNeighborCorners(sink.Orientation, rectSink, out s1, out s2);
+
+ bool flag1 = IsPointVisible(currentPoint, s1, new RectangleBase[] { rectSource, rectSink });
+ bool flag2 = IsPointVisible(currentPoint, s2, new RectangleBase[] { rectSource, rectSink });
+
+ if (flag1) // s1 visible
+ {
+ if (flag2) // s1 and s2 visible
+ {
+ if (rectSink.Contains(s1))
+ return s2;
+
+ if (rectSink.Contains(s2))
+ return s1;
+
+ if ((Distance(s1, endPoint) <= Distance(s2, endPoint)))
+ return s1;
+ else
+ return s2;
+
+ }
+ else
+ {
+ return s1;
+ }
+ }
+ else // s1 not visible
+ {
+ if (flag2) // only s2 visible
+ {
+ return s2;
+ }
+ else // s1 and s2 not visible
+ {
+ return new PointBase(double.NaN, double.NaN);
+ }
+ }
+ }
+
+ private static bool IsPointVisible(PointBase fromPoint, PointBase targetPoint, RectangleBase[] rectangles)
+ {
+ foreach (RectangleBase rect in rectangles)
+ {
+ if (RectangleIntersectsLine(rect, fromPoint, targetPoint))
+ return false;
+ }
+ return true;
+ }
+
+ private static bool IsRectVisible(PointBase fromPoint, RectangleBase targetRect, RectangleBase[] rectangles)
+ {
+ if (IsPointVisible(fromPoint, targetRect.TopLeft, rectangles))
+ return true;
+
+ if (IsPointVisible(fromPoint, targetRect.TopRight, rectangles))
+ return true;
+
+ if (IsPointVisible(fromPoint, targetRect.BottomLeft, rectangles))
+ return true;
+
+ if (IsPointVisible(fromPoint, targetRect.BottomRight, rectangles))
+ return true;
+
+ return false;
+ }
+
+ private static bool RectangleIntersectsLine(RectangleBase rect, PointBase startPoint, PointBase endPoint)
+ {
+ rect.Inflate(-1, -1);
+ return rect.IntersectsWith(new RectangleBase(startPoint, endPoint));
+ }
+
+ private static void GetOppositeCorners(ConnectorOrientation orientation, RectangleBase rect, out PointBase n1, out PointBase n2)
+ {
+ switch (orientation)
+ {
+ case ConnectorOrientation.Left:
+ n1 = rect.TopRight; n2 = rect.BottomRight;
+ break;
+ case ConnectorOrientation.Top:
+ n1 = rect.BottomLeft; n2 = rect.BottomRight;
+ break;
+ case ConnectorOrientation.Right:
+ n1 = rect.TopLeft; n2 = rect.BottomLeft;
+ break;
+ case ConnectorOrientation.Bottom:
+ n1 = rect.TopLeft; n2 = rect.TopRight;
+ break;
+ default:
+ throw new Exception("No opposite corners found!");
+ }
+ }
+
+ private static void GetNeighborCorners(ConnectorOrientation orientation, RectangleBase rect, out PointBase n1, out PointBase n2)
+ {
+ switch (orientation)
+ {
+ case ConnectorOrientation.Left:
+ n1 = rect.TopLeft; n2 = rect.BottomLeft;
+ break;
+ case ConnectorOrientation.Top:
+ n1 = rect.TopLeft; n2 = rect.TopRight;
+ break;
+ case ConnectorOrientation.Right:
+ n1 = rect.TopRight; n2 = rect.BottomRight;
+ break;
+ case ConnectorOrientation.Bottom:
+ n1 = rect.BottomLeft; n2 = rect.BottomRight;
+ break;
+ default:
+ throw new Exception("No neighour corners found!");
+ }
+ }
+
+ private static double Distance(PointBase p1, PointBase p2)
+ {
+ return PointBase.Subtract(p1, p2).Length;
+ }
+
+ private static RectangleBase GetRectWithMargin(ConnectorInfoBase connectorThumb, double margin)
+ {
+ RectangleBase rect;
+ if (connectorThumb is FullyCreatedConnectorInfo fullyCreated)
+ {
+ rect = fullyCreated.DataItem.GetBounds();
+ }
+ else
+ {
+ rect = new RectangleBase();
+ }
+
+ rect.Inflate(margin, margin);
+ return rect;
+ }
+
+ private static PointBase GetOffsetPoint(ConnectorInfoBase connector, RectangleBase rect)
+ {
+ PointBase offsetPoint = new PointBase();
+
+ switch (connector.Orientation)
+ {
+ case ConnectorOrientation.Left:
+ offsetPoint = new PointBase(rect.Left, connector.MiddlePosition.Y);
+ break;
+ case ConnectorOrientation.Top:
+ offsetPoint = new PointBase(connector.MiddlePosition.X, rect.Top);
+ break;
+ case ConnectorOrientation.Right:
+ offsetPoint = new PointBase(rect.Right, connector.MiddlePosition.Y);
+ break;
+ case ConnectorOrientation.Bottom:
+ offsetPoint = new PointBase(connector.MiddlePosition.X, rect.Bottom);
+ break;
+ default:
+ break;
+ }
+
+ return offsetPoint;
+ }
+
+ private static void CheckPathEnd(ConnectorInfoBase source, ConnectorInfoBase sink, bool showLastLine, List linePoints)
+ {
+ if (showLastLine)
+ {
+ PointBase startPoint = new PointBase(0, 0);
+ PointBase endPoint = new PointBase(0, 0);
+ double marginPath = 10;
+ switch (source.Orientation)
+ {
+ case ConnectorOrientation.Left:
+ startPoint = new PointBase(source.MiddlePosition.X - marginPath, source.MiddlePosition.Y);
+ break;
+ case ConnectorOrientation.Top:
+ startPoint = new PointBase(source.MiddlePosition.X, source.MiddlePosition.Y - marginPath);
+ break;
+ case ConnectorOrientation.Right:
+ startPoint = new PointBase(source.MiddlePosition.X + marginPath, source.MiddlePosition.Y);
+ break;
+ case ConnectorOrientation.Bottom:
+ startPoint = new PointBase(source.MiddlePosition.X, source.MiddlePosition.Y + marginPath);
+ break;
+ default:
+ break;
+ }
+
+ switch (sink.Orientation)
+ {
+ case ConnectorOrientation.Left:
+ endPoint = new PointBase(sink.MiddlePosition.X - marginPath, sink.MiddlePosition.Y);
+ break;
+ case ConnectorOrientation.Top:
+ endPoint = new PointBase(sink.MiddlePosition.X, sink.MiddlePosition.Y - marginPath);
+ break;
+ case ConnectorOrientation.Right:
+ endPoint = new PointBase(sink.MiddlePosition.X + marginPath, sink.MiddlePosition.Y);
+ break;
+ case ConnectorOrientation.Bottom:
+ endPoint = new PointBase(sink.MiddlePosition.X, sink.MiddlePosition.Y + marginPath);
+ break;
+ default:
+ break;
+ }
+ linePoints.Insert(0, startPoint);
+ linePoints.Add(endPoint);
+ }
+ else
+ {
+ linePoints.Insert(0, source.MiddlePosition);
+ linePoints.Add(sink.MiddlePosition);
+ }
+ }
+
+ private static ConnectorOrientation GetOpositeOrientation(ConnectorOrientation connectorOrientation)
+ {
+ switch (connectorOrientation)
+ {
+ case ConnectorOrientation.Left:
+ return ConnectorOrientation.Right;
+ case ConnectorOrientation.Top:
+ return ConnectorOrientation.Bottom;
+ case ConnectorOrientation.Right:
+ return ConnectorOrientation.Left;
+ case ConnectorOrientation.Bottom:
+ return ConnectorOrientation.Top;
+ default:
+ return ConnectorOrientation.Top;
+ }
+ }
+ }
+
+
+}
diff --git a/AIStudio.Wpf.DiagramDesigner/UserControls/ConnectorContainer.xaml.cs b/AIStudio.Wpf.DiagramDesigner/UserControls/ConnectorContainer.xaml.cs
index b62c47b..7210616 100644
--- a/AIStudio.Wpf.DiagramDesigner/UserControls/ConnectorContainer.xaml.cs
+++ b/AIStudio.Wpf.DiagramDesigner/UserControls/ConnectorContainer.xaml.cs
@@ -38,6 +38,8 @@ namespace AIStudio.Wpf.DiagramDesigner
var connector = ItemContainerGenerator.ContainerFromItem(item) as ContentPresenter;
if (connector != null)
{
+ vm.PropertyChanged -= Vm_PropertyChanged;
+ vm.PropertyChanged += Vm_PropertyChanged;
Canvas.SetLeft(connector, vm.DataItem.GetItemWidth() * vm.XRatio - vm.ConnectorWidth / 2);
Canvas.SetTop(connector, vm.DataItem.GetItemHeight() * vm.YRatio - vm.ConnectorHeight / 2);
}
@@ -65,6 +67,21 @@ namespace AIStudio.Wpf.DiagramDesigner
{
var vm = connector.DataContext as FullyCreatedConnectorInfo;
if (vm != null)
+ {
+ vm.PropertyChanged -= Vm_PropertyChanged;
+ vm.PropertyChanged += Vm_PropertyChanged;
+ Canvas.SetLeft(connector, vm.DataItem.GetItemWidth() * vm.XRatio - vm.ConnectorWidth / 2);
+ Canvas.SetTop(connector, vm.DataItem.GetItemHeight() * vm.YRatio - vm.ConnectorHeight / 2);
+ }
+ }
+ }
+
+ private void Vm_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
+ {
+ if (sender is FullyCreatedConnectorInfo vm)
+ {
+ var connector = ItemContainerGenerator.ContainerFromItem(vm) as ContentPresenter;
+ if (connector != null)
{
Canvas.SetLeft(connector, vm.DataItem.GetItemWidth() * vm.XRatio - vm.ConnectorWidth / 2);
Canvas.SetTop(connector, vm.DataItem.GetItemHeight() * vm.YRatio - vm.ConnectorHeight / 2);
diff --git a/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/Connector/FullyCreatedConnectorInfo.cs b/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/Connector/FullyCreatedConnectorInfo.cs
index e17cfd5..f6db966 100644
--- a/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/Connector/FullyCreatedConnectorInfo.cs
+++ b/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/Connector/FullyCreatedConnectorInfo.cs
@@ -11,6 +11,10 @@ namespace AIStudio.Wpf.DiagramDesigner
{
public class FullyCreatedConnectorInfo : ConnectorInfoBase
{
+ public FullyCreatedConnectorInfo(ConnectorOrientation orientation, bool isInnerPoint = false, bool isPortless = false)
+ : this(null, orientation, isInnerPoint, isPortless)
+ {
+ }
public FullyCreatedConnectorInfo(DesignerItemViewModelBase dataItem, ConnectorOrientation orientation, bool isInnerPoint = false, bool isPortless = false)
: this(null, dataItem, orientation, isInnerPoint, isPortless)
{
diff --git a/AIStudio.Wpf.DiagramDesigner/ViewModels/DrawingViewModel/Erasable/DrawingDesignerItemViewModelBase.cs b/AIStudio.Wpf.DiagramDesigner/ViewModels/DrawingViewModel/Erasable/DrawingDesignerItemViewModelBase.cs
index 00fe83d..8ed6180 100644
--- a/AIStudio.Wpf.DiagramDesigner/ViewModels/DrawingViewModel/Erasable/DrawingDesignerItemViewModelBase.cs
+++ b/AIStudio.Wpf.DiagramDesigner/ViewModels/DrawingViewModel/Erasable/DrawingDesignerItemViewModelBase.cs
@@ -249,8 +249,8 @@ namespace AIStudio.Wpf.DiagramDesigner
}
else
{
- ItemWidth = Geometry.Bounds.Width;// + ColorViewModel.LineWidth * 0.5;
- ItemHeight = Geometry.Bounds.Height;// + ColorViewModel.LineWidth * 0.5;
+ ItemWidth = Geometry.Bounds.Width + ColorViewModel.LineWidth * 1 - 1;
+ ItemHeight = Geometry.Bounds.Height + ColorViewModel.LineWidth * 1 - 1;
Left = point.X;
Top = point.Y;
}
@@ -270,8 +270,8 @@ namespace AIStudio.Wpf.DiagramDesigner
ScaleTransform scaleTransform = transformGroup.Children.OfType().FirstOrDefault();
transformGroup.Children.Remove(scaleTransform); ;
- double radiox = ItemWidth / Geometry.Bounds.Width;
- double radioy = ItemHeight / Geometry.Bounds.Height;
+ double radiox = (ItemWidth - ColorViewModel.LineWidth * 1 + 1) / Geometry.Bounds.Width;
+ double radioy = (ItemHeight - ColorViewModel.LineWidth * 1 + 1) / Geometry.Bounds.Height;
transformGroup.Children.Add(new ScaleTransform(radiox, radioy));
}
diff --git a/Extensions/AIStudio.Wpf.Logical/ViewModels/LogicalGateItemViewModel.cs b/Extensions/AIStudio.Wpf.Logical/ViewModels/LogicalGateItemViewModel.cs
index a00001a..cb72031 100644
--- a/Extensions/AIStudio.Wpf.Logical/ViewModels/LogicalGateItemViewModel.cs
+++ b/Extensions/AIStudio.Wpf.Logical/ViewModels/LogicalGateItemViewModel.cs
@@ -2530,7 +2530,8 @@ namespace AIStudio.Wpf.Logical.ViewModels
{
var first = Input.Values.FirstOrDefault();
Value = first.ConnectorValue;
- LinkPoint.Value = first.ConnectorValue;
+ if (LinkPoint !=null)
+ LinkPoint.Value = first.ConnectorValue;
foreach (var output in Output)
{
output.Value.ConnectorValue = first.ConnectorValue;