mirror of
https://gitee.com/akwkevin/aistudio.-wpf.-diagram
synced 2026-03-03 00:00:57 +08:00
638 lines
24 KiB
C#
638 lines
24 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Windows;
|
|
using System.Windows.Controls;
|
|
using System.Windows.Documents;
|
|
using System.Windows.Input;
|
|
using System.Windows.Markup;
|
|
using System.Windows.Media;
|
|
using System.Xml;
|
|
using System.Linq;
|
|
using System.Windows.Shapes;
|
|
using System.Windows.Resources;
|
|
using System.Runtime.InteropServices;
|
|
using Newtonsoft.Json;
|
|
using AIStudio.Wpf.DiagramDesigner.Models;
|
|
|
|
namespace AIStudio.Wpf.DiagramDesigner
|
|
{
|
|
public class DesignerCanvas : Canvas
|
|
{
|
|
private IDiagramViewModel _viewModel
|
|
{
|
|
get
|
|
{
|
|
return DataContext as IDiagramViewModel;
|
|
}
|
|
}
|
|
private IDiagramServiceProvider _service
|
|
{
|
|
get
|
|
{
|
|
return DiagramServicesProvider.Instance.Provider;
|
|
}
|
|
}
|
|
|
|
private ConnectionViewModel partialConnection;
|
|
private List<Connector> connectorsHit = new List<Connector>();
|
|
|
|
private Point? rubberbandSelectionStartPoint = null;
|
|
|
|
private DrawMode DrawMode
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
private bool EnableSnapping
|
|
{
|
|
get
|
|
{
|
|
if (_viewModel.DrawModeViewModel != null)
|
|
{
|
|
return _viewModel.DrawModeViewModel.EnableSnapping;
|
|
}
|
|
else
|
|
{
|
|
return _service.DrawModeViewModel.EnableSnapping;
|
|
}
|
|
}
|
|
}
|
|
|
|
private double SnappingRadius
|
|
{
|
|
get
|
|
{
|
|
if (_viewModel.DrawModeViewModel != null)
|
|
{
|
|
return _viewModel.DrawModeViewModel.SnappingRadius;
|
|
}
|
|
else
|
|
{
|
|
return _service.DrawModeViewModel.SnappingRadius;
|
|
}
|
|
}
|
|
}
|
|
|
|
#region GridCellSize
|
|
|
|
public static readonly DependencyProperty GridCellSizeProperty =
|
|
DependencyProperty.Register(nameof(GridCellSize),
|
|
typeof(Size),
|
|
typeof(DesignerCanvas),
|
|
new FrameworkPropertyMetadata(new Size(50, 50), FrameworkPropertyMetadataOptions.AffectsRender));
|
|
|
|
public Size GridCellSize
|
|
{
|
|
get
|
|
{
|
|
return (Size)GetValue(GridCellSizeProperty);
|
|
}
|
|
set
|
|
{
|
|
SetValue(GridCellSizeProperty, value);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ShowGrid
|
|
|
|
public static readonly DependencyProperty ShowGridProperty =
|
|
DependencyProperty.Register(nameof(ShowGrid),
|
|
typeof(bool),
|
|
typeof(DesignerCanvas),
|
|
new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsRender));
|
|
|
|
public bool ShowGrid
|
|
{
|
|
get
|
|
{
|
|
return (bool)GetValue(ShowGridProperty);
|
|
}
|
|
set
|
|
{
|
|
SetValue(ShowGridProperty, value);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GridColor
|
|
|
|
public static readonly DependencyProperty GridColorProperty =
|
|
DependencyProperty.Register(nameof(GridColor),
|
|
typeof(Color),
|
|
typeof(DesignerCanvas),
|
|
new FrameworkPropertyMetadata(Colors.LightGray, FrameworkPropertyMetadataOptions.AffectsRender));
|
|
|
|
public Color GridColor
|
|
{
|
|
get
|
|
{
|
|
return (Color)GetValue(GridColorProperty);
|
|
}
|
|
set
|
|
{
|
|
SetValue(GridColorProperty, value);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GridMarginSize 单位mm
|
|
|
|
public static readonly DependencyProperty GridMarginSizeProperty =
|
|
DependencyProperty.Register(nameof(GridMarginSize),
|
|
typeof(Size),
|
|
typeof(DesignerCanvas),
|
|
new FrameworkPropertyMetadata(new Size(28, 28), FrameworkPropertyMetadataOptions.AffectsRender));
|
|
|
|
public Size GridMarginSize
|
|
{
|
|
get
|
|
{
|
|
return (Size)GetValue(GridMarginSizeProperty);
|
|
}
|
|
set
|
|
{
|
|
SetValue(GridMarginSizeProperty, value);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
public DesignerCanvas()
|
|
{
|
|
this.AllowDrop = true;
|
|
Mediator.Instance.Register(this);
|
|
|
|
_service.PropertyChanged += _service_PropertyChanged;
|
|
}
|
|
|
|
protected override void OnRender(DrawingContext dc)
|
|
{
|
|
var rect = new Rect(0, 0, RenderSize.Width, RenderSize.Height);
|
|
dc.DrawRectangle(Background, null, rect);
|
|
if (ShowGrid && GridCellSize.Width > 0 && GridCellSize.Height > 0)
|
|
DrawGrid(dc, rect);
|
|
}
|
|
|
|
protected virtual void DrawGrid(DrawingContext dc, Rect rect)
|
|
{
|
|
//using .5 forces wpf to draw a single pixel line
|
|
for (var i = GridMarginSize.Height + 0.5; i < rect.Height - GridMarginSize.Height; i += GridCellSize.Height)
|
|
dc.DrawLine(new Pen(new SolidColorBrush(GridColor), 1), new Point(GridMarginSize.Width, i), new Point(rect.Width - GridMarginSize.Width, i));
|
|
dc.DrawLine(new Pen(new SolidColorBrush(GridColor), 1), new Point(GridMarginSize.Width, rect.Height - GridMarginSize.Height), new Point(rect.Width - GridMarginSize.Width, rect.Height - GridMarginSize.Height));
|
|
|
|
for (var i = GridMarginSize.Width + 0.5; i < rect.Width - GridMarginSize.Width; i += GridCellSize.Width)
|
|
dc.DrawLine(new Pen(new SolidColorBrush(GridColor), 1), new Point(i, GridMarginSize.Height), new Point(i, rect.Height - GridMarginSize.Height));
|
|
dc.DrawLine(new Pen(new SolidColorBrush(GridColor), 1), new Point(rect.Width - GridMarginSize.Width, GridMarginSize.Height), new Point(rect.Width - GridMarginSize.Width, rect.Height - GridMarginSize.Height));
|
|
}
|
|
|
|
private void _service_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
|
|
{
|
|
if (sender is IDrawModeViewModel)
|
|
{
|
|
if (e.PropertyName == nameof(CursorMode))
|
|
{
|
|
if (_service.DrawModeViewModel.CursorMode == CursorMode.Format)
|
|
{
|
|
EnterFormat();
|
|
}
|
|
else if (_service.DrawModeViewModel.CursorMode == CursorMode.Move)
|
|
{
|
|
EnterMove();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#region Format/Move
|
|
private void EnterFormat()
|
|
{
|
|
StreamResourceInfo sri = Application.GetResourceStream(new Uri("pack://application:,,,/AIStudio.Wpf.DiagramDesigner;component/Images/FormatPainter.cur", UriKind.RelativeOrAbsolute));
|
|
this.Cursor = new Cursor(sri.Stream);
|
|
foreach (SelectableDesignerItemViewModelBase item in _viewModel.Items)
|
|
{
|
|
item.IsHitTestVisible = false;
|
|
}
|
|
}
|
|
|
|
private void EnterMove()
|
|
{
|
|
this.Cursor = Cursors.SizeAll;
|
|
foreach (SelectableDesignerItemViewModelBase item in _viewModel.Items)
|
|
{
|
|
item.IsHitTestVisible = false;
|
|
}
|
|
}
|
|
|
|
private void ExitCursor()
|
|
{
|
|
this.Cursor = Cursors.Arrow;
|
|
foreach (SelectableDesignerItemViewModelBase item in _viewModel.Items)
|
|
{
|
|
item.IsHitTestVisible = true;
|
|
}
|
|
_service.DrawModeViewModel.CursorMode = CursorMode.Normal;
|
|
}
|
|
#endregion
|
|
|
|
private void Format(SelectableDesignerItemViewModelBase source, SelectableDesignerItemViewModelBase target)
|
|
{
|
|
CopyHelper.CopyPropertyValue(source.ColorViewModel, target.ColorViewModel);
|
|
CopyHelper.CopyPropertyValue(source.FontViewModel, target.FontViewModel);
|
|
}
|
|
|
|
private Connector sourceConnector;
|
|
public Connector SourceConnector
|
|
{
|
|
get
|
|
{
|
|
return sourceConnector;
|
|
}
|
|
set
|
|
{
|
|
if (sourceConnector != value)
|
|
{
|
|
sourceConnector = value;
|
|
connectorsHit.Add(sourceConnector);
|
|
|
|
FullyCreatedConnectorInfo sourceDataItem = sourceConnector.Info;
|
|
|
|
|
|
Rect rectangleBounds = sourceConnector.TransformToVisual(this).TransformBounds(new Rect(sourceConnector.RenderSize));
|
|
Point point = new Point(rectangleBounds.Left + (rectangleBounds.Width / 2),
|
|
rectangleBounds.Bottom + (rectangleBounds.Height / 2));
|
|
partialConnection = new ConnectionViewModel(_viewModel, sourceDataItem, new PartCreatedConnectorInfo(point.X, point.Y), DrawMode, RouterMode);
|
|
|
|
_viewModel.DirectAddItemCommand.Execute(partialConnection);
|
|
}
|
|
}
|
|
}
|
|
|
|
private FullyCreatedConnectorInfo sourceConnectorInfo;
|
|
public FullyCreatedConnectorInfo SourceConnectorInfo
|
|
{
|
|
get
|
|
{
|
|
return sourceConnectorInfo;
|
|
}
|
|
set
|
|
{
|
|
if (sourceConnectorInfo != value)
|
|
{
|
|
sourceConnectorInfo = value;
|
|
sourceConnector = new Connector() { Name = "占位" };//占位使用
|
|
connectorsHit.Add(sourceConnector);
|
|
|
|
Rect rectangleBounds = new Rect(sourceConnectorInfo.DataItem.Left, sourceConnectorInfo.DataItem.Top, 3, 3);
|
|
Point point = new Point(rectangleBounds.Left + (rectangleBounds.Width / 2),
|
|
rectangleBounds.Bottom + (rectangleBounds.Height / 2));
|
|
partialConnection = new ConnectionViewModel(_viewModel, sourceConnectorInfo, new PartCreatedConnectorInfo(point.X, point.Y), DrawMode, RouterMode);
|
|
_viewModel.DirectAddItemCommand.Execute(partialConnection);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected override void OnMouseDown(MouseButtonEventArgs e)
|
|
{
|
|
base.OnMouseDown(e);
|
|
if (_viewModel.IsReadOnly) return;
|
|
|
|
if (_service.DrawModeViewModel.CursorMode == CursorMode.Format)
|
|
{
|
|
var element = (e.OriginalSource as FrameworkElement);
|
|
if (element.DataContext is SelectableDesignerItemViewModelBase target)
|
|
{
|
|
Format(_viewModel.SelectedItems.FirstOrDefault(), target);
|
|
return;
|
|
}
|
|
|
|
ExitCursor();
|
|
}
|
|
else if (_service.DrawModeViewModel.CursorMode == CursorMode.Move)
|
|
{
|
|
ExitCursor();
|
|
return;
|
|
}
|
|
|
|
if (e.LeftButton == MouseButtonState.Pressed)
|
|
{
|
|
//if we are source of event, we are rubberband selecting
|
|
if (e.Source == this)
|
|
{
|
|
// in case that this click is the start for a
|
|
// drag operation we cache the start point
|
|
rubberbandSelectionStartPoint = e.GetPosition(this);
|
|
|
|
if (!(Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)))
|
|
{
|
|
_viewModel.ClearSelectedItemsCommand.Execute(null);
|
|
|
|
}
|
|
e.Handled = true;
|
|
|
|
if (_service.DrawModeViewModel.GetDrawMode() == DrawMode.ConnectingLineSmooth)
|
|
{
|
|
if (connectorsHit.Count == 0)
|
|
{
|
|
LinkPointDesignerItemViewModel pointItemView = new LinkPointDesignerItemViewModel(rubberbandSelectionStartPoint.Value);
|
|
_viewModel.DirectAddItemCommand.Execute(pointItemView);
|
|
SourceConnectorInfo = pointItemView.Connectors.FirstOrDefault();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
protected override void OnMouseMove(MouseEventArgs e)
|
|
{
|
|
base.OnMouseMove(e);
|
|
|
|
if (_viewModel.IsReadOnly) return;
|
|
|
|
Point currentPoint = e.GetPosition(this);
|
|
_viewModel.CurrentPoint = currentPoint;
|
|
var point = CursorPointManager.GetCursorPosition();
|
|
_viewModel.CurrentColor = ColorPickerManager.GetColor(point.X, point.Y);
|
|
|
|
if (_service.DrawModeViewModel.CursorMode == CursorMode.Move)
|
|
{
|
|
_viewModel.SelectedItems.OfType<DesignerItemViewModelBase>().ToList().ForEach(p => {
|
|
p.Left = currentPoint.X;
|
|
p.Top = currentPoint.Y;
|
|
});
|
|
return;
|
|
}
|
|
|
|
if (SourceConnector != null)
|
|
{
|
|
if (e.LeftButton == MouseButtonState.Pressed)
|
|
{
|
|
partialConnection.SinkConnectorInfo = new PartCreatedConnectorInfo(currentPoint.X, currentPoint.Y);
|
|
HitTesting(currentPoint);
|
|
|
|
if (EnableSnapping)
|
|
{
|
|
var nearPort = FindNearPortToAttachTo();
|
|
if (nearPort != null || partialConnection.SinkConnectorInfoFully != null)
|
|
{
|
|
//var oldPort = _ongoingLink.TargetPort;
|
|
//_ongoingLink.SetTargetPort(nearPort);
|
|
//oldPort?.Refresh();
|
|
//nearPort?.Refresh();
|
|
partialConnection.SinkConnectorInfo = nearPort;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// if mouse button is not pressed we have no drag operation, ...
|
|
if (e.LeftButton != MouseButtonState.Pressed && _service.DrawModeViewModel.GetDrawMode() != DrawMode.DirectLine)
|
|
rubberbandSelectionStartPoint = null;
|
|
|
|
// ... but if mouse button is pressed and start
|
|
// point value is set we do have one
|
|
if (this.rubberbandSelectionStartPoint.HasValue)
|
|
{
|
|
// create rubberband adorner
|
|
AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this);
|
|
if (adornerLayer != null)
|
|
{
|
|
RubberbandAdorner adorner = new RubberbandAdorner(this, rubberbandSelectionStartPoint);
|
|
if (adorner != null)
|
|
{
|
|
adornerLayer.Add(adorner);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
e.Handled = true;
|
|
}
|
|
|
|
protected override void OnMouseUp(MouseButtonEventArgs e)
|
|
{
|
|
base.OnMouseUp(e);
|
|
|
|
if (_viewModel.IsReadOnly) return;
|
|
|
|
if (_service.DrawModeViewModel.GetDrawMode() == DrawMode.DirectLine)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Mediator.Instance.NotifyColleagues<bool>("DoneDrawingMessage", true);
|
|
|
|
if (sourceConnector != null)
|
|
{
|
|
FullyCreatedConnectorInfo sourceDataItem = sourceConnectorInfo ?? (sourceConnector.Info);
|
|
if (connectorsHit.Count() == 2)
|
|
{
|
|
Connector sinkConnector = connectorsHit.Last();
|
|
FullyCreatedConnectorInfo sinkDataItem = sinkConnector.Info;
|
|
|
|
int indexOfLastTempConnection = sinkDataItem.DataItem.Root.Items.Count - 1;
|
|
sinkDataItem.DataItem.Root.DirectRemoveItemCommand.Execute(
|
|
sinkDataItem.DataItem.Root.Items[indexOfLastTempConnection]);
|
|
sinkDataItem.DataItem.Root.AddItemCommand.Execute(new ConnectionViewModel(_viewModel, sourceDataItem, sinkDataItem, DrawMode, RouterMode));
|
|
}
|
|
else if (partialConnection.IsFullConnection)
|
|
{
|
|
partialConnection.RaiseFullConnection();
|
|
}
|
|
else if (_service.DrawModeViewModel.GetDrawMode() == DrawMode.DirectLine && connectorsHit.Count() == 1)
|
|
{
|
|
LinkPointDesignerItemViewModel pointItemView = new LinkPointDesignerItemViewModel(e.GetPosition(this));
|
|
FullyCreatedConnectorInfo sinkDataItem = pointItemView.TopConnector;
|
|
|
|
int indexOfLastTempConnection = _viewModel.Items.Count - 1;
|
|
_viewModel.DirectRemoveItemCommand.Execute(_viewModel.Items[indexOfLastTempConnection]);
|
|
_viewModel.DirectAddItemCommand.Execute(pointItemView);
|
|
|
|
var connector = new ConnectionViewModel(_viewModel, sourceDataItem, sinkDataItem, DrawMode, RouterMode);
|
|
_viewModel.AddItemCommand.Execute(connector);
|
|
|
|
sourceDataItem.DataItem.ZIndex++;
|
|
connector.ZIndex--;
|
|
}
|
|
else
|
|
{
|
|
//Need to remove last item as we did not finish drawing the path
|
|
int indexOfLastTempConnection = sourceDataItem.DataItem.Root.Items.Count - 1;
|
|
sourceDataItem.DataItem.Root.DirectRemoveItemCommand.Execute(
|
|
sourceDataItem.DataItem.Root.Items[indexOfLastTempConnection]);
|
|
|
|
|
|
}
|
|
}
|
|
|
|
connectorsHit = new List<Connector>();
|
|
sourceConnector = null;
|
|
sourceConnectorInfo = null;
|
|
|
|
_service.DrawModeViewModel.ResetDrawMode();
|
|
}
|
|
|
|
protected override void OnPreviewKeyDown(KeyEventArgs e)
|
|
{
|
|
base.OnPreviewKeyDown(e);
|
|
|
|
//FFE6E6FA
|
|
}
|
|
|
|
protected override Size MeasureOverride(Size constraint)
|
|
{
|
|
Size size = new Size();
|
|
foreach (UIElement element in this.InternalChildren)
|
|
{
|
|
double left = Canvas.GetLeft(element);
|
|
double top = Canvas.GetTop(element);
|
|
left = double.IsNaN(left) ? 0 : left;
|
|
top = double.IsNaN(top) ? 0 : top;
|
|
|
|
//measure desired size for each child
|
|
element.Measure(constraint);
|
|
|
|
Size desiredSize = element.DesiredSize;
|
|
if (!double.IsNaN(desiredSize.Width) && !double.IsNaN(desiredSize.Height))
|
|
{
|
|
size.Width = Math.Max(size.Width, left + desiredSize.Width);
|
|
size.Height = Math.Max(size.Height, top + desiredSize.Height);
|
|
}
|
|
}
|
|
// add margin
|
|
size.Width += 10;
|
|
size.Height += 10;
|
|
|
|
return size;
|
|
}
|
|
|
|
private void HitTesting(Point hitPoint)
|
|
{
|
|
DependencyObject hitObject = this.InputHitTest(hitPoint) as DependencyObject;
|
|
while (hitObject != null &&
|
|
hitObject.GetType() != typeof(DesignerCanvas))
|
|
{
|
|
if (hitObject is Connector connector && connector.Info != null)
|
|
{
|
|
if (SourceConnector == null || connector.Info.CanAttachTo(SourceConnector.Info))
|
|
{
|
|
if (connectorsHit.Any(p => p.Name == "占位"))
|
|
{
|
|
connectorsHit.Remove(connectorsHit.FirstOrDefault(p => p.Name == "占位"));
|
|
}
|
|
if (!connectorsHit.Contains(hitObject as Connector))
|
|
connectorsHit.Add(hitObject as Connector);
|
|
}
|
|
}
|
|
hitObject = VisualTreeHelper.GetParent(hitObject);
|
|
}
|
|
|
|
}
|
|
|
|
protected override void OnDrop(DragEventArgs e)
|
|
{
|
|
base.OnDrop(e);
|
|
|
|
if (_viewModel.IsReadOnly) return;
|
|
|
|
DragObject dragObject = e.Data.GetData(typeof(DragObject)) as DragObject;
|
|
if (dragObject != null)
|
|
{
|
|
_viewModel.ClearSelectedItemsCommand.Execute(null);
|
|
Point position = e.GetPosition(this);
|
|
if (dragObject.DesignerItem is SerializableObject serializableObject)
|
|
{
|
|
var designerItems = serializableObject.ToObject();
|
|
foreach (var item in designerItems.OfType<DesignerItemViewModelBase>())
|
|
{
|
|
item.Left += position.X;
|
|
item.Top += position.Y;
|
|
}
|
|
_viewModel.AddItemCommand.Execute(designerItems);
|
|
}
|
|
else
|
|
{
|
|
DesignerItemViewModelBase itemBase = null;
|
|
if (dragObject.DesignerItem is DesignerItemBase)
|
|
{
|
|
itemBase = Activator.CreateInstance(dragObject.ContentType, _viewModel, dragObject.DesignerItem) as DesignerItemViewModelBase;
|
|
}
|
|
else
|
|
{
|
|
itemBase = Activator.CreateInstance(dragObject.ContentType) as DesignerItemViewModelBase;
|
|
itemBase.Icon = dragObject.Icon;
|
|
itemBase.ColorViewModel = CopyHelper.Mapper(dragObject.ColorViewModel);
|
|
if (dragObject.DesiredSize != null)
|
|
{
|
|
itemBase.ItemWidth = dragObject.DesiredSize.Value.Width;
|
|
itemBase.ItemHeight = dragObject.DesiredSize.Value.Height;
|
|
}
|
|
}
|
|
itemBase.Left = Math.Max(0, position.X - itemBase.ItemWidth / 2);
|
|
itemBase.Top = Math.Max(0, position.Y - itemBase.ItemHeight / 2);
|
|
_viewModel.AddItemCommand.Execute(itemBase);
|
|
}
|
|
}
|
|
var dragFile = e.Data.GetData(DataFormats.FileDrop);
|
|
if (dragFile != null && dragFile is string[] files)
|
|
{
|
|
foreach (var file in files)
|
|
{
|
|
_viewModel.ClearSelectedItemsCommand.Execute(null);
|
|
Point position = e.GetPosition(this);
|
|
ImageItemViewModel itemBase = new ImageItemViewModel();
|
|
itemBase.Icon = file;
|
|
itemBase.Suffix = System.IO.Path.GetExtension(itemBase.Icon).ToLower();
|
|
itemBase.InitWidthAndHeight();
|
|
itemBase.AutoSize();
|
|
|
|
itemBase.Left = Math.Max(0, position.X - itemBase.ItemWidth / 2);
|
|
itemBase.Top = Math.Max(0, position.Y - itemBase.ItemHeight / 2);
|
|
_viewModel.AddItemCommand.Execute(itemBase);
|
|
}
|
|
}
|
|
e.Handled = true;
|
|
}
|
|
|
|
public FullyCreatedConnectorInfo FindNearPortToAttachTo()
|
|
{
|
|
foreach (var port in _viewModel.Items.OfType<DesignerItemViewModelBase>().ToList().SelectMany(n => n.Connectors))
|
|
{
|
|
if (partialConnection.OnGoingPosition.DistanceTo(port.Position) < SnappingRadius &&
|
|
partialConnection.SourceConnectorInfo.CanAttachTo(port))
|
|
return port;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|
|
} |