Files
aistudio-wpf-diagram/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/DiagramViewModel.cs
2023-01-12 23:02:53 +08:00

1787 lines
62 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Reactive.Linq;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using AIStudio.Wpf.DiagramDesigner.Geometrys;
using AIStudio.Wpf.DiagramDesigner.Helpers;
using AIStudio.Wpf.DiagramDesigner.Models;
using Newtonsoft.Json;
namespace AIStudio.Wpf.DiagramDesigner
{
public class DiagramViewModel : BindableBase, IDiagramViewModel
{
#region
private bool _isReadOnly;
public bool IsReadOnly
{
get
{
return _isReadOnly;
}
set
{
SetProperty(ref _isReadOnly, value);
}
}
public bool IsLoading
{
get; set;
}
public IDrawModeViewModel DrawModeViewModel
{
get; set;
}
public IColorViewModel ColorViewModel
{
get; set;
}
private PageSizeType _pageSizeType = PageSizeType.A4;
public PageSizeType PageSizeType
{
get
{
return _pageSizeType;
}
set
{
SetProperty(ref _pageSizeType, value);
RaisePropertyChanged(nameof(PageSize));
}
}
private Size _pageSize = new Size(1000, 600);
public Size PageSize
{
get
{
if (PageSizeOrientation == PageSizeOrientation.Vertical)
{
return GetPageSize();
}
else
{
return new Size(GetPageSize().Height, GetPageSize().Width);
}
}
set
{
SetProperty(ref _pageSize, value);
}
}
public Size GetPageSize()
{
switch (PageSizeType)
{
case PageSizeType.Letter: return new Size(612, 792);
case PageSizeType.Folio: return new Size(612, 936);
case PageSizeType.Legal: return new Size(612, 1008);
case PageSizeType.Executive: return new Size(522, 756);
case PageSizeType.Statement: return new Size(396, 612);
case PageSizeType.Envelope: return new Size(297, 684);
case PageSizeType.MonarchEnvelope: return new Size(279, 540);
case PageSizeType.Tabloid: return new Size(792, 1224);
case PageSizeType.LetterSmall: return new Size(612, 792);
case PageSizeType.CSheet: return new Size(1224, 1584);
case PageSizeType.DSheet: return new Size(1584, 2448);
case PageSizeType.ESheet: return new Size(2448, 3168);
case PageSizeType.A3: return new Size(842, 1191);
case PageSizeType.A4: return new Size(595, 842);
case PageSizeType.A5: return new Size(420, 595);
case PageSizeType.B4: return new Size(709, 1003);
case PageSizeType.B5: return new Size(516, 729);
case PageSizeType.DLEnvelope: return new Size(312, 624);
case PageSizeType.C5Envelope: return new Size(459, 649);
case PageSizeType.Quarto: return new Size(609, 780);
case PageSizeType.C6Quarto: return new Size(323, 459);
case PageSizeType.B5Quarto: return new Size(499, 709);
case PageSizeType.ItalyQuarto: return new Size(312, 652);
case PageSizeType.A4small: return new Size(595, 842);
case PageSizeType.GermanStdFanfold: return new Size(612, 864);
case PageSizeType.GermanLegalFanfold: return new Size(576, 936);
case PageSizeType.PRC16K: return new Size(414, 609);
case PageSizeType.PRC32K: return new Size(275, 428);
default: return _pageSize;
}
}
private PageSizeOrientation _pageSizeOrientation;
public PageSizeOrientation PageSizeOrientation
{
get
{
return _pageSizeOrientation;
}
set
{
SetProperty(ref _pageSizeOrientation, value);
RaisePropertyChanged(nameof(PageSize));
}
}
private PageUnit _pageUnit = PageUnit.cm;
[Browsable(false)]
public PageUnit PageUnit
{
get
{
return _pageUnit;
}
set
{
if (value != PageUnit.cm && value != PageUnit.inch)
{
return;
}
SetProperty(ref _pageUnit, value);
}
}
private Size _gridCellSize = new Size(100, 100);
public Size GridCellSize
{
get
{
return _gridCellSize;
}
set
{
SetProperty(ref _gridCellSize, value);
}
}
public double GridCellWidth
{
get
{
return _gridCellSize.Width;
}
set
{
_gridCellSize.Width = value;
RaisePropertyChanged(nameof(GridCellSize));
}
}
public double GridCellHeight
{
get
{
return _gridCellSize.Height;
}
set
{
_gridCellSize.Height = value;
RaisePropertyChanged(nameof(GridCellSize));
}
}
private Color _pageBackground = Colors.White;
public Color PageBackground
{
get
{
return _pageBackground;
}
set
{
SetProperty(ref _pageBackground, value);
}
}
private bool _showGrid;
public bool ShowGrid
{
get
{
return _showGrid;
}
set
{
SetProperty(ref _showGrid, value);
}
}
private Color _gridColor = Colors.LightGray;
public Color GridColor
{
get
{
return _gridColor;
}
set
{
SetProperty(ref _gridColor, value);
}
}
private double _gridMargin = 28d;
public double GridMargin
{
get
{
return _gridMargin;
}
set
{
SetProperty(ref _gridMargin, value);
}
}
private double _zoomValue = 1;
[Browsable(false)]
public double ZoomValue
{
get
{
return _zoomValue;
}
set
{
SetProperty(ref _zoomValue, value);
}
}
private string _name;
[Browsable(false)]
public string Name
{
get
{
return _name;
}
set
{
SetProperty(ref _name, value);
}
}
private DiagramType _diagramType;
[Browsable(false)]
public DiagramType DiagramType
{
get
{
return _diagramType;
}
set
{
SetProperty(ref _diagramType, value);
}
}
private CellHorizontalAlignment _cellHorizontalAlignment;
[Browsable(false)]
public CellHorizontalAlignment CellHorizontalAlignment
{
get
{
return _cellHorizontalAlignment;
}
set
{
SetProperty(ref _cellHorizontalAlignment, value);
}
}
private CellVerticalAlignment _cellVerticalAlignment;
[Browsable(false)]
public CellVerticalAlignment CellVerticalAlignment
{
get
{
return _cellVerticalAlignment;
}
set
{
SetProperty(ref _cellVerticalAlignment, value);
}
}
private bool _isEditName;
[Browsable(false)]
public bool IsEditName
{
get
{
return _isEditName;
}
set
{
SetProperty(ref _isEditName, value);
}
}
private System.Windows.Point _currentPoint;
[Browsable(false)]
public System.Windows.Point CurrentPoint
{
get
{
return _currentPoint;
}
set
{
SetProperty(ref _currentPoint, value);
}
}
private Color _currentColor;
[Browsable(false)]
public Color CurrentColor
{
get
{
return _currentColor;
}
set
{
SetProperty(ref _currentColor, value);
}
}
/// <summary>
/// 用于wpf大小与物理像素之间转换
/// </summary>
public double ScreenScale { get; set; } = 1;
private double OffsetX = 10;
private double OffsetY = 10;
#endregion
private DoCommandManager DoCommandManager = new DoCommandManager();
public DiagramViewModel()
{
CreateNewDiagramCommand = new SimpleCommand(ExecuteEnable, ExecuteCreateNewDiagramCommand);
AddItemCommand = new SimpleCommand(ExecuteEnable, ExecuteAddItemCommand);
DirectAddItemCommand = new SimpleCommand(ExecuteEnable, ExecuteDirectAddItemCommand);
RemoveItemCommand = new SimpleCommand(ExecuteEnable, ExecuteRemoveItemCommand);
DirectRemoveItemCommand = new SimpleCommand(ExecuteEnable, ExecuteDirectRemoveItemCommand);
ClearSelectedItemsCommand = new SimpleCommand(ExecuteEnable, ExecuteClearSelectedItemsCommand);
AlignTopCommand = new SimpleCommand(ExecuteEnable, ExecuteAlignTopCommand);
AlignVerticalCentersCommand = new SimpleCommand(ExecuteEnable, ExecuteAlignVerticalCentersCommand);
AlignBottomCommand = new SimpleCommand(ExecuteEnable, ExecuteAlignBottomCommand);
AlignLeftCommand = new SimpleCommand(ExecuteEnable, ExecuteAlignLeftCommand);
AlignHorizontalCentersCommand = new SimpleCommand(ExecuteEnable, ExecuteAlignHorizontalCentersCommand);
AlignRightCommand = new SimpleCommand(ExecuteEnable, ExecuteAlignRightCommand);
BringForwardCommand = new SimpleCommand(ExecuteEnable, ExecuteBringForwardCommand);
BringToFrontCommand = new SimpleCommand(ExecuteEnable, ExecuteBringToFrontCommand);
SendBackwardCommand = new SimpleCommand(ExecuteEnable, ExecuteSendBackwardCommand);
SendToBackCommand = new SimpleCommand(ExecuteEnable, ExecuteSendToBackCommand);
DistributeHorizontalCommand = new SimpleCommand(ExecuteEnable, ExecuteDistributeHorizontalCommand);
DistributeVerticalCommand = new SimpleCommand(ExecuteEnable, ExecuteDistributeVerticalCommand);
SelectAllCommand = new SimpleCommand(ExecuteEnable, ExecuteSelectAllCommand);
CopyCommand = new SimpleCommand(ExecuteEnable, ExecuteCopyCommand);
PasteCommand = new SimpleCommand(ExecuteEnable, ExecutePasteCommand);
CutCommand = new SimpleCommand(ExecuteEnable, ExecuteCutCommand);
DeleteCommand = new SimpleCommand(ExecuteEnable, ExecuteDeleteCommand);
LeftMoveCommand = new SimpleCommand(ExecuteEnable, ExecuteLeftMoveCommand);
RightMoveCommand = new SimpleCommand(ExecuteEnable, ExecuteRightMoveCommand);
UpMoveCommand = new SimpleCommand(ExecuteEnable, ExecuteUpMoveCommand);
DownMoveCommand = new SimpleCommand(ExecuteEnable, ExecuteDownMoveCommand);
CenterMoveCommand = new SimpleCommand(ExecuteEnable, ExecuteCenterMoveCommand);
SameSizeCommand = new SimpleCommand(ExecuteEnable, ExecuteSameSizeCommand);
SameWidthCommand = new SimpleCommand(ExecuteEnable, ExecuteSameWidthCommand);
SameHeightCommand = new SimpleCommand(ExecuteEnable, ExecuteSameHeightCommand);
SameAngleCommand = new SimpleCommand(ExecuteEnable, ExecuteSameAngleCommand);
GroupCommand = new SimpleCommand(ExecuteEnable, ExecuteGroupCommand);
UngroupCommand = new SimpleCommand(ExecuteEnable, ExecuteUngroupCommand);
LockCommand = new SimpleCommand(ExecuteEnable, ExecuteLockCommand);
UnlockCommand = new SimpleCommand(ExecuteEnable, ExecuteUnlockCommand);
Mediator.Instance.Register(this);
Items.CollectionChanged += Items_CollectionChanged;
}
public bool ExecuteEnable(object para)
{
return IsReadOnly == false;
}
#region UnDo ReDo
private void Do(object sender, string propertyName, object newvalue)
{
sender.SetPropertyValue(propertyName, newvalue);
}
private void UnDo(object sender, string propertyName, object oldvalue)
{
sender.SetPropertyValue(propertyName, oldvalue);
}
private bool _undoing;
private void UndoExecuted(object para)
{
_undoing = true;
DoCommandManager.UnDo();
_undoing = false;
}
private void RedoExecuted(object para)
{
_undoing = true;
DoCommandManager.ReDo();
_undoing = false;
}
private bool Undo_Enabled(object para)
{
return DoCommandManager.CanUnDo;
}
private bool Redo_Enabled(object para)
{
return DoCommandManager.CanReDo;
}
#endregion
private void Items_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.OldItems != null)
{
foreach (var item in e.OldItems.OfType<SelectableDesignerItemViewModelBase>())
{
item.PropertyChanged -= Item_PropertyChanged;
item.Dispose();
}
}
if (e.NewItems != null)
{
foreach (var item in e.NewItems.OfType<SelectableDesignerItemViewModelBase>())
{
item.PropertyChanged += Item_PropertyChanged;
}
}
RaisePropertyChanged("Items");
}
private void Item_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
RaisePropertyChanged(sender, e.PropertyName);
if (_undoing == true) return;
//连续改变需要特殊处理不单独触发属性改变ReDo
if (sender is DesignerItemViewModelBase designer)
{
if (designer.BeginDo) return;
}
if (e is ValuePropertyChangedEventArgs valuePropertyChangedEventArgs)
{
var property = sender.GetType().GetProperty(e.PropertyName);
var attr = property.GetCustomAttributes(typeof(CanDoAttribute), true);
if (attr != null && attr.Length != 0)
{
DoCommandManager.DoNewCommand(sender.ToString() + e.PropertyName, () => Do(sender, e.PropertyName, valuePropertyChangedEventArgs.NewValue), () => UnDo(sender, e.PropertyName, valuePropertyChangedEventArgs.OldValue), null, false);
}
}
}
[MediatorMessageSink("DoneDrawingMessage")]
public void OnDoneDrawingMessage(bool dummy)
{
foreach (var item in Items.OfType<DesignerItemViewModelBase>())
{
item.ShowConnectors = false;
}
}
public SimpleCommand CreateNewDiagramCommand
{
get; private set;
}
public SimpleCommand DirectAddItemCommand
{
get; private set;
}
public SimpleCommand AddItemCommand
{
get; private set;
}
public SimpleCommand DirectRemoveItemCommand
{
get; private set;
}
public SimpleCommand RemoveItemCommand
{
get; private set;
}
public SimpleCommand ClearSelectedItemsCommand
{
get; private set;
}
public SimpleCommand AlignTopCommand
{
get; private set;
}
public SimpleCommand AlignVerticalCentersCommand
{
get; private set;
}
public SimpleCommand AlignBottomCommand
{
get; private set;
}
public SimpleCommand AlignLeftCommand
{
get; private set;
}
public SimpleCommand AlignHorizontalCentersCommand
{
get; private set;
}
public SimpleCommand AlignRightCommand
{
get; private set;
}
public SimpleCommand BringForwardCommand
{
get; private set;
}
public SimpleCommand BringToFrontCommand
{
get; private set;
}
public SimpleCommand SendBackwardCommand
{
get; private set;
}
public SimpleCommand SendToBackCommand
{
get; private set;
}
public SimpleCommand DistributeHorizontalCommand
{
get; private set;
}
public SimpleCommand DistributeVerticalCommand
{
get; private set;
}
public SimpleCommand SelectAllCommand
{
get; private set;
}
public SimpleCommand CopyCommand
{
get; private set;
}
public SimpleCommand PasteCommand
{
get; private set;
}
public SimpleCommand CutCommand
{
get; private set;
}
public SimpleCommand DeleteCommand
{
get; private set;
}
public SimpleCommand LeftMoveCommand
{
get; private set;
}
public SimpleCommand RightMoveCommand
{
get; private set;
}
public SimpleCommand UpMoveCommand
{
get; private set;
}
public SimpleCommand DownMoveCommand
{
get; private set;
}
public SimpleCommand CenterMoveCommand
{
get; private set;
}
public SimpleCommand SameSizeCommand
{
get; private set;
}
public SimpleCommand SameWidthCommand
{
get; private set;
}
public SimpleCommand SameHeightCommand
{
get; private set;
}
public SimpleCommand SameAngleCommand
{
get; private set;
}
public SimpleCommand GroupCommand
{
get; private set;
}
public SimpleCommand UngroupCommand
{
get; private set;
}
public SimpleCommand LockCommand
{
get; private set;
}
public SimpleCommand UnlockCommand
{
get; private set;
}
private SimpleCommand _undoCommand;
public SimpleCommand UndoCommand
{
get
{
return this._undoCommand ?? (this._undoCommand = new SimpleCommand(Undo_Enabled, this.UndoExecuted));
}
}
private SimpleCommand _redoCommand;
public SimpleCommand RedoCommand
{
get
{
return this._redoCommand ?? (this._redoCommand = new SimpleCommand(Redo_Enabled, this.RedoExecuted));
}
}
public ObservableCollection<SelectableDesignerItemViewModelBase> Items { get; set; } = new ObservableCollection<SelectableDesignerItemViewModelBase>();
public List<SelectableDesignerItemViewModelBase> SelectedItems
{
get
{
return Items.Where(x => x.IsSelected).ToList();
}
}
private SelectionService selectionService;
public SelectionService SelectionService
{
get
{
if (selectionService == null)
selectionService = new SelectionService(this);
return selectionService;
}
}
public Func<SelectableDesignerItemViewModelBase, bool> OutAddVerify
{
get; set;
}
public bool AddVerify(SelectableDesignerItemViewModelBase item)
{
if (item.InitData() == false)
return false;
if (OutAddVerify != null && OutAddVerify(item) != true)
return false;
return true;
}
private void ExecuteCreateNewDiagramCommand(object parameter)
{
this.Items.Clear();
}
private void ExecuteDirectAddItemCommand(object parameter)
{
if (parameter is SelectableDesignerItemViewModelBase ite)
{
if (AddVerify(ite) != true) return;
ClearSelectedItems();
Add(ite);
}
else if (parameter is List<SelectableDesignerItemViewModelBase> items)
{
if (items.Select(p => AddVerify(p)).Any() != true) return;
ClearSelectedItems();
foreach (var item in items)
{
Add(item);
}
}
}
private void Add(SelectableDesignerItemViewModelBase item)
{
item.Parent = this;
item.ZIndex = Items.Count;
if (item.Id == Guid.Empty)
{
item.Id = Guid.NewGuid();
}
//item.LineColor = this.LineColor;
//item.FillColor = this.FillColor;
var logical = item as LogicalGateItemViewModelBase;
if (logical != null && logical.LogicalType > 0)
{
logical.OrderNumber = Items.OfType<LogicalGateItemViewModelBase>().Count(p => (int)p.LogicalType > 0) + 1;
}
var designerItemViewModelBase = item as DesignerItemViewModelBase;
if (designerItemViewModelBase != null)
{
designerItemViewModelBase.SetCellAlignment();
}
Items.Add(item);
item.IsSelected = true;
}
private void ExecuteAddItemCommand(object parameter)
{
if (parameter is SelectableDesignerItemViewModelBase ite)
{
if (AddVerify(ite) != true) return;
DoCommandManager.DoNewCommand(this.ToString(),
() => {
ClearSelectedItems();
Add(ite);
},
() => {
Items.Remove(ite);
});
}
else if (parameter is List<SelectableDesignerItemViewModelBase> items)
{
if (items.Select(p => AddVerify(p)).Any() != true) return;
DoCommandManager.DoNewCommand(this.ToString(),
() => {
ClearSelectedItems();
foreach (var item in items)
{
Add(item);
}
},
() => {
items.ForEach(item => Items.Remove(item));
});
}
}
private void ExecuteDirectRemoveItemCommand(object parameter)
{
if (parameter is SelectableDesignerItemViewModelBase ite)
{
ite.IsSelected = false;
Items.Remove(ite);
if (ite.OutTextItem != null)
{
Items.Remove(ite.OutTextItem);
}
}
else if (parameter is List<SelectableDesignerItemViewModelBase> items)
{
foreach (var item in items)
{
item.IsSelected = false;
Items.Remove(item);
if (item.OutTextItem != null)
{
Items.Remove(item.OutTextItem);
}
}
}
}
private void ExecuteRemoveItemCommand(object parameter)
{
if (parameter is SelectableDesignerItemViewModelBase ite)
{
DoCommandManager.DoNewCommand(this.ToString(),
() => {
ite.IsSelected = false;
Items.Remove(ite);
if (ite.OutTextItem != null)
{
Items.Remove(ite.OutTextItem);
}
},
() => {
Items.Add(ite);
});
}
else if (parameter is List<SelectableDesignerItemViewModelBase> items)
{
DoCommandManager.DoNewCommand(this.ToString(),
() => {
foreach (var item in items)
{
item.IsSelected = false;
Items.Remove(item);
if (item.OutTextItem != null)
{
Items.Remove(item.OutTextItem);
}
}
},
() => {
foreach (var item in items)
{
Items.Add(item);
if (item.OutTextItem != null)
{
Items.Add(item.OutTextItem);
}
}
});
}
}
private void ExecuteClearSelectedItemsCommand(object parameter)
{
ClearSelectedItems();
}
public void ClearSelectedItems()
{
foreach (var item in this.Items.ToList())
{
item.IsSelected = false;
}
}
#region
private void ExecuteAlignTopCommand(object parameter)
{
var selectedItems = this.SelectedItems.OfType<DesignerItemViewModelBase>();
var guid = Guid.NewGuid();
if (selectedItems.Count() > 1)
{
DoCommandManager.DoNewCommand(this.ToString(),
() => {
double top = selectedItems.OrderBy(p => p.Top).Select(p => p.Top).FirstOrDefault();
foreach (DesignerItemViewModelBase item in selectedItems)
{
item.SetOldValue(item.Top, nameof(item.Top), guid.ToString());
item.Top = top;
}
},
() => {
foreach (DesignerItemViewModelBase item in selectedItems)
{
item.Top = item.GetOldValue<double>(nameof(item.Top), guid.ToString());
}
},
() => {
foreach (DesignerItemViewModelBase item in selectedItems)
{
item.ClearOldValue<double>(nameof(item.Top), guid.ToString());
}
});
}
}
private void ExecuteAlignVerticalCentersCommand(object parameter)
{
var selectedItems = this.SelectedItems.OfType<DesignerItemViewModelBase>();
var guid = Guid.NewGuid();
if (selectedItems.Count() > 1)
{
DoCommandManager.DoNewCommand(this.ToString(),
() => {
double mid = selectedItems.Select(p => p.Top + p.ItemHeight / 2).Average();
foreach (DesignerItemViewModelBase item in selectedItems)
{
item.SetOldValue(item.Top, nameof(item.Top), guid.ToString());
item.Top = mid - item.ItemHeight / 2;
}
},
() => {
foreach (DesignerItemViewModelBase item in selectedItems)
{
item.Top = item.GetOldValue<double>(nameof(item.Top), guid.ToString());
}
},
() => {
foreach (DesignerItemViewModelBase item in selectedItems)
{
item.ClearOldValue<double>(nameof(item.Top), guid.ToString());
}
});
}
}
private void ExecuteAlignBottomCommand(object parameter)
{
var selectedItems = this.SelectedItems.OfType<DesignerItemViewModelBase>();
var guid = Guid.NewGuid();
if (selectedItems.Count() > 1)
{
DoCommandManager.DoNewCommand(this.ToString(),
() => {
double top = selectedItems.OrderBy(p => p.Top + p.ItemHeight).Select(p => p.Top + p.ItemHeight).LastOrDefault();
foreach (DesignerItemViewModelBase item in selectedItems)
{
item.SetOldValue(item.Top, nameof(item.Top), guid.ToString());
item.Top = top - item.ItemHeight;
}
},
() => {
foreach (DesignerItemViewModelBase item in selectedItems)
{
item.Top = item.GetOldValue<double>(nameof(item.Top), guid.ToString());
}
},
() => {
foreach (DesignerItemViewModelBase item in selectedItems)
{
item.ClearOldValue<double>(nameof(item.Top), guid.ToString());
}
});
}
}
private void ExecuteAlignLeftCommand(object parameter)
{
var selectedItems = this.SelectedItems.OfType<DesignerItemViewModelBase>();
var guid = Guid.NewGuid();
if (selectedItems.Count() > 1)
{
DoCommandManager.DoNewCommand(this.ToString(),
() => {
double left = selectedItems.OrderBy(p => p.Left).Select(p => p.Left).FirstOrDefault();
foreach (DesignerItemViewModelBase item in selectedItems)
{
item.SetOldValue(item.Left, nameof(item.Left), guid.ToString());
item.Left = left;
}
},
() => {
foreach (DesignerItemViewModelBase item in selectedItems)
{
item.Left = item.GetOldValue<double>(nameof(item.Left), guid.ToString());
}
},
() => {
foreach (DesignerItemViewModelBase item in selectedItems)
{
item.ClearOldValue<double>(nameof(item.Left), guid.ToString());
}
});
}
}
private void ExecuteAlignHorizontalCentersCommand(object parameter)
{
var selectedItems = this.SelectedItems.OfType<DesignerItemViewModelBase>();
var guid = Guid.NewGuid();
if (selectedItems.Count() > 1)
{
DoCommandManager.DoNewCommand(this.ToString(),
() => {
double mid = selectedItems.Select(p => p.Left + p.ItemWidth / 2).Average();
foreach (DesignerItemViewModelBase item in selectedItems)
{
item.SetOldValue(item.Left, nameof(item.Left), guid.ToString());
item.Left = mid - item.ItemWidth / 2;
}
},
() => {
foreach (DesignerItemViewModelBase item in selectedItems)
{
item.Left = item.GetOldValue<double>(nameof(item.Left), guid.ToString());
}
},
() => {
foreach (DesignerItemViewModelBase item in selectedItems)
{
item.ClearOldValue<double>(nameof(item.Left), guid.ToString());
}
});
}
}
private void ExecuteAlignRightCommand(object parameter)
{
var selectedItems = this.SelectedItems.OfType<DesignerItemViewModelBase>();
var guid = Guid.NewGuid();
if (selectedItems.Count() > 1)
{
DoCommandManager.DoNewCommand(this.ToString(),
() => {
double right = selectedItems.OrderBy(p => p.Left + p.ItemWidth).Select(p => p.Left + p.ItemWidth).LastOrDefault();
foreach (DesignerItemViewModelBase item in selectedItems)
{
item.SetOldValue(item.Left, nameof(item.Left), guid.ToString());
item.Left = right - item.ItemWidth;
}
},
() => {
foreach (DesignerItemViewModelBase item in selectedItems)
{
item.Left = item.GetOldValue<double>(nameof(item.Left), guid.ToString());
}
},
() => {
foreach (DesignerItemViewModelBase item in selectedItems)
{
item.ClearOldValue<double>(nameof(item.Left), guid.ToString());
}
});
}
}
#endregion
private void ExecuteBringForwardCommand(object parameter)
{
List<SelectableDesignerItemViewModelBase> ordered = SelectedItems.OrderByDescending(p => p.ZIndex).ToList();
List<SelectableDesignerItemViewModelBase> changeditems = new List<SelectableDesignerItemViewModelBase>();
var guid = Guid.NewGuid();
DoCommandManager.DoNewCommand(this.ToString(),
() => {
int count = this.Items.Count;
for (int i = 0; i < ordered.Count; i++)
{
var item = ordered[i];
int currentIndex = item.ZIndex;
int newIndex = Math.Min(count - 1 - i, currentIndex + 1);
if (currentIndex != newIndex)
{
item.SetOldValue<int>(item.ZIndex, nameof(item.ZIndex), guid.ToString());
item.ZIndex = newIndex;
changeditems.Add(item);
IEnumerable<SelectableDesignerItemViewModelBase> it = this.Items.Where(p => p.ZIndex == newIndex);
foreach (var elm in it)
{
if (elm != item)
{
elm.SetOldValue<int>(elm.ZIndex, nameof(elm.ZIndex), guid.ToString());
elm.ZIndex = currentIndex;
changeditems.Add(elm);
break;
}
}
}
}
},
() => {
foreach (var item in changeditems)
{
item.ZIndex = item.GetOldValue<int>(nameof(item.ZIndex), guid.ToString());
}
},
() => {
foreach (var item in changeditems)
{
item.ClearOldValue<double>(nameof(item.ZIndex), guid.ToString());
}
});
}
private void ExecuteBringToFrontCommand(object parameter)
{
List<SelectableDesignerItemViewModelBase> selectionSorted = SelectedItems.OrderByDescending(p => p.ZIndex).ToList();
List<SelectableDesignerItemViewModelBase> childrenSorted = Items.OrderByDescending(p => p.ZIndex).ToList();
List<SelectableDesignerItemViewModelBase> changeditems = new List<SelectableDesignerItemViewModelBase>();
var guid = Guid.NewGuid();
DoCommandManager.DoNewCommand(this.ToString(),
() => {
int i = childrenSorted.Count - 1;
int j = childrenSorted.Count - selectionSorted.Count - 1;
foreach (SelectableDesignerItemViewModelBase item in childrenSorted)
{
item.SetOldValue<int>(item.ZIndex, nameof(item.ZIndex), guid.ToString());
if (selectionSorted.Contains(item))
{
item.ZIndex = i--;
}
else
{
item.ZIndex = j--;
}
changeditems.Add(item);
}
},
() => {
foreach (var item in changeditems)
{
item.ZIndex = item.GetOldValue<int>(nameof(item.ZIndex), guid.ToString());
}
},
() => {
foreach (var item in changeditems)
{
item.ClearOldValue<double>(nameof(item.ZIndex), guid.ToString());
}
});
}
private void ExecuteSendBackwardCommand(object parameter)
{
List<SelectableDesignerItemViewModelBase> ordered = this.SelectedItems.OrderBy(p => p.ZIndex).ToList();
int count = this.Items.Count;
List<SelectableDesignerItemViewModelBase> changeditems = new List<SelectableDesignerItemViewModelBase>();
var guid = Guid.NewGuid();
DoCommandManager.DoNewCommand(this.ToString(),
() => {
for (int i = 0; i < ordered.Count; i++)
{
var item = ordered[i];
int currentIndex = item.ZIndex;
int newIndex = Math.Max(i, currentIndex - 1);
if (currentIndex != newIndex)
{
item.SetOldValue<int>(item.ZIndex, nameof(item.ZIndex), guid.ToString());
item.ZIndex = newIndex;
changeditems.Add(item);
IEnumerable<SelectableDesignerItemViewModelBase> it = this.Items.Where(p => p.ZIndex == newIndex);
foreach (var elm in it)
{
if (elm != ordered[i])
{
elm.SetOldValue<int>(elm.ZIndex, nameof(elm.ZIndex), guid.ToString());
elm.ZIndex = currentIndex;
changeditems.Add(elm);
break;
}
}
}
}
},
() => {
foreach (var item in changeditems)
{
item.ZIndex = item.GetOldValue<int>(nameof(item.ZIndex), guid.ToString());
}
},
() => {
foreach (var item in changeditems)
{
item.ClearOldValue<double>(nameof(item.ZIndex), guid.ToString());
}
});
}
private void ExecuteSendToBackCommand(object parameter)
{
List<SelectableDesignerItemViewModelBase> selectionSorted = SelectedItems.OrderByDescending(p => p.ZIndex).ToList();
List<SelectableDesignerItemViewModelBase> childrenSorted = Items.OrderByDescending(p => p.ZIndex).ToList();
List<SelectableDesignerItemViewModelBase> changeditems = new List<SelectableDesignerItemViewModelBase>();
var guid = Guid.NewGuid();
DoCommandManager.DoNewCommand(this.ToString(),
() => {
int i = childrenSorted.Count - 1;
int j = selectionSorted.Count - 1;
foreach (SelectableDesignerItemViewModelBase item in childrenSorted)
{
item.SetOldValue<int>(item.ZIndex, nameof(item.ZIndex), guid.ToString());
if (selectionSorted.Contains(item))
{
item.ZIndex = j--;
}
else
{
item.ZIndex = i--;
}
changeditems.Add(item);
}
},
() => {
foreach (var item in changeditems)
{
item.ZIndex = item.GetOldValue<int>(nameof(item.ZIndex), guid.ToString());
}
},
() => {
foreach (var item in changeditems)
{
item.ClearOldValue<double>(nameof(item.ZIndex), guid.ToString());
}
});
}
private void ExecuteDistributeHorizontalCommand(object parameter)
{
var selectedItems = from item in this.SelectedItems.OfType<DesignerItemViewModelBase>()
where item.ParentId == Guid.Empty
orderby item.Left
select item;
var guid = Guid.NewGuid();
if (selectedItems.Count() > 1)
{
DoCommandManager.DoNewCommand(this.ToString(),
() => {
double left = Double.MaxValue;
double right = Double.MinValue;
double sumWidth = 0;
foreach (DesignerItemViewModelBase item in selectedItems)
{
left = Math.Min(left, item.Left);
right = Math.Max(right, item.Left + item.ItemWidth);
sumWidth += item.ItemWidth;
}
double distance = Math.Max(0, (right - left - sumWidth) / (selectedItems.Count() - 1));
double offset = selectedItems.First().Left;
foreach (DesignerItemViewModelBase item in selectedItems)
{
double delta = offset - item.Left;
foreach (DesignerItemViewModelBase di in SelectionService.GetGroupMembers(item))
{
di.SetOldValue(di.Left, nameof(di.Left), guid.ToString());
di.Left += delta;
}
offset = offset + item.ItemWidth + distance;
}
},
() => {
foreach (DesignerItemViewModelBase item in selectedItems)
{
foreach (DesignerItemViewModelBase di in SelectionService.GetGroupMembers(item))
{
di.Left = di.GetOldValue<double>(nameof(di.Left), guid.ToString());
}
}
},
() => {
foreach (DesignerItemViewModelBase item in selectedItems)
{
foreach (DesignerItemViewModelBase di in SelectionService.GetGroupMembers(item))
{
di.ClearOldValue<double>(nameof(di.Left), guid.ToString());
}
}
});
}
}
private void ExecuteDistributeVerticalCommand(object parameter)
{
var selectedItems = from item in this.SelectedItems.OfType<DesignerItemViewModelBase>()
where item.ParentId == Guid.Empty
orderby item.Top
select item;
var guid = Guid.NewGuid();
if (selectedItems.Count() > 1)
{
DoCommandManager.DoNewCommand(this.ToString(),
() => {
double top = Double.MaxValue;
double bottom = Double.MinValue;
double sumHeight = 0;
foreach (DesignerItemViewModelBase item in selectedItems)
{
top = Math.Min(top, item.Top);
bottom = Math.Max(bottom, item.Top + item.ItemHeight);
sumHeight += item.ItemHeight;
}
double distance = Math.Max(0, (bottom - top - sumHeight) / (selectedItems.Count() - 1));
double offset = selectedItems.First().Top;
foreach (DesignerItemViewModelBase item in selectedItems)
{
double delta = offset - item.Top;
foreach (DesignerItemViewModelBase di in SelectionService.GetGroupMembers(item))
{
di.SetOldValue(di.Top, nameof(di.Top), guid.ToString());
di.Top += +delta;
}
offset = offset + item.ItemHeight + distance;
}
},
() => {
foreach (DesignerItemViewModelBase item in selectedItems)
{
foreach (DesignerItemViewModelBase di in SelectionService.GetGroupMembers(item))
{
di.Top = di.GetOldValue<double>(nameof(di.Top), guid.ToString());
}
}
},
() => {
foreach (DesignerItemViewModelBase item in selectedItems)
{
foreach (DesignerItemViewModelBase di in SelectionService.GetGroupMembers(item))
{
di.ClearOldValue<double>(nameof(di.Top), guid.ToString());
}
}
});
}
}
private void ExecuteSelectAllCommand(object parameter)
{
foreach (var item in Items)
{
item.IsSelected = true;
}
}
private void ExecuteCopyCommand(object parameter)
{
List<DesignerItemViewModelBase> selectedDesignerItems =
SelectedItems.OfType<DesignerItemViewModelBase>().ToList();
List<ConnectorViewModel> selectedConnections =
SelectedItems.OfType<ConnectorViewModel>().ToList();
foreach (ConnectorViewModel connection in Items.OfType<ConnectorViewModel>())
{
if (!selectedConnections.Contains(connection))
{
DesignerItemViewModelBase sourceItem = (from item in selectedDesignerItems
where item.Id == connection.SourceConnectorInfo.DataItem.Id
select item).FirstOrDefault();
DesignerItemViewModelBase sinkItem = (from item in selectedDesignerItems
where item.Id == connection.SinkConnectorInfoFully?.DataItem?.Id
select item).FirstOrDefault();
if (sourceItem != null &&
sinkItem != null &&
BelongToSameGroup(sourceItem, sinkItem))
{
selectedConnections.Add(connection);
}
}
}
//连线上的文本
foreach (var selectedConnection in selectedConnections)
{
if (selectedConnection.OutTextItem != null)
{
selectedDesignerItems.Add(selectedConnection.OutTextItem);
}
}
string json = new SerializableObject
{
DesignerItems = selectedDesignerItems.Select(p => p.ToSerializabObject()).Where(p => p != null).ToList(),
Connections = selectedConnections.Select(p => p.ToSerializabObject()).Where(p => p != null).ToList(),
}.ToJson();
OffsetX = 10;
OffsetY = 10;
System.Windows.Clipboard.Clear();
System.Windows.Clipboard.SetData(System.Windows.DataFormats.Serializable, json);
}
private void ExecutePasteCommand(object parameter)
{
if (System.Windows.Clipboard.ContainsData(System.Windows.DataFormats.Serializable))
{
String clipboardData = System.Windows.Clipboard.GetData(System.Windows.DataFormats.Serializable) as String;
if (String.IsNullOrEmpty(clipboardData))
return;
try
{
List<SelectableDesignerItemViewModelBase> items = new List<SelectableDesignerItemViewModelBase>();
SerializableObject copyitem = JsonConvert.DeserializeObject<SerializableObject>(clipboardData);
Dictionary<Guid, Guid> mappingOldToNewIDs = new Dictionary<Guid, Guid>();
foreach (var diagramItemData in copyitem.DesignerItems)
{
DesignerItemViewModelBase newItem = null;
Type type = TypeHelper.GetType(diagramItemData.TypeName);
DesignerItemViewModelBase itemBase = (DesignerItemViewModelBase)Activator.CreateInstance(type, this, diagramItemData.ObjectJson);
Guid newID = Guid.NewGuid();
mappingOldToNewIDs.Add(itemBase.Id, newID);
itemBase.Id = newID;
itemBase.Left += OffsetX;
itemBase.Top += OffsetY;
newItem = itemBase;
if (newItem != null)
{
items.Add(newItem);
}
}
DirectAddItemCommand.Execute(items);
OffsetX += 10;
OffsetY += 10;
List<SelectableDesignerItemViewModelBase> connectors = new List<SelectableDesignerItemViewModelBase>();
foreach (var connection in copyitem.Connections)
{
var connectionItem = JsonConvert.DeserializeObject<ConnectionItem>(connection.ObjectJson);
Guid newID = Guid.NewGuid();
mappingOldToNewIDs.Add(connectionItem.Id, newID);
connectionItem.SourceId = mappingOldToNewIDs[connectionItem.SourceId];
connectionItem.SinkId = mappingOldToNewIDs[connectionItem.SinkId];
connectionItem.SourceType = System.Type.GetType(connectionItem.SourceTypeName);
connectionItem.SinkType = System.Type.GetType(connectionItem.SinkTypeName);
DesignerItemViewModelBase sourceItem = GetConnectorDataItem(this, connectionItem.SourceId, connectionItem.SourceType);
ConnectorOrientation sourceConnectorOrientation = connectionItem.SourceOrientation;
FullyCreatedConnectorInfo sourceConnectorInfo = GetFullConnectorInfo(connectionItem.Id, sourceItem, sourceConnectorOrientation, connectionItem.SourceXRatio, connectionItem.SourceYRatio, connectionItem.SourceInnerPoint);
DesignerItemViewModelBase sinkItem = GetConnectorDataItem(this, connectionItem.SinkId, connectionItem.SinkType);
ConnectorOrientation sinkConnectorOrientation = connectionItem.SinkOrientation;
FullyCreatedConnectorInfo sinkConnectorInfo = GetFullConnectorInfo(connectionItem.Id, sinkItem, sinkConnectorOrientation, connectionItem.SinkXRatio, connectionItem.SinkYRatio, connectionItem.SinkInnerPoint);
ConnectorViewModel connectionVM = new ConnectorViewModel(this, sourceConnectorInfo, sinkConnectorInfo, connectionItem);
connectors.Add(connectionVM);
DesignerItemViewModelBase textItem = items.OfType<DesignerItemViewModelBase>().FirstOrDefault(x => x.ParentId == connectionItem.Id);
if (textItem != null)
{
connectionVM.OutTextItem = textItem;
}
}
DirectAddItemCommand.Execute(connectors);
//修复父级的引用
foreach (var item in items)
{
if (item.ParentId != Guid.Empty)
{
if (mappingOldToNewIDs.ContainsKey(item.ParentId))
item.ParentId = mappingOldToNewIDs[item.ParentId];
}
}
}
catch (Exception e)
{
System.Windows.MessageBox.Show(e.StackTrace, e.Message, System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error);
}
}
}
private DesignerItemViewModelBase GetConnectorDataItem(IDiagramViewModel diagramViewModel, Guid conectorDataItemId, Type connectorDataItemType)
{
DesignerItemViewModelBase dataItem = diagramViewModel.Items.OfType<DesignerItemViewModelBase>().Single(x => x.Id == conectorDataItemId);
return dataItem;
}
private FullyCreatedConnectorInfo GetFullConnectorInfo(Guid connectorId, DesignerItemViewModelBase dataItem, ConnectorOrientation connectorOrientation, double xRatio, double yRatio, bool isInnerPoint)
{
if (isInnerPoint)
{
return dataItem.Connectors.Where(p => p.XRatio == xRatio && p.YRatio == yRatio).FirstOrDefault();
}
else
{
switch (connectorOrientation)
{
case ConnectorOrientation.Top:
return dataItem.TopConnector;
case ConnectorOrientation.Left:
return dataItem.LeftConnector;
case ConnectorOrientation.Right:
return dataItem.RightConnector;
case ConnectorOrientation.Bottom:
return dataItem.BottomConnector;
default:
throw new InvalidOperationException(
string.Format("Found invalid persisted Connector Orientation for Connector Id: {0}", connectorId));
}
}
}
private bool ItemsToDeleteHasConnector(List<SelectableDesignerItemViewModelBase> itemsToRemove, ConnectorInfoBase connector)
{
if (connector is FullyCreatedConnectorInfo fully)
{
return itemsToRemove.Contains(fully.DataItem);
}
return false;
}
private void ExecuteCutCommand(object parameter)
{
ExecutePasteCommand(null);
OffsetX = 0;
OffsetY = 0;
ExecuteDeleteCommand(null);
}
private void ExecuteDeleteCommand(object parameter)
{
List<SelectableDesignerItemViewModelBase> itemsToRemove = SelectedItems.OfType<SelectableDesignerItemViewModelBase>().ToList();
List<SelectableDesignerItemViewModelBase> connectionsToAlsoRemove = new List<SelectableDesignerItemViewModelBase>();
foreach (var connector in Items.OfType<ConnectorViewModel>())
{
if (ItemsToDeleteHasConnector(itemsToRemove, connector.SourceConnectorInfo))
{
connectionsToAlsoRemove.Add(connector);
}
if (ItemsToDeleteHasConnector(itemsToRemove, connector.SinkConnectorInfo))
{
connectionsToAlsoRemove.Add(connector);
}
}
itemsToRemove.AddRange(connectionsToAlsoRemove);
RemoveItemCommand.Execute(itemsToRemove);
}
private void ExecuteLeftMoveCommand(object parameter)
{
foreach (var item in SelectedItems.OfType<DesignerItemViewModelBase>())
{
item.Left -= 0.5;
}
}
private void ExecuteRightMoveCommand(object parameter)
{
foreach (var item in SelectedItems.OfType<DesignerItemViewModelBase>())
{
item.Left += 0.5;
}
}
private void ExecuteUpMoveCommand(object parameter)
{
foreach (var item in SelectedItems.OfType<DesignerItemViewModelBase>())
{
item.Top -= 0.5;
}
}
private void ExecuteDownMoveCommand(object parameter)
{
foreach (var item in SelectedItems.OfType<DesignerItemViewModelBase>())
{
item.Top += 0.5;
}
}
private void ExecuteCenterMoveCommand(object parameter)
{
foreach (var item in SelectedItems.OfType<DesignerItemViewModelBase>())
{
item.Left = (PageSize.Width - item.ItemWidth) / 2;
item.Top = (PageSize.Height - item.ItemHeight) / 2;
}
}
private void ExecuteSameSizeCommand(object parameter)
{
if (parameter is DesignerItemViewModelBase designerItem)
{
foreach (var item in SelectedItems.OfType<DesignerItemViewModelBase>())
{
item.ItemWidth = designerItem.ItemWidth;
item.ItemHeight = designerItem.ItemHeight;
}
}
}
private void ExecuteSameWidthCommand(object parameter)
{
if (parameter is DesignerItemViewModelBase designerItem)
{
foreach (var item in SelectedItems.OfType<DesignerItemViewModelBase>())
{
item.ItemWidth = designerItem.ItemWidth;
}
}
}
private void ExecuteSameHeightCommand(object parameter)
{
if (parameter is DesignerItemViewModelBase designerItem)
{
foreach (var item in SelectedItems.OfType<DesignerItemViewModelBase>())
{
item.ItemHeight = designerItem.ItemHeight;
}
}
}
private void ExecuteSameAngleCommand(object parameter)
{
if (parameter is DesignerItemViewModelBase designerItem)
{
foreach (var item in SelectedItems.OfType<DesignerItemViewModelBase>())
{
item.Angle = designerItem.Angle;
}
}
}
private void ExecuteGroupCommand(object parameter)
{
var items = from item in SelectedItems.OfType<DesignerItemViewModelBase>()
where item.ParentId == Guid.Empty
select item;
RectangleBase rect = GetBoundingRectangle(items);
GroupDesignerItemViewModel groupItem = new GroupDesignerItemViewModel();
groupItem.IsGroup = true;
groupItem.ItemWidth = rect.Width;
groupItem.ItemHeight = rect.Height;
groupItem.Left = rect.Left;
groupItem.Top = rect.Top;
groupItem.ZIndex = Items.Count;
DirectAddItemCommand.Execute(groupItem);
foreach (DesignerItemViewModelBase item in items)
item.ParentId = groupItem.Id;
ClearSelectedItemsCommand.Execute(null);
//groupItem.IsSelected = true;
SelectionService.AddToSelection(groupItem);
}
private void ExecuteUngroupCommand(object parameter)
{
var groups = (from item in SelectedItems.OfType<DesignerItemViewModelBase>()
where item.IsGroup && item.ParentId == Guid.Empty
select item).ToArray();
foreach (DesignerItemViewModelBase groupRoot in groups)
{
var children = from child in SelectedItems.OfType<DesignerItemViewModelBase>()
where child.ParentId == groupRoot.Id
select child;
foreach (DesignerItemViewModelBase child in children)
child.ParentId = Guid.Empty;
RemoveItemCommand.Execute(groupRoot);
UpdateZIndex();
}
}
private void ExecuteLockCommand(object parameter)
{
}
private void ExecuteUnlockCommand(object parameter)
{
}
public bool BelongToSameGroup(IGroupable item1, IGroupable item2)
{
IGroupable root1 = SelectionService.GetGroupRoot(item1);
IGroupable root2 = SelectionService.GetGroupRoot(item2);
return (root1.Id == root2.Id);
}
public void UpdateZIndex()
{
List<SelectableDesignerItemViewModelBase> ordered = Items.OrderBy(p => p.ZIndex).ToList();
for (int i = 0; i < ordered.Count; i++)
{
ordered[i].ZIndex = i;
}
}
public RectangleBase GetBoundingRectangle(IEnumerable<DesignerItemViewModelBase> items)
{
double x1 = Double.MaxValue;
double y1 = Double.MaxValue;
double x2 = Double.MinValue;
double y2 = Double.MinValue;
foreach (DesignerItemViewModelBase item in items)
{
x1 = Math.Min(item.Left, x1);
y1 = Math.Min(item.Top, y1);
x2 = Math.Max(item.Left + item.ItemWidth, x2);
y2 = Math.Max(item.Top + item.ItemHeight, y2);
}
return new RectangleBase(new PointBase(x1, y1), new PointBase(x2, y2));
}
#region wpf大小与物理像素之间转换
public void SetScreenScale()
{
ScreenScale = ScreenHelper.ResetScreenScale();
}
#endregion
}
}