using System; using System.Collections.Generic; using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Media3D; using System.Windows.Resources; using AIStudio.Wpf.DiagramDesigner.Helpers; using AIStudio.Wpf.DiagramDesigner.Models; using AIStudio.Wpf.DiagramDesigner.ViewModels; using AIStudio.Wpf.DiagramDesigner.ViewModels.BaseViewModel; namespace AIStudio.Wpf.DiagramDesigner { public class DesignerCanvas : Canvas { #region 属性 private IDiagramViewModel _viewModel { get { return DataContext as IDiagramViewModel; } } private IDiagramServiceProvider _service { get { return DiagramServicesProvider.Instance.Provider; } } private ConnectionViewModel _partialConnection; private Point? rubberbandSelectionStartPoint = null; private Connector _sourceConnector; public Connector SourceConnector { get { return _sourceConnector; } set { if (_sourceConnector != value) { _sourceConnector = value; if (_sourceConnector != null) { ConnectorInfoBase 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)); Point point = sourceDataItem.MiddlePosition; _partialConnection = new ConnectionViewModel(_viewModel, sourceDataItem, new PartCreatedConnectorInfo(point.X, point.Y), DrawModeViewModel.LineDrawMode, DrawModeViewModel.LineRouterMode); _viewModel.Add(_partialConnection); _partialConnection.ZIndex = -1; } } } } private Connector _sinkConnector; public Connector SinkConnector { get { return _sinkConnector; } set { if (_sinkConnector != null) { _sinkConnector.Info.DisableAttachTo = false; } if (_sinkConnector != value) { _sinkConnector = value; } } } private BlockItemsContainer _sourceItemsContainer; public BlockItemsContainer SourceItemsContainer { get { return _sourceItemsContainer; } set { if (_sourceItemsContainer != value) { _sourceItemsContainer = value; if (_sourceItemsContainer != null) { BlockItemsContainerInfo sourceContainerInfo = _sourceItemsContainer.Info; sourceContainerInfo.DataItem.RemoveChild(_sourceItemsContainer.DragObject, sourceContainerInfo); EnterMove(); } } } } private IDrawModeViewModel DrawModeViewModel { get { if (_viewModel.DrawModeViewModel != null) { return _viewModel.DrawModeViewModel; } else { return _service.DrawModeViewModel; } } } private DrawMode DrawMode { get { if (_viewModel.DrawModeViewModel != null) { return _viewModel.DrawModeViewModel.GetDrawMode(); } else { return _service.DrawModeViewModel.GetDrawMode(); } } } #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 AutoGrowth public static readonly DependencyProperty AutoGrowthProperty = DependencyProperty.Register(nameof(AutoGrowth), typeof(bool), typeof(DesignerCanvas), new FrameworkPropertyMetadata(true)); public bool AutoGrowth { get { return (bool)GetValue(AutoGrowthProperty); } set { SetValue(AutoGrowthProperty, value); } } #endregion #region CornerRadius public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.Register(nameof(CornerRadius), typeof(CornerRadius), typeof(DesignerCanvas), new FrameworkPropertyMetadata(new CornerRadius())); public CornerRadius CornerRadius { get { return (CornerRadius)GetValue(CornerRadiusProperty); } set { SetValue(CornerRadiusProperty, 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 #endregion #region 初始化 public DesignerCanvas() { this.Focusable = true; this.Loaded += DesignerCanvas_Loaded; this.IsVisibleChanged += DesignerCanvas_IsVisibleChanged; this.DataContextChanged += DesignerCanvas_DataContextChanged; } private void DesignerCanvas_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e) { if (e.OldValue is IDiagramViewModel oldvalue) { } if (e.NewValue is IDiagramViewModel newvalue) { if (newvalue.GenerateThumbnail) newvalue.Thumbnail = new VisualBrush(this) { Stretch = Stretch.Uniform }; } } private void DesignerCanvas_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e) { if (IsVisible) { this.Focus(); } } protected void DesignerCanvas_Loaded(object sender, RoutedEventArgs e) { //Mediator.Instance.Register(this); this.Focus(); _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); } public static Geometry GetRoundRectangle(Rect baseRect, Thickness borderThickness, CornerRadius cornerRadius) { // Normalizing the corner radius if (cornerRadius.TopLeft < double.Epsilon) { cornerRadius.TopLeft = 0.0; } if (cornerRadius.TopRight < double.Epsilon) { cornerRadius.TopRight = 0.0; } if (cornerRadius.BottomLeft < double.Epsilon) { cornerRadius.BottomLeft = 0.0; } if (cornerRadius.BottomRight < double.Epsilon) { cornerRadius.BottomRight = 0.0; } // Taking the border thickness into account var leftHalf = borderThickness.Left * 0.5; if (leftHalf < double.Epsilon) { leftHalf = 0.0; } var topHalf = borderThickness.Top * 0.5; if (topHalf < double.Epsilon) { topHalf = 0.0; } var rightHalf = borderThickness.Right * 0.5; if (rightHalf < double.Epsilon) { rightHalf = 0.0; } var bottomHalf = borderThickness.Bottom * 0.5; if (bottomHalf < double.Epsilon) { bottomHalf = 0.0; } // Create the rectangles for the corners that needs to be curved in the base rectangle // TopLeft Rectangle var topLeftRect = new Rect( baseRect.Location.X, baseRect.Location.Y, Math.Max(0.0, cornerRadius.TopLeft - leftHalf), Math.Max(0.0, cornerRadius.TopLeft - rightHalf)); // TopRight Rectangle var topRightRect = new Rect( baseRect.Location.X + baseRect.Width - cornerRadius.TopRight + rightHalf, baseRect.Location.Y, Math.Max(0.0, cornerRadius.TopRight - rightHalf), Math.Max(0.0, cornerRadius.TopRight - topHalf)); // BottomRight Rectangle var bottomRightRect = new Rect( baseRect.Location.X + baseRect.Width - cornerRadius.BottomRight + rightHalf, baseRect.Location.Y + baseRect.Height - cornerRadius.BottomRight + bottomHalf, Math.Max(0.0, cornerRadius.BottomRight - rightHalf), Math.Max(0.0, cornerRadius.BottomRight - bottomHalf)); // BottomLeft Rectangle var bottomLeftRect = new Rect( baseRect.Location.X, baseRect.Location.Y + baseRect.Height - cornerRadius.BottomLeft + bottomHalf, Math.Max(0.0, cornerRadius.BottomLeft - leftHalf), Math.Max(0.0, cornerRadius.BottomLeft - bottomHalf)); // Adjust the _width of the TopLeft and TopRight rectangles so that they are proportional to the _width of the baseRect if (topLeftRect.Right > topRightRect.Left) { var newWidth = (topLeftRect.Width / (topLeftRect.Width + topRightRect.Width)) * baseRect.Width; topLeftRect = new Rect(topLeftRect.Location.X, topLeftRect.Location.Y, newWidth, topLeftRect.Height); topRightRect = new Rect( baseRect.Left + newWidth, topRightRect.Location.Y, Math.Max(0.0, baseRect.Width - newWidth), topRightRect.Height); } // Adjust the height of the TopRight and BottomRight rectangles so that they are proportional to the height of the baseRect if (topRightRect.Bottom > bottomRightRect.Top) { var newHeight = (topRightRect.Height / (topRightRect.Height + bottomRightRect.Height)) * baseRect.Height; topRightRect = new Rect(topRightRect.Location.X, topRightRect.Location.Y, topRightRect.Width, newHeight); bottomRightRect = new Rect( bottomRightRect.Location.X, baseRect.Top + newHeight, bottomRightRect.Width, Math.Max(0.0, baseRect.Height - newHeight)); } // Adjust the _width of the BottomLeft and BottomRight rectangles so that they are proportional to the _width of the baseRect if (bottomRightRect.Left < bottomLeftRect.Right) { var newWidth = (bottomLeftRect.Width / (bottomLeftRect.Width + bottomRightRect.Width)) * baseRect.Width; bottomLeftRect = new Rect(bottomLeftRect.Location.X, bottomLeftRect.Location.Y, newWidth, bottomLeftRect.Height); bottomRightRect = new Rect( baseRect.Left + newWidth, bottomRightRect.Location.Y, Math.Max(0.0, baseRect.Width - newWidth), bottomRightRect.Height); } // Adjust the height of the TopLeft and BottomLeft rectangles so that they are proportional to the height of the baseRect if (bottomLeftRect.Top < topLeftRect.Bottom) { var newHeight = (topLeftRect.Height / (topLeftRect.Height + bottomLeftRect.Height)) * baseRect.Height; topLeftRect = new Rect(topLeftRect.Location.X, topLeftRect.Location.Y, topLeftRect.Width, newHeight); bottomLeftRect = new Rect( bottomLeftRect.Location.X, baseRect.Top + newHeight, bottomLeftRect.Width, Math.Max(0.0, baseRect.Height - newHeight)); } var roundedRectGeometry = new StreamGeometry(); using (var context = roundedRectGeometry.Open()) { // Begin from the Bottom of the TopLeft Arc and proceed clockwise context.BeginFigure(topLeftRect.BottomLeft, true, true); // TopLeft Arc context.ArcTo(topLeftRect.TopRight, topLeftRect.Size, 0, false, SweepDirection.Clockwise, true, true); // Top Line context.LineTo(topRightRect.TopLeft, true, true); // TopRight Arc context.ArcTo(topRightRect.BottomRight, topRightRect.Size, 0, false, SweepDirection.Clockwise, true, true); // Right Line context.LineTo(bottomRightRect.TopRight, true, true); // BottomRight Arc context.ArcTo(bottomRightRect.BottomLeft, bottomRightRect.Size, 0, false, SweepDirection.Clockwise, true, true); // Bottom Line context.LineTo(bottomLeftRect.BottomRight, true, true); // BottomLeft Arc context.ArcTo(bottomLeftRect.TopLeft, bottomLeftRect.Size, 0, false, SweepDirection.Clockwise, true, true); } return roundedRectGeometry; } #endregion 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)); } #region Format/Move private void _service_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { if (sender is IDrawModeViewModel) { if (e.PropertyName == nameof(CursorMode)) { if (DrawModeViewModel.CursorMode == CursorMode.Format) { EnterFormat(); } else if (DrawModeViewModel.CursorMode == CursorMode.Move) { EnterMove(); } else if (DrawModeViewModel.CursorMode == CursorMode.Exit) { ExitCursor(); } } else if (e.PropertyName == nameof(DrawModeViewModel.DrawingDrawMode)) { if (DrawModeViewModel.DrawingDrawMode == DrawMode.ColorPicker) { EnterColorPicker(); } } } } 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 EnterColorPicker() { // create rubberband adorner AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this); if (adornerLayer != null) { DrawingRubberbandAdorner adorner = new DrawingRubberbandAdorner(this, new Point()); if (adorner != null) { adornerLayer.Add(adorner); } } } private void ExitCursor() { this.Cursor = Cursors.Arrow; foreach (SelectableDesignerItemViewModelBase item in _viewModel.Items) { item.IsHitTestVisible = true; } DrawModeViewModel.CursorMode = CursorMode.Normal; } private void Format(SelectableDesignerItemViewModelBase source, SelectableDesignerItemViewModelBase target) { CopyHelper.CopyPropertyValue(source.ColorViewModel, target.ColorViewModel); CopyHelper.CopyPropertyValue(source.FontViewModel, target.FontViewModel); CopyHelper.CopyPropertyValue(source.ShapeViewModel, target.ShapeViewModel); CopyHelper.CopyPropertyValue(source.AnimationViewModel, target.AnimationViewModel); } #endregion protected override void OnMouseDown(MouseButtonEventArgs e) { base.OnMouseDown(e); if (_viewModel.IsReadOnly) return; if (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 (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 Point currentPoint = e.GetPosition(this); rubberbandSelectionStartPoint = currentPoint; if (!(Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))) { _viewModel.ClearSelectedItems(); } if (DrawModeViewModel.SharpDrawModeSelected || (DrawModeViewModel.DrawingDrawModeSelected && DrawModeViewModel.DrawingDrawMode != DrawMode.Select)) { // create rubberband adorner AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this); if (adornerLayer != null) { DrawingRubberbandAdorner adorner = new DrawingRubberbandAdorner(this, currentPoint); if (adorner != null) { adornerLayer.Add(adorner); } } } else if (DrawModeViewModel.LineDrawModeSelected)//画线模式,可以不命中实体 { if (SourceConnector == null) { //新建一个Part连接点 SourceConnector = new Connector() { Content = new PartCreatedConnectorInfo(currentPoint.X, currentPoint.Y), Tag = "虚拟的连接点" }; } } e.Handled = true; } } else { this.Focus(); } } protected override void OnMouseMove(MouseEventArgs e) { //var focusedElement = Keyboard.FocusedElement; //Debug.WriteLine("focusedElement:" + focusedElement?.ToString()); base.OnMouseMove(e); if (_viewModel.IsReadOnly) return; Point currentPoint = e.GetPosition(this); _viewModel.CurrentPoint = new Point(ScreenHelper.WidthToMm(currentPoint.X), ScreenHelper.WidthToMm(currentPoint.Y)); var point = CursorPointManager.GetCursorPosition(); _viewModel.CurrentColor = ColorPickerManager.GetColor(point.X, point.Y); //移动 if (DrawModeViewModel.CursorMode == CursorMode.Move) { _viewModel.SelectedItems.OfType().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); SinkConnector = HitTesting(currentPoint); if (SinkConnector != SourceConnector && SinkConnector?.Info?.CanAttachTo(SourceConnector?.Info) == false) { SinkConnector.Info.DisableAttachTo = true; } if (_viewModel.DiagramOption.SnappingOption.EnableSnapping) { var nearPort = _viewModel.FindNearPortToAttachTo(_partialConnection); if (nearPort != null) { _partialConnection.SinkConnectorInfo = nearPort; } } } } else if (SourceItemsContainer != null) { if (e.LeftButton == MouseButtonState.Pressed) { SourceItemsContainer.DragObject.Left = currentPoint.X - SourceItemsContainer.DragOffset.X; SourceItemsContainer.DragObject.Top = currentPoint.Y - SourceItemsContainer.DragOffset.Y; (_viewModel as IBlockDiagramViewModel).PreviewNearBlock(new System.Collections.Generic.List { SourceItemsContainer.DragObject }); } } else { // if mouse button is not pressed we have no drag operation, ... if (e.LeftButton != MouseButtonState.Pressed) 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; Mediator.Instance.NotifyColleagues("DoneDrawingMessage", true); if (SourceConnector != null) { ConnectorInfoBase sourceDataItem = SourceConnector.Info; if (SinkConnector != null && SinkConnector.Info?.DisableAttachTo == false) { ConnectorInfoBase sinkDataItem = SinkConnector.Info; _viewModel.Delete(_partialConnection); _viewModel.AddCommand.Execute(new ConnectionViewModel(_viewModel, sourceDataItem, sinkDataItem, DrawModeViewModel.LineDrawMode, DrawModeViewModel.LineRouterMode)); } else if (_partialConnection.IsFullConnection)//自动连接模式 { _viewModel.ClearAttachTo(); } 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, DrawModeViewModel.LineDrawMode, DrawModeViewModel.LineRouterMode)); } else { //Need to remove last item as we did not finish drawing the path _viewModel.Delete(_partialConnection); } } else if (SourceItemsContainer != null) { (_viewModel as IBlockDiagramViewModel).FinishNearBlock(new System.Collections.Generic.List { SourceItemsContainer.DragObject }); ExitCursor(); } SourceConnector = null; SinkConnector = null; _partialConnection = null; SourceItemsContainer = null; DrawModeViewModel.ResetDrawMode(); } protected override void OnPreviewKeyDown(KeyEventArgs e) { base.OnPreviewKeyDown(e); if (_viewModel.IsReadOnly) return; e.Handled = _viewModel.ExecuteShortcut(e); } protected override void OnPreviewMouseWheel(MouseWheelEventArgs e) { base.OnPreviewMouseWheel(e); if (Keyboard.IsKeyDown(Key.LeftCtrl) == false && Keyboard.IsKeyDown(Key.RightCtrl) == false) { return; } var newZoomValue = _viewModel.ZoomValue + (e.Delta > 0 ? 0.1 : -0.1); _viewModel.ZoomValue = Math.Max(Math.Min(newZoomValue, _viewModel.MaximumZoomValue), _viewModel.MinimumZoomValue); e.Handled = true; } protected override Size MeasureOverride(Size constraint) { if (AutoGrowth) { 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; } else { return base.MeasureOverride(constraint); } } private Connector HitTesting(Point hitPoint) { DependencyObject hitObject = this.InputHitTest(hitPoint) as DependencyObject; while (hitObject != null && hitObject.GetType() != typeof(DesignerCanvas)) { if (hitObject is Connector connector) { return connector; } hitObject = VisualTreeHelper.GetParent(hitObject); } return null; } protected override void OnDragOver(DragEventArgs e) { DragObject dragObject = e.Data.GetData(typeof(DragObject)) as DragObject; if (dragObject != null && (dragObject.ContentType == typeof(BlockDesignerItemViewModel) || dragObject.ContentType.IsSubclassOf(typeof(BlockDesignerItemViewModel)))) { var position = e.GetPosition(this); BlockDesignerItemViewModel itemBase = Activator.CreateInstance(dragObject.ContentType) as BlockDesignerItemViewModel; itemBase.Text = dragObject.Text; 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; } if (dragObject.DesiredMinSize != null) { itemBase.MinItemWidth = dragObject.DesiredMinSize.Value.Width; itemBase.MinItemHeight = dragObject.DesiredMinSize.Value.Height; } itemBase.Left = Math.Max(0, position.X - itemBase.GetItemWidth() / 2); itemBase.Top = Math.Max(0, position.Y - itemBase.GetItemHeight() / 2); (_viewModel as IBlockDiagramViewModel)?.PreviewNearBlock(new System.Collections.Generic.List { itemBase }); } base.OnDragOver(e); } 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.ClearSelectedItems(); Point position = e.GetPosition(this); if (dragObject.DesignerItem is SerializableObject serializableObject) { var designerItems = serializableObject.ToObject(); var minleft = designerItems.OfType().Min(p => p.Left); var mintop = designerItems.OfType().Min(p => p.Top); var maxright = designerItems.OfType().Max(p => p.Left + p.GetItemWidth()); var maxbottom = designerItems.OfType().Max(p => p.Top + p.GetItemHeight()); var itemswidth = maxright - minleft; var itemsheight = maxbottom - mintop; foreach (var item in designerItems.OfType()) { item.Left += position.X - itemswidth / 2; item.Top += position.Y - itemsheight / 2; } _viewModel.AddCommand.Execute(designerItems); } else if (dragObject.DesignerItem is SerializableItem serializableItem) { Type type = TypeHelper.GetType(serializableItem.ModelTypeName); DesignerItemViewModelBase itemBase = Activator.CreateInstance(type, _viewModel, serializableItem, ".json") as DesignerItemViewModelBase; itemBase.Left = Math.Max(0, position.X - itemBase.GetItemWidth() / 2); itemBase.Top = Math.Max(0, position.Y - itemBase.GetItemHeight() / 2); if (dragObject.DesiredSize != null) { itemBase.ItemWidth = dragObject.DesiredSize.Value.Width; itemBase.ItemHeight = dragObject.DesiredSize.Value.Height; } if (dragObject.DesiredMinSize != null) { 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) { (_viewModel as IBlockDiagramViewModel).FinishNearBlock(new System.Collections.Generic.List { block }); } } 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; if (!string.IsNullOrEmpty(dragObject.Text)) itemBase.Text = dragObject.Text; 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; itemBase.ItemHeight = dragObject.DesiredSize.Value.Height; } if (dragObject.DesiredMinSize != null) { 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); _viewModel.AddCommand.Execute(itemBase); if (itemBase is BlockDesignerItemViewModel block) { (_viewModel as IBlockDiagramViewModel).FinishNearBlock(new System.Collections.Generic.List { block }); } } } else { var dragFile = e.Data.GetData(DataFormats.FileDrop); if (dragFile != null && dragFile is string[] files) { foreach (var file in files) { _viewModel.ClearSelectedItems(); 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.GetItemWidth() / 2); itemBase.Top = Math.Max(0, position.Y - itemBase.GetItemHeight() / 2); _viewModel.AddCommand.Execute(itemBase); } } } e.Handled = true; 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 }); } } } }