mirror of
https://gitee.com/akwkevin/aistudio.-wpf.-diagram
synced 2026-04-06 09:16:37 +08:00
整理一下项目文件
This commit is contained in:
516
AIStudio.Wpf.DiagramDesigner/Controls/DesignerCanvas.cs
Normal file
516
AIStudio.Wpf.DiagramDesigner/Controls/DesignerCanvas.cs
Normal file
@@ -0,0 +1,516 @@
|
||||
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;
|
||||
|
||||
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 ConnectorViewModel partialConnection;
|
||||
private List<Connector> connectorsHit = new List<Connector>();
|
||||
|
||||
private Point? rubberbandSelectionStartPoint = null;
|
||||
|
||||
#region GridCellSize
|
||||
|
||||
public static readonly DependencyProperty GridCellSizeProperty =
|
||||
DependencyProperty.Register("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("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("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 GridMargin 单位mm
|
||||
|
||||
public static readonly DependencyProperty GridMarginProperty =
|
||||
DependencyProperty.Register("GridMargin",
|
||||
typeof(double),
|
||||
typeof(DesignerCanvas),
|
||||
new FrameworkPropertyMetadata(28d, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public double GridMargin
|
||||
{
|
||||
get { return (double)GetValue(GridMarginProperty); }
|
||||
set { SetValue(GridMarginProperty, 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 = GridMargin + 0.5; i < rect.Height - GridMargin; i += GridCellSize.Height)
|
||||
dc.DrawLine(new Pen(new SolidColorBrush(GridColor), 1), new Point(GridMargin, i), new Point(rect.Width - GridMargin, i));
|
||||
dc.DrawLine(new Pen(new SolidColorBrush(GridColor), 1), new Point(GridMargin, rect.Height - GridMargin), new Point(rect.Width - GridMargin, rect.Height - GridMargin));
|
||||
|
||||
for (var i = GridMargin + 0.5; i < rect.Width - GridMargin; i += GridCellSize.Width)
|
||||
dc.DrawLine(new Pen(new SolidColorBrush(GridColor), 1), new Point(i, GridMargin), new Point(i, rect.Height - GridMargin));
|
||||
dc.DrawLine(new Pen(new SolidColorBrush(GridColor), 1), new Point(rect.Width - GridMargin, GridMargin), new Point(rect.Width - GridMargin, rect.Height - GridMargin));
|
||||
}
|
||||
|
||||
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.DataContext as FullyCreatedConnectorInfo;
|
||||
|
||||
|
||||
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 ConnectorViewModel(sourceDataItem, new PartCreatedConnectionInfo(point), _service.DrawModeViewModel.VectorLineDrawMode);
|
||||
_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 ConnectorViewModel(sourceConnectorInfo, new PartCreatedConnectionInfo(point), _service.DrawModeViewModel.VectorLineDrawMode);
|
||||
_viewModel.DirectAddItemCommand.Execute(partialConnection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnMouseDown(MouseButtonEventArgs e)
|
||||
{
|
||||
base.OnMouseDown(e);
|
||||
|
||||
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);
|
||||
|
||||
IDiagramViewModel vm = (this.DataContext as IDiagramViewModel);
|
||||
if (!(Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)))
|
||||
{
|
||||
vm.ClearSelectedItemsCommand.Execute(null);
|
||||
|
||||
}
|
||||
e.Handled = true;
|
||||
|
||||
if (_service.DrawModeViewModel.GetDrawMode() == DrawMode.ConnectingLine)
|
||||
{
|
||||
if (connectorsHit.Count == 0)
|
||||
{
|
||||
LinkPointDesignerItemViewModel pointItemView = new LinkPointDesignerItemViewModel(rubberbandSelectionStartPoint.Value);
|
||||
_viewModel.DirectAddItemCommand.Execute(pointItemView);
|
||||
SourceConnectorInfo = pointItemView.TopConnector;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected override void OnMouseMove(MouseEventArgs e)
|
||||
{
|
||||
base.OnMouseMove(e);
|
||||
|
||||
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 PartCreatedConnectionInfo(currentPoint);
|
||||
HitTesting(currentPoint);
|
||||
}
|
||||
}
|
||||
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 (_service.DrawModeViewModel.GetDrawMode() == DrawMode.DirectLine)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Mediator.Instance.NotifyColleagues<bool>("DoneDrawingMessage", true);
|
||||
|
||||
if (sourceConnector != null)
|
||||
{
|
||||
FullyCreatedConnectorInfo sourceDataItem = sourceConnectorInfo ?? (sourceConnector.DataContext as FullyCreatedConnectorInfo);
|
||||
if (connectorsHit.Count() == 2)
|
||||
{
|
||||
Connector sinkConnector = connectorsHit.Last();
|
||||
FullyCreatedConnectorInfo sinkDataItem = sinkConnector.DataContext as FullyCreatedConnectorInfo;
|
||||
|
||||
int indexOfLastTempConnection = sinkDataItem.DataItem.Parent.Items.Count - 1;
|
||||
sinkDataItem.DataItem.Parent.DirectRemoveItemCommand.Execute(
|
||||
sinkDataItem.DataItem.Parent.Items[indexOfLastTempConnection]);
|
||||
sinkDataItem.DataItem.Parent.AddItemCommand.Execute(new ConnectorViewModel(sourceDataItem, sinkDataItem, _service.DrawModeViewModel.VectorLineDrawMode));
|
||||
}
|
||||
else if (_service.DrawModeViewModel.GetDrawMode() == DrawMode.ConnectingLine && 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 ConnectorViewModel(sourceDataItem, sinkDataItem, _service.DrawModeViewModel.VectorLineDrawMode);
|
||||
_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.Parent.Items.Count - 1;
|
||||
sourceDataItem.DataItem.Parent.DirectRemoveItemCommand.Execute(
|
||||
sourceDataItem.DataItem.Parent.Items[indexOfLastTempConnection]);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
connectorsHit = new List<Connector>();
|
||||
sourceConnector = null;
|
||||
sourceConnectorInfo = null;
|
||||
|
||||
_service.DrawModeViewModel.ResetDrawMode();
|
||||
}
|
||||
|
||||
protected override void OnPreviewKeyDown(KeyEventArgs e)
|
||||
{
|
||||
base.OnPreviewKeyDown(e);
|
||||
|
||||
if (e.Key == Key.Left)
|
||||
{
|
||||
if (_viewModel.SelectedItems != null)
|
||||
{
|
||||
foreach(var item in _viewModel.SelectedItems.OfType<DesignerItemViewModelBase>())
|
||||
{
|
||||
item.Left -= 0.1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (e.Key == Key.Right)
|
||||
{
|
||||
if (_viewModel.SelectedItems != null)
|
||||
{
|
||||
foreach (var item in _viewModel.SelectedItems.OfType<DesignerItemViewModelBase>())
|
||||
{
|
||||
item.Left += 0.1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (e.Key == Key.Up)
|
||||
{
|
||||
if (_viewModel.SelectedItems != null)
|
||||
{
|
||||
foreach (var item in _viewModel.SelectedItems.OfType<DesignerItemViewModelBase>())
|
||||
{
|
||||
item.Top -= 0.1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (e.Key == Key.Down)
|
||||
{
|
||||
if (_viewModel.SelectedItems != null)
|
||||
{
|
||||
foreach (var item in _viewModel.SelectedItems.OfType<DesignerItemViewModelBase>())
|
||||
{
|
||||
item.Top += 0.1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
DragObject dragObject = e.Data.GetData(typeof(DragObject)) as DragObject;
|
||||
if (dragObject != null)
|
||||
{
|
||||
(DataContext as IDiagramViewModel).ClearSelectedItemsCommand.Execute(null);
|
||||
Point position = e.GetPosition(this);
|
||||
DesignerItemViewModelBase itemBase = null;
|
||||
if (dragObject.DesignerItem != null)
|
||||
{
|
||||
itemBase = (DesignerItemViewModelBase)Activator.CreateInstance(dragObject.ContentType, null, dragObject.DesignerItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
itemBase = (DesignerItemViewModelBase)Activator.CreateInstance(dragObject.ContentType);
|
||||
itemBase.Icon = dragObject.Icon;
|
||||
itemBase.ColorViewModel = CopyHelper.Mapper(dragObject.ColorViewModel);
|
||||
}
|
||||
itemBase.Left = Math.Max(0, position.X - itemBase.ItemWidth / 2);
|
||||
itemBase.Top = Math.Max(0, position.Y - itemBase.ItemHeight / 2);
|
||||
(DataContext as IDiagramViewModel).AddItemCommand.Execute(itemBase);
|
||||
}
|
||||
var dragFile = e.Data.GetData(DataFormats.FileDrop);
|
||||
if (dragFile != null && dragFile is string[] files)
|
||||
{
|
||||
foreach (var file in files)
|
||||
{
|
||||
(DataContext as IDiagramViewModel).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);
|
||||
(DataContext as IDiagramViewModel).AddItemCommand.Execute(itemBase);
|
||||
}
|
||||
}
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user