using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Linq; using System.Reactive.Linq; using System.Text.RegularExpressions; using System.Windows; using System.Windows.Controls; 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; using Newtonsoft.Json.Linq; namespace AIStudio.Wpf.DiagramDesigner { public class DiagramViewModel : BindableBase, IDiagramViewModel { #region 属性 public ObservableCollection Items { get; set; } = new ObservableCollection(); public List SelectedItems { get { return Items.Where(x => x.IsSelected).ToList(); } } public SelectableDesignerItemViewModelBase SelectedItem { get { return SelectedItems.FirstOrDefault(); } } private SelectionService selectionService; public SelectionService SelectionService { get { if (selectionService == null) selectionService = new SelectionService(this); return selectionService; } } 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; } public IFontViewModel FontViewModel { get; set; } public IShapeViewModel ShapeViewModel { get; set; } public IAnimationViewModel AnimationViewModel { 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 { if (SetProperty(ref _pageSize, value)) { RaisePropertyChanged(nameof(PhysicalPageSize)); } } } public Size PhysicalPageSize { get { return new Size(ScreenHelper.WidthToMm(PageSize.Width), ScreenHelper.WidthToMm(PageSize.Height)); } set { PageSize = new Size(ScreenHelper.MmToWidth(value.Width), ScreenHelper.MmToWidth(value.Height)); } } public Size GetPageSize() { Size size = _pageSize; switch (PageSizeType) { case PageSizeType.A3: size = new Size(297, 420); break; case PageSizeType.A4: size = new Size(210, 297); break; case PageSizeType.A5: size = new Size(148, 210); break; case PageSizeType.B4: size = new Size(257, 364); break; case PageSizeType.B5: size = new Size(176, 250); break; case PageSizeType.DLEnvelope: size = new Size(110, 220); break; case PageSizeType.C5Envelope: size = new Size(162, 229); break; case PageSizeType.Quarto: size = new Size(215, 275); break; case PageSizeType.C6Quarto: size = new Size(114, 162); break; case PageSizeType.B5Quarto: size = new Size(176, 250); break; case PageSizeType.ItalyQuarto: size = new Size(110, 230); break; case PageSizeType.A4small: size = new Size(210, 297); break; case PageSizeType.GermanStdFanfold: size = new Size(215.9, 304.8); break; case PageSizeType.GermanLegalFanfold: size = new Size(203.2, 330.2); break; case PageSizeType.PRC16K: size = new Size(146, 215); break; case PageSizeType.PRC32K: size = new Size(97, 151); break; case PageSizeType.Letter: size = new Size(215.9, 279.4); break; case PageSizeType.Folio: size = new Size(215.9, 330.2); break; case PageSizeType.Legal: size = new Size(215.9, 355.6); break; case PageSizeType.Executive: size = new Size(184.15, 266.7); break; case PageSizeType.Statement: size = new Size(139.7, 215.9); break; case PageSizeType.Envelope: size = new Size(104.77, 241.3); break; case PageSizeType.MonarchEnvelope: size = new Size(98.425, 190.5); break; case PageSizeType.Tabloid: size = new Size(279.4, 431.8); break; case PageSizeType.LetterSmall: size = new Size(215.9, 279.4); break; case PageSizeType.CSheet: size = new Size(431.8, 558.8); break; case PageSizeType.DSheet: size = new Size(558.8, 863.6); break; case PageSizeType.ESheet: size = new Size(863.6, 1117.6); break; } return new Size(ScreenHelper.MmToWidth(size.Width), ScreenHelper.MmToWidth(size.Height)); } 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(PhysicalGridCellWidth)); RaisePropertyChanged(nameof(GridCellSize)); } } public double GridCellHeight { get { return _gridCellSize.Height; } set { _gridCellSize.Height = value; RaisePropertyChanged(nameof(PhysicalGridCellHeight)); RaisePropertyChanged(nameof(GridCellSize)); } } public Size PhysicalGridCellSize { get { return new Size(ScreenHelper.WidthToMm(GridCellSize.Width), ScreenHelper.WidthToMm(GridCellSize.Height)); } set { GridCellSize = new Size(ScreenHelper.MmToWidth(value.Width), ScreenHelper.MmToWidth(value.Height)); } } public double PhysicalGridCellWidth { get { return ScreenHelper.WidthToMm(GridCellWidth); } set { GridCellWidth = ScreenHelper.MmToWidth(value); } } public double PhysicalGridCellHeight { get { return ScreenHelper.WidthToMm(GridCellHeight); } set { GridCellHeight = ScreenHelper.MmToWidth(value); } } private Color _pageBackground = Colors.White; public Color PageBackground { get { return _pageBackground; } set { SetProperty(ref _pageBackground, value); } } private bool _showGrid = true; 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 Size _gridMarginSize = new Size(28, 28); public Size GridMarginSize { get { return _gridMarginSize; } set { SetProperty(ref _gridMarginSize, value); } } public double GridMarginWidth { get { return _gridMarginSize.Width; } set { _gridMarginSize.Width = value; RaisePropertyChanged(nameof(GridMarginSize)); } } public double GridMarginHeight { get { return _gridMarginSize.Height; } set { _gridMarginSize.Height = value; RaisePropertyChanged(nameof(GridMarginSize)); } } public Size PhysicalGridMarginSize { get { return new Size(ScreenHelper.WidthToMm(GridMarginSize.Width), ScreenHelper.WidthToMm(GridMarginSize.Height)); } set { GridMarginSize = new Size(ScreenHelper.MmToWidth(value.Width), ScreenHelper.MmToWidth(value.Height)); } } public double PhysicalGridMarginWidth { get { return ScreenHelper.WidthToMm(GridMarginWidth); } set { GridMarginWidth = ScreenHelper.MmToWidth(value); } } public double PhysicalGridMarginHeight { get { return ScreenHelper.WidthToMm(GridMarginHeight); } set { GridMarginHeight = ScreenHelper.MmToWidth(value); } } private double _zoomValue = 1; [Browsable(false)] public double ZoomValue { get { return _zoomValue; } set { SetProperty(ref _zoomValue, value); } } private double _maximumZoomValue = 100; [Browsable(false)] public double MaximumZoomValue { get { return _maximumZoomValue; } set { SetProperty(ref _maximumZoomValue, value); } } private double _minimumZoomValue = 0.1; [Browsable(false)] public double MinimumZoomValue { get { return _minimumZoomValue; } set { SetProperty(ref _minimumZoomValue, value); } } private bool _defaultZoomBox; public bool DefaultZoomBox { get { return _defaultZoomBox; } set { SetProperty(ref _defaultZoomBox, value); } } private double _delayZoomValue = 1; [Browsable(false)] public double DelayZoomValue { get { return _delayZoomValue; } set { SetProperty(ref _delayZoomValue, value); } } private FitViewModel _fitViewModel; public FitViewModel FitViewModel { get { return _fitViewModel; } set { SetProperty(ref _fitViewModel, 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); } } private bool _showSearch; public bool ShowSearch { get { return _showSearch; } set { SetProperty(ref _showSearch, value); } } private string _searchText; public string SearchText { get { return _searchText; } set { SetProperty(ref _searchText, value); } } private string _replaceText; public string ReplaceText { get { return _replaceText; } set { SetProperty(ref _replaceText, value); } } private string _searchInfo; public string SearchInfo { get { return _searchInfo; } set { SetProperty(ref _searchInfo, value); } } private bool _searchCaseMatch; public bool SearchCaseMatch { get { return _searchCaseMatch; } set { SetProperty(ref _searchCaseMatch, value); } } private bool _searchWholeWordMatch; public bool SearchWholeWordMatch { get { return _searchWholeWordMatch; } set { SetProperty(ref _searchWholeWordMatch, value); } } protected ObservableCollection menuOptions; public IEnumerable MenuOptions { get { return menuOptions; } } public bool ShowMenuOptions { get { if (MenuOptions == null || MenuOptions.Count() == 0) return false; else return true; } } public DiagramOption DiagramOption { get; set; } = new DiagramOption(); public bool AllowDrop { get; set; } = true; public DoCommandManager DoCommandManager { get; private set; } = new DoCommandManager(); public event DiagramEventHandler Event; protected double OffsetX = 10; protected double OffsetY = 10; #endregion #region 命令 private ICommand _clearCommand; public ICommand ClearCommand { get { return this._clearCommand ?? (this._clearCommand = new SimpleCommand(ExecuteEnable, ExecuteClearCommand)); } } private ICommand _addItemCommand; public ICommand AddItemCommand { get { return this._addItemCommand ?? (this._addItemCommand = new SimpleCommand(ExecuteEnable, ExecuteAddItemCommand)); } } private ICommand _removeItemCommand; public ICommand RemoveItemCommand { get { return this._removeItemCommand ?? (this._removeItemCommand = new SimpleCommand(ExecuteEnable, ExecuteRemoveItemCommand)); } } private ICommand _clearSelectedItemsCommand; public ICommand ClearSelectedItemsCommand { get { return this._clearSelectedItemsCommand ?? (this._clearSelectedItemsCommand = new SimpleCommand(ExecuteEnable, ExecuteClearSelectedItemsCommand)); } } private ICommand _alignTopCommand; public ICommand AlignTopCommand { get { return this._alignTopCommand ?? (this._alignTopCommand = new SimpleCommand(ExecuteEnable, ExecuteAlignTopCommand)); } } private ICommand _alignVerticalCentersCommand; public ICommand AlignVerticalCentersCommand { get { return this._alignVerticalCentersCommand ?? (this._alignVerticalCentersCommand = new SimpleCommand(ExecuteEnable, ExecuteAlignVerticalCentersCommand)); } } private ICommand _alignBottomCommand; public ICommand AlignBottomCommand { get { return this._alignBottomCommand ?? (this._alignBottomCommand = new SimpleCommand(ExecuteEnable, ExecuteAlignBottomCommand)); } } private ICommand _alignLeftCommand; public ICommand AlignLeftCommand { get { return this._alignLeftCommand ?? (this._alignLeftCommand = new SimpleCommand(ExecuteEnable, ExecuteAlignLeftCommand)); } } private ICommand _alignHorizontalCentersCommand; public ICommand AlignHorizontalCentersCommand { get { return this._alignHorizontalCentersCommand ?? (this._alignHorizontalCentersCommand = new SimpleCommand(ExecuteEnable, ExecuteAlignHorizontalCentersCommand)); } } private ICommand _alignRightCommand; public ICommand AlignRightCommand { get { return this._alignRightCommand ?? (this._alignRightCommand = new SimpleCommand(ExecuteEnable, ExecuteAlignRightCommand)); } } private ICommand _bringForwardCommand; public ICommand BringForwardCommand { get { return this._bringForwardCommand ?? (this._bringForwardCommand = new SimpleCommand(ExecuteEnable, ExecuteBringForwardCommand)); } } private ICommand _bringToFrontCommand; public ICommand BringToFrontCommand { get { return this._bringToFrontCommand ?? (this._bringToFrontCommand = new SimpleCommand(ExecuteEnable, ExecuteBringToFrontCommand)); } } private ICommand _sendBackwardCommand; public ICommand SendBackwardCommand { get { return this._sendBackwardCommand ?? (this._sendBackwardCommand = new SimpleCommand(ExecuteEnable, ExecuteSendBackwardCommand)); } } private ICommand _sendToBackCommand; public ICommand SendToBackCommand { get { return this._sendToBackCommand ?? (this._sendToBackCommand = new SimpleCommand(ExecuteEnable, ExecuteSendToBackCommand)); } } private ICommand _distributeHorizontalCommand; public ICommand DistributeHorizontalCommand { get { return this._distributeHorizontalCommand ?? (this._distributeHorizontalCommand = new SimpleCommand(ExecuteEnable, ExecuteDistributeHorizontalCommand)); } } private ICommand _distributeVerticalCommand; public ICommand DistributeVerticalCommand { get { return this._distributeVerticalCommand ?? (this._distributeVerticalCommand = new SimpleCommand(ExecuteEnable, ExecuteDistributeVerticalCommand)); } } private ICommand _selectAllCommand; public ICommand SelectAllCommand { get { return this._selectAllCommand ?? (this._selectAllCommand = new SimpleCommand(ExecuteEnable, ExecuteSelectAllCommand)); } } private ICommand _selectInverseCommand; public ICommand SelectInverseCommand { get { return this._selectInverseCommand ?? (this._selectInverseCommand = new SimpleCommand(ExecuteEnable, ExecuteSelectInverseCommand)); } } private ICommand _selectItemCommand; public ICommand SelectItemCommand { get { return this._selectItemCommand ?? (this._selectItemCommand = new SimpleCommand(ExecuteEnable, ExecuteSelectItemCommand)); } } private ICommand _copyCommand; public ICommand CopyCommand { get { return this._copyCommand ?? (this._copyCommand = new SimpleCommand(ExecuteEnable, ExecuteCopyCommand)); } } private ICommand _pasteCommand; public ICommand PasteCommand { get { return this._pasteCommand ?? (this._pasteCommand = new SimpleCommand(ExecuteEnable, ExecutePasteCommand)); } } private ICommand _cutCommand; public ICommand CutCommand { get { return this._cutCommand ?? (this._cutCommand = new SimpleCommand(ExecuteEnable, ExecuteCutCommand)); } } private ICommand _deleteCommand; public virtual ICommand DeleteCommand { get { return this._deleteCommand ?? (this._deleteCommand = new SimpleCommand(ExecuteEnable, ExecuteDeleteCommand)); } } private ICommand _leftMoveCommand; public ICommand LeftMoveCommand { get { return this._leftMoveCommand ?? (this._leftMoveCommand = new SimpleCommand(ExecuteEnable, ExecuteLeftMoveCommand)); } } private ICommand _rightMoveCommand; public ICommand RightMoveCommand { get { return this._rightMoveCommand ?? (this._rightMoveCommand = new SimpleCommand(ExecuteEnable, ExecuteRightMoveCommand)); } } private ICommand _upMoveCommand; public ICommand UpMoveCommand { get { return this._upMoveCommand ?? (this._upMoveCommand = new SimpleCommand(ExecuteEnable, ExecuteUpMoveCommand)); } } private ICommand _downMoveCommand; public ICommand DownMoveCommand { get { return this._downMoveCommand ?? (this._downMoveCommand = new SimpleCommand(ExecuteEnable, ExecuteDownMoveCommand)); } } private ICommand _centerMoveCommand; public ICommand CenterMoveCommand { get { return this._centerMoveCommand ?? (this._centerMoveCommand = new SimpleCommand(ExecuteEnable, ExecuteCenterMoveCommand)); } } private ICommand _sameSizeCommand; public ICommand SameSizeCommand { get { return this._sameSizeCommand ?? (this._sameSizeCommand = new SimpleCommand(ExecuteEnable, ExecuteSameSizeCommand)); } } private ICommand _sameWidthCommand; public ICommand SameWidthCommand { get { return this._sameWidthCommand ?? (this._sameWidthCommand = new SimpleCommand(ExecuteEnable, ExecuteSameWidthCommand)); } } private ICommand _sameHeightCommand; public ICommand SameHeightCommand { get { return this._sameHeightCommand ?? (this._sameHeightCommand = new SimpleCommand(ExecuteEnable, ExecuteSameHeightCommand)); } } private ICommand _sameAngleCommand; public ICommand SameAngleCommand { get { return this._sameAngleCommand ?? (this._sameAngleCommand = new SimpleCommand(ExecuteEnable, ExecuteSameAngleCommand)); } } private ICommand _fitAutoCommand; public ICommand FitAutoCommand { get { return this._fitAutoCommand ?? (this._fitAutoCommand = new SimpleCommand(ExecuteEnable, ExecuteFitAutoCommand)); } } private ICommand _fitWidthCommand; public ICommand FitWidthCommand { get { return this._fitWidthCommand ?? (this._fitWidthCommand = new SimpleCommand(ExecuteEnable, ExecuteFitWidthCommand)); } } private ICommand _fitHeightCommand; public ICommand FitHeightCommand { get { return this._fitHeightCommand ?? (this._fitHeightCommand = new SimpleCommand(ExecuteEnable, ExecuteFitHeightCommand)); } } private ICommand _groupCommand; public ICommand GroupCommand { get { return this._groupCommand ?? (this._groupCommand = new SimpleCommand(ExecuteEnable, ExecuteGroupCommand)); } } private ICommand _ungroupCommand; public ICommand UngroupCommand { get { return this._ungroupCommand ?? (this._ungroupCommand = new SimpleCommand(ExecuteEnable, ExecuteUngroupCommand)); } } private ICommand _lockCommand; public ICommand LockCommand { get { return this._lockCommand ?? (this._lockCommand = new SimpleCommand(ExecuteEnable, ExecuteLockCommand)); } } private ICommand _unlockCommand; public ICommand UnlockCommand { get { return this._unlockCommand ?? (this._unlockCommand = new SimpleCommand(ExecuteEnable, ExecuteUnlockCommand)); } } private ICommand _editCommand; public ICommand EditCommand { get { return this._editCommand ?? (this._editCommand = new SimpleCommand(ExecuteEnable, ExecuteEditCommand)); } } private ICommand _undoCommand; public ICommand UndoCommand { get { return this._undoCommand ?? (this._undoCommand = new SimpleCommand(Undo_Enabled, this.ExecutedUndoCommand)); } } private ICommand _redoCommand; public ICommand RedoCommand { get { return this._redoCommand ?? (this._redoCommand = new SimpleCommand(Redo_Enabled, this.ExecutedRedoCommand)); } } private ICommand _resetLayoutCommand; public ICommand ResetLayoutCommand { get { return this._resetLayoutCommand ?? (this._resetLayoutCommand = new SimpleCommand(ExecuteEnable, this.ExecutedResetLayoutCommand)); } } private ICommand _showSearchCommand; public ICommand ShowSearchCommand { get { return this._showSearchCommand ?? (this._showSearchCommand = new SimpleCommand(ExecuteEnable, this.ExecutedShowSearchCommand)); } } private ICommand _closeSearchCommand; public ICommand CloseSearchCommand { get { return this._closeSearchCommand ?? (this._closeSearchCommand = new SimpleCommand(ExecuteEnable, this.ExecutedCloseSearchCommand)); } } private ICommand _searchDownCommand; public ICommand SearchDownCommand { get { return this._searchDownCommand ?? (this._searchDownCommand = new SimpleCommand(ExecuteEnable, this.ExecutedSearchDownCommand)); } } private ICommand _searchUpCommand; public ICommand SearchUpCommand { get { return this._searchUpCommand ?? (this._searchUpCommand = new SimpleCommand(ExecuteEnable, this.ExecutedSearchUpCommand)); } } private ICommand _replaceCommand; public ICommand ReplaceCommand { get { return this._replaceCommand ?? (this._replaceCommand = new SimpleCommand(ExecuteEnable, this.ExecutedSearchReplaceCommand)); } } private ICommand _replaceAllCommand; public ICommand ReplaceAllCommand { get { return this._replaceAllCommand ?? (this._replaceAllCommand = new SimpleCommand(ExecuteEnable, this.ExecutedSearchReplaceAllCommand)); } } #endregion #region ctor和初始化 public DiagramViewModel() { Mediator.Instance.Register(this); Items.CollectionChanged += Items_CollectionChanged; var zoomValueChangedSubscription = WhenPropertyChanged.Where(o => o.ToString() == nameof(ZoomValue)).Throttle(TimeSpan.FromMilliseconds(100)).Subscribe(OnZoomValueChanged);//Sample this.PropertyChanged += DiagramViewModel_PropertyChanged; BuildMenuOptions(); } public DiagramViewModel(DiagramItem diagramItem) : this() { DiagramType = diagramItem.DiagramType; ShowGrid = diagramItem.ShowGrid; PhysicalGridCellSize = diagramItem.PhysicalGridCellSize; CellHorizontalAlignment = diagramItem.CellHorizontalAlignment; CellVerticalAlignment = diagramItem.CellVerticalAlignment; PageSizeOrientation = diagramItem.PageSizeOrientation; PhysicalPageSize = diagramItem.PhysicalPageSize; PageSizeType = diagramItem.PageSizeType; PhysicalGridMarginSize = diagramItem.PhysicalGridMarginSize; GridColor = diagramItem.GridColor; AllowDrop = diagramItem.AllowDrop; Init(true); } public virtual void Init(bool initNew) { DoCommandManager.Init(); } protected virtual void ExecutedResetLayoutCommand(object obj) { } #endregion #region 命令使能 public virtual bool ExecuteEnable(object para) { return IsReadOnly == false; } #endregion #region 菜单 private void BuildMenuOptions() { menuOptions = new ObservableCollection(); CinchMenuItem menuItem = new CinchMenuItem(); menuItem.Text = "居中"; menuItem.Command = CenterMoveCommand; menuItem.CommandParameter = this; menuOptions.Add(menuItem); } #endregion #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 void ExecutedUndoCommand(object para) { Undo(para); } private bool Undo(object para) { DoCommandManager.UnDo(); return true; } private void ExecutedRedoCommand(object para) { Redo(para); } private bool Redo(object para) { DoCommandManager.ReDo(); return true; } private bool Undo_Enabled(object para) { return DoCommandManager.CanUnDo; } private bool Redo_Enabled(object para) { return DoCommandManager.CanReDo; } #endregion #region 属性改变 protected virtual void DiagramViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e) { } private void Items_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) { if (e.OldItems != null) { foreach (var item in e.OldItems.OfType()) { item.PropertyChanged -= Item_PropertyChanged; item.Dispose(); } } if (e.NewItems != null) { foreach (var item in e.NewItems.OfType()) { item.PropertyChanged += Item_PropertyChanged; } } RaisePropertyChanged("Items"); } protected virtual void Item_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { RaisePropertyChanged(sender, e.PropertyName); if (e.PropertyName == "IsSelected") { RaisePropertyChanged(nameof(SelectedItem)); } var selectable = sender as SelectableViewModelBase; 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) { //加入ReDo DoCommandManager.DoNewCommand(sender.ToString() + e.PropertyName, () => { Do(sender, e.PropertyName, valuePropertyChangedEventArgs.NewValue); }, () => { UnDo(sender, e.PropertyName, valuePropertyChangedEventArgs.OldValue); }, null, false); Event?.Invoke(sender, new DiagramEventArgs(valuePropertyChangedEventArgs.PropertyName, valuePropertyChangedEventArgs.NewValue, valuePropertyChangedEventArgs.OldValue, selectable?.Id)); } } } //提供给标尺计算,延迟100ms,等布局改变再计算。 private void OnZoomValueChanged(string obj) { DelayZoomValue = ZoomValue; } #endregion [MediatorMessageSink("DoneDrawingMessage")] public void OnDoneDrawingMessage(bool dummy) { foreach (var item in Items.OfType()) { item.ShowConnectors = false; } } #region 新增,删除 protected virtual void ExecuteClearCommand(object parameter) { var items = this.Items.ToList(); DoCommandManager.DoNewCommand(this.ToString(), () => { this.Items.Clear(); }, () => { foreach (var item in items) { Add(item); } }); } private void ExecuteAddItemCommand(object parameter) { List newitems = new List(); if (parameter is SelectableDesignerItemViewModelBase ite) { newitems.Add(ite); } else if (parameter is IEnumerable items) { newitems.AddRange(items); } DoCommandManager.DoNewCommand(this.ToString(), () => { ClearSelectedItems(); Add(newitems, true); }, () => { foreach (var item in newitems) { Items.Remove(item); } }); } public bool AddVerify(SelectableDesignerItemViewModelBase item) { if (item.InitData() == false) return false; return true; } //使用程序添加对象,比如Demo初始化 public void Add(object parameter, bool? isSelected = false) { if (parameter is SelectableDesignerItemViewModelBase ite) { if (AddVerify(ite) != true) return; Add(ite, isSelected); } else if (parameter is IEnumerable items) { if (items.Select(p => AddVerify(p)).Any() != true) return; foreach (var item in items) { Add(item, isSelected); } } } private void Add(SelectableDesignerItemViewModelBase item, bool? isSelected = true) { item.Root = this; item.ZIndex = Items.Any() ? Items.Max(p => p.ZIndex) + 1 : 0; if (item.Id == Guid.Empty) { item.Id = Guid.NewGuid(); } var logical = item as LogicalGateItemViewModelBase; if (logical != null) { logical.OrderNumber = Items.OfType().Count() + 1; } var designerItemViewModelBase = item as DesignerItemViewModelBase; if (designerItemViewModelBase != null) { designerItemViewModelBase.SetCellAlignment(); } Items.Add(item); if (isSelected != null) { item.IsSelected = isSelected.Value; } } public void Remove(object parameter) { if (parameter is SelectableDesignerItemViewModelBase ite) { ite.IsSelected = false; ite.Dispose(); Items.Remove(ite); } else if (parameter is IEnumerable items) { foreach (var item in items) { item.IsSelected = false; item.Dispose(); Items.Remove(item); } } } private void ExecuteRemoveItemCommand(object parameter) { List olditems = new List(); if (parameter is SelectableDesignerItemViewModelBase node) { olditems.Add(node); } else if (parameter is IEnumerable para) { olditems.AddRange(para); } else { olditems.AddRange(SelectedItems); } if (olditems.Any()) { DoCommandManager.DoNewCommand(this.ToString(), () => { Remove(olditems); }, () => { Add(olditems); }); } } private void ExecuteClearSelectedItemsCommand(object parameter) { List selectedItems = new List(); if (parameter is SelectableDesignerItemViewModelBase node) { selectedItems.Add(node); } else if (parameter is IEnumerable para) { selectedItems.AddRange(para); } else { selectedItems.AddRange(SelectedItems); } if (selectedItems.Any()) { Dictionary infos = selectedItems.ToDictionary(p => p, p => p.IsSelected); DoCommandManager.DoNewCommand(this.ToString(), () => { foreach (var item in selectedItems) { item.IsSelected = false; } }, () => { foreach (var item in infos) { item.Key.IsSelected = item.Value; } }); } } public void ClearSelectedItems() { foreach (var item in this.SelectedItems.ToList()) { item.IsSelected = false; } } private void ExecuteSelectAllCommand(object parameter) { List selectedItems = Items.ToList(); if (selectedItems.Any()) { Dictionary infos = selectedItems.ToDictionary(p => p, p => p.IsSelected); DoCommandManager.DoNewCommand(this.ToString(), () => { foreach (var item in selectedItems) { item.IsSelected = true; } }, () => { foreach (var item in infos) { item.Key.IsSelected = item.Value; } }); } } private void ExecuteSelectInverseCommand(object parameter) { List selectedItems = new List(); if (parameter is SelectableDesignerItemViewModelBase node) { selectedItems.Add(node); } else if (parameter is IEnumerable para) { selectedItems.AddRange(para); } else { selectedItems.AddRange(Items); } if (selectedItems.Any()) { Dictionary infos = selectedItems.ToDictionary(p => p, p => p.IsSelected); DoCommandManager.DoNewCommand(this.ToString(), () => { foreach (var item in selectedItems) { item.IsSelected = !item.IsSelected; } }, () => { foreach (var item in infos) { item.Key.IsSelected = item.Value; } }); } } public void ExecuteSelectItemCommand(object parameter) { List selectedItems = new List(); if (parameter is SelectableDesignerItemViewModelBase node) { selectedItems.Add(node); } else if (parameter is IEnumerable para) { selectedItems.AddRange(para); } else { selectedItems.AddRange(Items); } if (selectedItems.Any()) { Dictionary infos = selectedItems.ToDictionary(p => p, p => p.IsSelected); DoCommandManager.DoNewCommand(this.ToString(), () => { ClearSelectedItems(); foreach (var item in selectedItems) { item.IsSelected = true; } }, () => { foreach (var item in infos) { item.Key.IsSelected = item.Value; } }); } } #endregion #region 复制,粘贴 private void ExecuteCopyCommand(object parameter) { Copy(parameter); } private List Copy(object parameter) { List selectedItems = new List(); if (parameter is SelectableDesignerItemViewModelBase node) { selectedItems.Add(node); } else if (parameter is IEnumerable para) { selectedItems.AddRange(para); } else { selectedItems.AddRange(SelectedItems); } if (selectedItems.Any()) { var selectedDesignerItems = selectedItems.OfType().ToList(); var selectedConnections = selectedItems.OfType().ToList(); foreach (ConnectionViewModel connection in Items.OfType()) { if (!selectedConnections.Contains(connection)) { DesignerItemViewModelBase sourceItem = selectedDesignerItems.FirstOrDefault(p => p.Id == connection.SourceConnectorInfo.DataItem.Id); DesignerItemViewModelBase sinkItem = selectedDesignerItems.FirstOrDefault(p => p.Id == connection.SinkConnectorInfoFully?.DataItem?.Id); if (sourceItem != null && sinkItem != null && BelongToSameGroup(sourceItem, sinkItem)) { selectedConnections.Add(connection); } } } string json = new SerializableObject { DesignerItems = selectedDesignerItems.Select(p => p.ToSerializableItem(".json")).Where(p => p != null).ToList(), Connections = selectedConnections.Select(p => p.ToSerializableItem(".json")).Where(p => p != null).ToList(), }.ToJson(); OffsetX = 0; OffsetY = 0; System.Windows.Clipboard.Clear(); System.Windows.Clipboard.SetData(System.Windows.DataFormats.Serializable, json); } return selectedItems; } private void ExecutePasteCommand(object parameter) { Paste(parameter); } protected virtual List Paste(object parameter, bool paste = true) { 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 null; List items = new List(); try { OffsetX += 10; OffsetY += 10; SerializableObject copyitem = JsonConvert.DeserializeObject(clipboardData); Dictionary mappingOldToNewIDs = new Dictionary(); foreach (var diagramItemData in copyitem.DesignerItems) { DesignerItemViewModelBase newItem = null; Type type = TypeHelper.GetType(diagramItemData.ModelTypeName); DesignerItemViewModelBase itemBase = Activator.CreateInstance(type, this, diagramItemData, ".json") as DesignerItemViewModelBase; 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); } } List connectors = new List(); foreach (var connection in copyitem.Connections) { var connectionItem = JsonConvert.DeserializeObject(connection.SerializableString); Guid newID = Guid.NewGuid(); mappingOldToNewIDs.Add(connectionItem.Id, newID); connectionItem.SourceId = mappingOldToNewIDs[connectionItem.SourceId]; connectionItem.SinkId = mappingOldToNewIDs[connectionItem.SinkId]; connectionItem.SourceType = TypeHelper.GetType(connectionItem.SourceTypeName); connectionItem.SinkType = TypeHelper.GetType(connectionItem.SinkTypeName); DesignerItemViewModelBase sourceItem = DiagramViewModelHelper.GetConnectorDataItem(items, connectionItem.SourceId, connectionItem.SourceType); ConnectorOrientation sourceConnectorOrientation = connectionItem.SourceOrientation; FullyCreatedConnectorInfo sourceConnectorInfo = sourceItem.GetFullConnectorInfo(connectionItem.Id, sourceConnectorOrientation, connectionItem.SourceXRatio, connectionItem.SourceYRatio, connectionItem.SourceInnerPoint, connectionItem.SourceIsPortless); DesignerItemViewModelBase sinkItem = DiagramViewModelHelper.GetConnectorDataItem(items, connectionItem.SinkId, connectionItem.SinkType); ConnectorOrientation sinkConnectorOrientation = connectionItem.SinkOrientation; FullyCreatedConnectorInfo sinkConnectorInfo = sinkItem.GetFullConnectorInfo(connectionItem.Id, sinkConnectorOrientation, connectionItem.SinkXRatio, connectionItem.SinkYRatio, connectionItem.SinkInnerPoint, connectionItem.SinkIsPortless); ConnectionViewModel connectionVM = new ConnectionViewModel(this, sourceConnectorInfo, sinkConnectorInfo, connectionItem); connectionVM.Id = Guid.NewGuid(); connectors.Add(connectionVM); } //修复父级的引用 foreach (var item in items) { if (item.ParentId != Guid.Empty) { if (mappingOldToNewIDs.ContainsKey(item.ParentId)) item.ParentId = mappingOldToNewIDs[item.ParentId]; } } items.AddRange(connectors); } catch (Exception e) { System.Windows.MessageBox.Show(e.StackTrace, e.Message, System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error); return null; } if (items.Any()) { if (paste) { DoCommandManager.DoNewCommand(this.ToString(), () => { ClearSelectedItems(); Add(items, true); FixOtherInfo(items); }, () => { foreach (var item in items) { Items.Remove(item); } }); } } return items; } else { return null; } } protected virtual void FixOtherInfo(List items) { } private bool ItemsToDeleteHasConnector(List itemsToRemove, ConnectorInfoBase connector) { if (connector is FullyCreatedConnectorInfo fully) { return itemsToRemove.Contains(fully.DataItem); } return false; } private void ExecuteCutCommand(object parameter) { Cut(parameter); } private List Cut(object parameter, bool cut = true) { if (Copy(null) == null) return null; var items = Delete(parameter, false); if (items.Any()) { if (cut) { DoCommandManager.DoNewCommand(this.ToString(), () => { foreach (var item in items) { Items.Remove(item); } }, () => { foreach (var item in items) { Items.Add(item); } }); } } return items; } protected void ExecuteDeleteCommand(object parameter) { var items = Delete(parameter, false); if (items.Any()) { DoCommandManager.DoNewCommand(this.ToString(), () => { foreach (var item in items) { Items.Remove(item); } }, () => { foreach (var item in items) { Items.Add(item); } }); } } protected virtual List Delete(object parameter, bool delete = true) { List itemsToRemove = new List(); if (parameter is SelectableDesignerItemViewModelBase node) { itemsToRemove.Add(node); } else if (parameter is IEnumerable para) { itemsToRemove.AddRange(para); } else { itemsToRemove.AddRange(SelectedItems); } List connectionsToAlsoRemove = new List(); foreach (var connector in Items.OfType()) { if (ItemsToDeleteHasConnector(itemsToRemove, connector.SourceConnectorInfo)) { connectionsToAlsoRemove.Add(connector); } if (ItemsToDeleteHasConnector(itemsToRemove, connector.SinkConnectorInfo)) { connectionsToAlsoRemove.Add(connector); } } itemsToRemove.AddRange(connectionsToAlsoRemove); if (itemsToRemove.Any()) { if (delete) { foreach (var item in itemsToRemove) { Items.Remove(item); } } } return itemsToRemove; } #endregion #region 布局 private void ExecuteAlignTopCommand(object parameter) { List selectedItems = new List(); if (parameter is DesignerItemViewModelBase node) { selectedItems.Add(node); } else if (parameter is IEnumerable para) { selectedItems.AddRange(para); } else { selectedItems.AddRange(SelectedItems.OfType()); } if (selectedItems.Any()) { Dictionary infos = selectedItems.ToDictionary(p => p, p => p.Top); DoCommandManager.DoNewCommand(this.ToString(), () => { double top = selectedItems.OrderBy(p => p.Top).Select(p => p.Top).FirstOrDefault(); foreach (DesignerItemViewModelBase item in selectedItems) { item.Top = top; } }, () => { foreach (var item in infos) { item.Key.Top = item.Value; } }); } } private void ExecuteAlignVerticalCentersCommand(object parameter) { List selectedItems = new List(); if (parameter is DesignerItemViewModelBase node) { selectedItems.Add(node); } else if (parameter is IEnumerable para) { selectedItems.AddRange(para); } else { selectedItems.AddRange(SelectedItems.OfType()); } if (selectedItems.Any()) { Dictionary infos = selectedItems.ToDictionary(p => p, p => p.Top); DoCommandManager.DoNewCommand(this.ToString(), () => { double mid = selectedItems.Select(p => p.Top + p.ItemHeight / 2).Average(); foreach (DesignerItemViewModelBase item in selectedItems) { item.Top = mid - item.ItemHeight / 2; } }, () => { foreach (var item in infos) { item.Key.Top = item.Value; } }); } } private void ExecuteAlignBottomCommand(object parameter) { List selectedItems = new List(); if (parameter is DesignerItemViewModelBase node) { selectedItems.Add(node); } else if (parameter is IEnumerable para) { selectedItems.AddRange(para); } else { selectedItems.AddRange(SelectedItems.OfType()); } if (selectedItems.Any()) { Dictionary infos = selectedItems.ToDictionary(p => p, p => p.Top); 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.Top = top - item.ItemHeight; } }, () => { foreach (var item in infos) { item.Key.Top = item.Value; } }); } } private void ExecuteAlignLeftCommand(object parameter) { List selectedItems = new List(); if (parameter is DesignerItemViewModelBase node) { selectedItems.Add(node); } else if (parameter is IEnumerable para) { selectedItems.AddRange(para); } else { selectedItems.AddRange(SelectedItems.OfType()); } if (selectedItems.Any()) { Dictionary infos = selectedItems.ToDictionary(p => p, p => p.Left); DoCommandManager.DoNewCommand(this.ToString(), () => { double left = selectedItems.OrderBy(p => p.Left).Select(p => p.Left).FirstOrDefault(); foreach (DesignerItemViewModelBase item in selectedItems) { item.Left = left; } }, () => { foreach (var item in infos) { item.Key.Left = item.Value; } }); } } private void ExecuteAlignHorizontalCentersCommand(object parameter) { List selectedItems = new List(); if (parameter is DesignerItemViewModelBase node) { selectedItems.Add(node); } else if (parameter is IEnumerable para) { selectedItems.AddRange(para); } else { selectedItems.AddRange(SelectedItems.OfType()); } if (selectedItems.Any()) { Dictionary infos = selectedItems.ToDictionary(p => p, p => p.Left); DoCommandManager.DoNewCommand(this.ToString(), () => { double mid = selectedItems.Select(p => p.Left + p.ItemWidth / 2).Average(); foreach (DesignerItemViewModelBase item in selectedItems) { item.Left = mid - item.ItemWidth / 2; } }, () => { foreach (var item in infos) { item.Key.Left = item.Value; } }); } } private void ExecuteAlignRightCommand(object parameter) { List selectedItems = new List(); if (parameter is DesignerItemViewModelBase node) { selectedItems.Add(node); } else if (parameter is IEnumerable para) { selectedItems.AddRange(para); } else { selectedItems.AddRange(SelectedItems.OfType()); } if (selectedItems.Any()) { Dictionary infos = selectedItems.ToDictionary(p => p, p => p.Left); 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.Left = right - item.ItemWidth; } }, () => { foreach (var item in infos) { item.Key.Left = item.Value; } }); } } private void ExecuteBringForwardCommand(object parameter) { List ordered = new List(); if (parameter is SelectableDesignerItemViewModelBase node) { ordered.Add(node); } else if (parameter is IEnumerable para) { ordered.AddRange(para.OrderByDescending(p => p.ZIndex)); } else { ordered.AddRange(SelectedItems.OrderByDescending(p => p.ZIndex)); } if (ordered.Any()) { Dictionary infos = ordered.ToDictionary(p => p, p => p.ZIndex); 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.ZIndex = newIndex; IEnumerable it = this.Items.Where(p => p.ZIndex == newIndex); foreach (var elm in it) { if (elm != item) { elm.ZIndex = currentIndex; break; } } } } }, () => { foreach (var item in infos) { item.Key.ZIndex = item.Value; } }); } } private void ExecuteBringToFrontCommand(object parameter) { List selectionSorted = new List(); if (parameter is SelectableDesignerItemViewModelBase node) { selectionSorted.Add(node); } else if (parameter is IEnumerable para) { selectionSorted.AddRange(para.OrderByDescending(p => p.ZIndex)); } else { selectionSorted.AddRange(SelectedItems.OrderByDescending(p => p.ZIndex)); } if (selectionSorted.Any()) { List childrenSorted = Items.OrderByDescending(p => p.ZIndex).ToList(); Dictionary infos = selectionSorted.ToDictionary(p => p, p => p.ZIndex); DoCommandManager.DoNewCommand(this.ToString(), () => { int i = childrenSorted.Count - 1; int j = childrenSorted.Count - selectionSorted.Count - 1; foreach (SelectableDesignerItemViewModelBase item in childrenSorted) { if (selectionSorted.Contains(item)) { item.ZIndex = i--; } else { item.ZIndex = j--; } } }, () => { foreach (var item in infos) { item.Key.ZIndex = item.Value; } }); } } private void ExecuteSendBackwardCommand(object parameter) { List ordered = new List(); if (parameter is SelectableDesignerItemViewModelBase node) { ordered.Add(node); } else if (parameter is IEnumerable para) { ordered.AddRange(para.OrderBy(p => p.ZIndex)); } else { ordered.AddRange(SelectedItems.OrderBy(p => p.ZIndex)); } if (ordered.Any()) { Dictionary infos = ordered.ToDictionary(p => p, p => p.ZIndex); 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.ZIndex = newIndex; IEnumerable it = this.Items.Where(p => p.ZIndex == newIndex); foreach (var elm in it) { if (elm != ordered[i]) { elm.ZIndex = currentIndex; break; } } } } }, () => { foreach (var item in infos) { item.Key.ZIndex = item.Value; } }); } } private void ExecuteSendToBackCommand(object parameter) { List selectionSorted = new List(); if (parameter is SelectableDesignerItemViewModelBase node) { selectionSorted.Add(node); } else if (parameter is IEnumerable para) { selectionSorted.AddRange(para.OrderByDescending(p => p.ZIndex)); } else { selectionSorted.AddRange(SelectedItems.OrderByDescending(p => p.ZIndex)); } if (selectionSorted.Any()) { List childrenSorted = Items.OrderByDescending(p => p.ZIndex).ToList(); Dictionary infos = selectionSorted.ToDictionary(p => p, p => p.ZIndex); DoCommandManager.DoNewCommand(this.ToString(), () => { int i = childrenSorted.Count - 1; int j = selectionSorted.Count - 1; foreach (SelectableDesignerItemViewModelBase item in childrenSorted) { if (selectionSorted.Contains(item)) { item.ZIndex = j--; } else { item.ZIndex = i--; } } }, () => { foreach (var item in infos) { item.Key.ZIndex = item.Value; } }); } } private void ExecuteDistributeHorizontalCommand(object parameter) { List selectedItems = new List(); if (parameter is DesignerItemViewModelBase node) { selectedItems.Add(node); } else if (parameter is IEnumerable para) { selectedItems.AddRange(para); } else { selectedItems.AddRange(SelectedItems.OfType()); } if (selectedItems.Count > 1) { Dictionary infos = selectedItems.ToDictionary(p => p, p => p.Left); 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.Left += delta; } offset = offset + item.ItemWidth + distance; } }, () => { foreach (var item in infos) { item.Key.Left = item.Value; } }); } } private void ExecuteDistributeVerticalCommand(object parameter) { List selectedItems = new List(); if (parameter is DesignerItemViewModelBase node) { selectedItems.Add(node); } else if (parameter is IEnumerable para) { selectedItems.AddRange(para); } else { selectedItems.AddRange(SelectedItems.OfType()); } if (selectedItems.Count > 1) { Dictionary infos = selectedItems.ToDictionary(p => p, p => p.Top); 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.Top += +delta; } offset = offset + item.ItemHeight + distance; } }, () => { foreach (var item in infos) { item.Key.Top = item.Value; } }); } } #endregion #region 移动 private void ExecuteLeftMoveCommand(object parameter) { List selectedItems = new List(); if (parameter is DesignerItemViewModelBase node) { selectedItems.Add(node); } else if (parameter is IEnumerable para) { selectedItems.AddRange(para); } else { selectedItems.AddRange(SelectedItems.OfType()); } if (selectedItems.Any()) { Dictionary infos = selectedItems.ToDictionary(p => p, p => p.Left); DoCommandManager.DoNewCommand(this.ToString(), () => { foreach (var item in selectedItems) { item.Left -= 0.5; } }, () => { foreach (var item in infos) { item.Key.Left = item.Value; } }); } } private void ExecuteRightMoveCommand(object parameter) { List selectedItems = new List(); if (parameter is DesignerItemViewModelBase node) { selectedItems.Add(node); } else if (parameter is IEnumerable para) { selectedItems.AddRange(para); } else { selectedItems.AddRange(SelectedItems.OfType()); } if (selectedItems.Any()) { Dictionary infos = selectedItems.ToDictionary(p => p, p => p.Left); DoCommandManager.DoNewCommand(this.ToString(), () => { foreach (var item in selectedItems) { item.Left += 0.5; } }, () => { foreach (var item in infos) { item.Key.Left = item.Value; } }); } } private void ExecuteUpMoveCommand(object parameter) { IEnumerable selectedItems; if (parameter is IEnumerable para) { selectedItems = para; } else { selectedItems = this.SelectedItems.OfType(); } foreach (var item in selectedItems.OfType()) { item.Top -= 0.5; } } private void ExecuteDownMoveCommand(object parameter) { List selectedItems = new List(); if (parameter is DesignerItemViewModelBase node) { selectedItems.Add(node); } else if (parameter is IEnumerable para) { selectedItems.AddRange(para); } else { selectedItems.AddRange(SelectedItems.OfType()); } if (selectedItems.Any()) { Dictionary infos = selectedItems.ToDictionary(p => p, p => p.Top); DoCommandManager.DoNewCommand(this.ToString(), () => { foreach (var item in selectedItems.OfType()) { item.Top += 0.5; } }, () => { foreach (var item in infos) { item.Key.Top = item.Value; } }); } } protected virtual void ExecuteCenterMoveCommand(object parameter) { List selectedItems = new List(); if (parameter is DesignerItemViewModelBase node) { selectedItems.Add(node); } else if (parameter is IEnumerable para) { selectedItems.AddRange(para); } else { selectedItems.AddRange(SelectedItems.OfType()); } if (selectedItems.Any()) { Dictionary infos = selectedItems.ToDictionary(p => p, p => p.TopLeft); DoCommandManager.DoNewCommand(this.ToString(), () => { var BoundingRect = DiagramViewModelHelper.GetBoundingRectangle(selectedItems); var oldcenter = BoundingRect.Center; foreach (var item in selectedItems.OfType()) { item.Left = item.Left - oldcenter.X + PageSize.Width / 2; item.Top = item.Top - oldcenter.Y + PageSize.Height / 2; } FitViewModel = new FitViewModel() { BoundingRect = DiagramViewModelHelper.GetBoundingRectangle(selectedItems) }; }, () => { foreach (var item in infos) { item.Key.TopLeft = item.Value; } FitViewModel = new FitViewModel() { BoundingRect = DiagramViewModelHelper.GetBoundingRectangle(selectedItems) }; }); } } protected void UpdateZIndex() { List ordered = Items.OrderBy(p => p.ZIndex).ToList(); for (int i = 0; i < ordered.Count; i++) { ordered[i].ZIndex = i; } } #endregion #region 大小 private void ExecuteSameSizeCommand(object parameter) { List selectedItems = new List(); if (parameter is DesignerItemViewModelBase node) { selectedItems.Add(node); } else if (parameter is IEnumerable para) { selectedItems.AddRange(para); } else { selectedItems.AddRange(SelectedItems.OfType()); } if (selectedItems.Count > 1) { Dictionary infos = selectedItems.ToDictionary(p => p, p => p.Size); DoCommandManager.DoNewCommand(this.ToString(), () => { foreach (var item in selectedItems) { item.ItemWidth = selectedItems.FirstOrDefault().ItemWidth; item.ItemHeight = selectedItems.FirstOrDefault().ItemHeight; } }, () => { foreach (var item in infos) { item.Key.Size = item.Value; } }); } } private void ExecuteSameWidthCommand(object parameter) { List selectedItems = new List(); if (parameter is DesignerItemViewModelBase node) { selectedItems.Add(node); } else if (parameter is IEnumerable para) { selectedItems.AddRange(para); } else { selectedItems.AddRange(SelectedItems.OfType()); } if (selectedItems.Count > 1) { Dictionary infos = selectedItems.ToDictionary(p => p, p => p.ItemWidth); DoCommandManager.DoNewCommand(this.ToString(), () => { foreach (var item in selectedItems) { item.ItemWidth = selectedItems.FirstOrDefault().ItemWidth; } }, () => { foreach (var item in infos) { item.Key.ItemWidth = item.Value; } }); } } private void ExecuteSameHeightCommand(object parameter) { List selectedItems = new List(); if (parameter is DesignerItemViewModelBase node) { selectedItems.Add(node); } else if (parameter is IEnumerable para) { selectedItems.AddRange(para); } else { selectedItems.AddRange(SelectedItems.OfType()); } if (selectedItems.Count > 1) { Dictionary infos = selectedItems.ToDictionary(p => p, p => p.ItemHeight); DoCommandManager.DoNewCommand(this.ToString(), () => { foreach (var item in selectedItems) { item.ItemHeight = selectedItems.FirstOrDefault().ItemHeight; } }, () => { foreach (var item in infos) { item.Key.ItemHeight = item.Value; } }); } } private void ExecuteSameAngleCommand(object parameter) { List selectedItems = new List(); if (parameter is DesignerItemViewModelBase node) { selectedItems.Add(node); } else if (parameter is IEnumerable para) { selectedItems.AddRange(para); } else { selectedItems.AddRange(SelectedItems.OfType()); } if (selectedItems.Count > 1) { Dictionary infos = selectedItems.ToDictionary(p => p, p => p.Angle); DoCommandManager.DoNewCommand(this.ToString(), () => { foreach (var item in selectedItems) { item.Angle = selectedItems.FirstOrDefault().Angle; } }, () => { foreach (var item in infos) { item.Key.Angle = item.Value; } }); } } #endregion #region 适应大小 private void ExecuteFitAutoCommand(object parameter) { if (Items.Any()) { FitViewModel = new FitViewModel() { BoundingRect = DiagramViewModelHelper.GetBoundingRectangle(Items.OfType()), FitMode = FitMode.FitAuto }; } } private void ExecuteFitWidthCommand(object parameter) { if (Items.Any()) { FitViewModel = new FitViewModel() { BoundingRect = DiagramViewModelHelper.GetBoundingRectangle(Items.OfType()), FitMode = FitMode.FitWidth }; } } private void ExecuteFitHeightCommand(object parameter) { if (Items.Any()) { FitViewModel = new FitViewModel() { BoundingRect = DiagramViewModelHelper.GetBoundingRectangle(Items.OfType()), FitMode = FitMode.FitHeight }; } } #endregion #region 分组 private void ExecuteGroupCommand(object parameter) { List items; GroupDesignerItemViewModel groupItem = null; if (parameter is IEnumerable para) { if (para.FirstOrDefault() is GroupDesignerItemViewModel groupDesignerItemViewModel) { groupItem = groupDesignerItemViewModel; items = para.Skip(1).ToList(); } else { items = para.ToList(); } } else { items = SelectedItems?.OfType().Where(p => p.ParentId == Guid.Empty).ToList(); } RectangleBase rect = DiagramViewModelHelper.GetBoundingRectangle(items); if (groupItem == null) { groupItem = new GroupDesignerItemViewModel(); } DoCommandManager.DoNewCommand(this.ToString(), () => { Add(groupItem); foreach (DesignerItemViewModelBase item in items) item.ParentId = groupItem.Id; groupItem.Resize(); ClearSelectedItems(); SelectionService.AddToSelection(groupItem); }, () => { Remove(groupItem); foreach (DesignerItemViewModelBase item in items) { item.IsSelected = true; item.ParentId = Guid.Empty; } }); } private void ExecuteUngroupCommand(object parameter) { List groups; if (parameter is IEnumerable para) { groups = para.Where(p => p.IsGroup && p.ParentId == Guid.Empty).ToList(); } else { groups = SelectedItems?.OfType().Where(p => p.IsGroup && p.ParentId == Guid.Empty).ToList(); } Dictionary> items = new Dictionary>(); foreach (DesignerItemViewModelBase groupRoot in groups) { var children = SelectedItems.OfType().Where(p => p.ParentId == groupRoot.Id); foreach (DesignerItemViewModelBase child in children) items.Add(child, new Tuple(child.ParentId, child.ZIndex)); } DoCommandManager.DoNewCommand(this.ToString(), () => { foreach (DesignerItemViewModelBase groupRoot in groups) { Remove(groupRoot); } foreach (var item in items) { item.Key.ParentId = Guid.Empty; } UpdateZIndex(); }, () => { foreach (DesignerItemViewModelBase groupRoot in groups) { Add(groupRoot); } foreach (var item in items) { item.Key.ParentId = item.Value.Item1; item.Key.ZIndex = item.Value.Item2; } }); } private bool BelongToSameGroup(IGroupable item1, IGroupable item2) { IGroupable root1 = SelectionService.GetGroupRoot(item1); IGroupable root2 = SelectionService.GetGroupRoot(item2); return (root1.Id == root2.Id); } #endregion #region 设置属性 public void SetPropertyValue(SelectableDesignerItemViewModelBase selectable, string propertyName, List items) { if (items.Any()) { Dictionary infos = items.ToDictionary(p => p, p => p.GetPropertyValue(propertyName)); DoCommandManager.DoNewCommand(this.ToString(), () => { var value = selectable.GetPropertyValue(propertyName); foreach (var item in items) { item.SetPropertyValue(propertyName, value); } }, () => { foreach (var item in infos) { item.Key.SetPropertyValue(propertyName, item.Value); } }); } } public void SetFont(IFontViewModel fontViewModel, string propertyName, List items) { if (items.Any()) { Dictionary infos = items.ToDictionary(p => p, p => p.FontViewModel.GetPropertyValue(propertyName)); DoCommandManager.DoNewCommand(this.ToString(), () => { var value = fontViewModel.GetPropertyValue(propertyName); foreach (var item in items) { item.FontViewModel.SetPropertyValue(propertyName, value); } }, () => { foreach (var item in infos) { item.Key.FontViewModel.SetPropertyValue(propertyName, item.Value); } }); } } public void SetColor(IColorViewModel colorViewModel, string propertyName, List items) { if (items.Any()) { Dictionary infos = items.ToDictionary(p => p, p => p.ColorViewModel.GetPropertyValue(propertyName)); DoCommandManager.DoNewCommand(this.ToString(), () => { var value = colorViewModel.GetPropertyValue(propertyName); foreach (var item in items) { item.ColorViewModel.SetPropertyValue(propertyName, value); } }, () => { foreach (var item in infos) { item.Key.ColorViewModel.SetPropertyValue(propertyName, item.Value); } }); } } public void SetSharp(IShapeViewModel shapeViewModel, string propertyName, List items) { if (items.Any()) { Dictionary infos = items.ToDictionary(p => p, p => p.ShapeViewModel.GetPropertyValue(propertyName)); DoCommandManager.DoNewCommand(this.ToString(), () => { var value = shapeViewModel.GetPropertyValue(propertyName); foreach (var item in items) { item.ShapeViewModel.SetPropertyValue(propertyName, value); } }, () => { foreach (var item in infos) { item.Key.ShapeViewModel.SetPropertyValue(propertyName, item.Value); } }); } } public void SetAnimation(IAnimationViewModel animationViewModel, string propertyName, List items) { if (items.Any()) { Dictionary infos = items.ToDictionary(p => p, p => p.AnimationViewModel.GetPropertyValue(propertyName)); DoCommandManager.DoNewCommand(this.ToString(), () => { var value = animationViewModel.GetPropertyValue(propertyName); foreach (var item in items) { item.AnimationViewModel.SetPropertyValue(propertyName, value); } }, () => { foreach (var item in infos) { item.Key.AnimationViewModel.SetPropertyValue(propertyName, item.Value); } }); } } public void SetQuickItem(IQuickThemeViewModel quickThemeViewModel, string propertyName, List items) { if (propertyName == nameof(QuickTheme) && quickThemeViewModel.QuickTheme != null) { if (items.Any()) { Dictionary> infos = items.ToDictionary(p => p, p => new Tuple( p.FontViewModel.GetPropertyValue("Color"), p.ColorViewModel.GetPropertyValue("FillColor"), p.ColorViewModel.GetPropertyValue("LineColor"), p.ColorViewModel.GetPropertyValue("LineWidth"))); DoCommandManager.DoNewCommand(this.ToString(), () => { var value1 = quickThemeViewModel.QuickTheme.FontViewModel.GetPropertyValue("Color"); var value2 = quickThemeViewModel.QuickTheme.ColorViewModel.GetPropertyValue("FillColor"); var value3 = quickThemeViewModel.QuickTheme.ColorViewModel.GetPropertyValue("LineColor"); var value4 = quickThemeViewModel.QuickTheme.ColorViewModel.GetPropertyValue("LineWidth"); foreach (var item in items) { item.FontViewModel.SetPropertyValue("Color", value1); item.ColorViewModel.SetPropertyValue("FillColor", value2); item.ColorViewModel.SetPropertyValue("LineColor", value3); item.ColorViewModel.SetPropertyValue("LineWidth", value4); } }, () => { foreach (var item in infos) { item.Key.FontViewModel.SetPropertyValue("Color", item.Value.Item1); item.Key.ColorViewModel.SetPropertyValue("FillColor", item.Value.Item2); item.Key.ColorViewModel.SetPropertyValue("LineColor", item.Value.Item3); item.Key.ColorViewModel.SetPropertyValue("LineWidth", item.Value.Item4); } }); } quickThemeViewModel.QuickTheme = null; } } public void LockAction(LockObject lockObject, string propertyName, List items) { foreach (var item in items) { item.LockObjectViewModel.SetValue(lockObject); } } #endregion #region 快捷键操作 public bool ExecuteShortcut(KeyEventArgs e) { if (SelectedItem?.IsEditing == true) { return false; } if (DiagramOption.ShortcutOption.SelectAll(e)) { SelectAllCommand.Execute(null); return true; } else if (DiagramOption.ShortcutOption.Copy(e)) { CopyCommand.Execute(null); return true; } else if (DiagramOption.ShortcutOption.Paste(e)) { PasteCommand.Execute(null); return true; } else if (DiagramOption.ShortcutOption.Cut(e)) { CutCommand.Execute(null); return true; } else if (DiagramOption.ShortcutOption.Undo(e)) { UndoCommand.Execute(null); return true; } else if (DiagramOption.ShortcutOption.Redo(e)) { RedoCommand.Execute(null); return true; } else if (DiagramOption.ShortcutOption.Delete(e)) { DeleteCommand.Execute(null); return true; } else if (DiagramOption.ShortcutOption.LeftMove(e)) { LeftMoveCommand.Execute(null); return true; } else if (DiagramOption.ShortcutOption.RightMove(e)) { RightMoveCommand.Execute(null); return true; } else if (DiagramOption.ShortcutOption.UpMove(e)) { UpMoveCommand.Execute(null); return true; } else if (DiagramOption.ShortcutOption.DownMove(e)) { DownMoveCommand.Execute(null); return true; } else if (DiagramOption.ShortcutOption.Group(e)) { GroupCommand.Execute(null); return true; } else if (DiagramOption.ShortcutOption.Ungroup(e)) { UngroupCommand.Execute(null); return true; } else if (DiagramOption.ShortcutOption.Search(e)) { ShowSearchCommand.Execute(null); return true; } else if (DiagramOption.ShortcutOption.SearchDown(e)) { SearchDownCommand.Execute(SearchText); return true; } else if (DiagramOption.ShortcutOption.SearchUp(e)) { SearchUpCommand.Execute(SearchText); return true; } else if (DiagramOption.ShortcutOption.Replace(e)) { ReplaceCommand.Execute(new object[] { SearchText, ReplaceText }); return true; } else if (DiagramOption.ShortcutOption.ReplaceAll(e)) { ReplaceAllCommand.Execute(new object[] { SearchText, ReplaceText }); return true; } return false; } #endregion #region 锁定与解锁,待完善 private void ExecuteLockCommand(object parameter) { } private void ExecuteUnlockCommand(object parameter) { } #endregion #region 搜索与编辑 protected virtual void ExecuteEditCommand(object parameter) { if (parameter is SelectableDesignerItemViewModelBase designerItem) { designerItem.ShowText = true; } else { if (SelectedItem != null) SelectedItem.ShowText = true; } } private void ExecutedShowSearchCommand(object parameter) { ShowSearch = true; } private void ExecutedCloseSearchCommand(object parameter) { ShowSearch = false; } private void ExecutedSearchUpCommand(object obj) { if (obj != null) { var selecteddesign = SelectedItem as SelectableDesignerItemViewModelBase; var searchitems = Items.OfType().Where(p => SearchMatch(p.Text, obj.ToString()) == true).ToList(); if (searchitems.Count > 0) { int selectindex = 0; if (selecteddesign != null) { int index = searchitems.IndexOf(selecteddesign); if (index == -1) { selectindex = 0; } else if (index - 1 >= 0) { selectindex = index - 1; } else { selectindex = searchitems.Count - 1; } } SelectItemCommand.Execute(searchitems[selectindex]); SearchInfo = $"第{selectindex + 1}条,共{searchitems.Count}条"; FitViewModel = new FitViewModel() { BoundingRect = DiagramViewModelHelper.GetBoundingRectangle(SelectedItem as DesignerItemViewModelBase) }; } else { SearchInfo = "第0条,共0条"; } } else { SearchInfo = null; } } private void ExecutedSearchDownCommand(object obj) { if (!string.IsNullOrEmpty(obj?.ToString())) { var selecteddesign = SelectedItem as SelectableDesignerItemViewModelBase; var searchitems = Items.OfType().Where(p => SearchMatch(p.Text, obj.ToString()) == true).ToList(); if (searchitems.Count > 0) { int selectindex = 0; if (selecteddesign != null) { int index = searchitems.IndexOf(selecteddesign); if (index == -1) { selectindex = 0; } else if (index + 1 < searchitems.Count) { selectindex = index + 1; } else { selectindex = 0; } } SelectItemCommand.Execute(searchitems[selectindex]); SearchInfo = $"第{selectindex + 1}条,共{searchitems.Count}条"; FitViewModel = new FitViewModel() { BoundingRect = DiagramViewModelHelper.GetBoundingRectangle(SelectedItem as DesignerItemViewModelBase) }; } else { SearchInfo = "第0条,共0条"; } } else { SearchInfo = null; } } private bool SearchMatch(string input, string searchtext) { if (input == null || searchtext == null) return false; if (SearchCaseMatch == true && SearchWholeWordMatch == true) { return input == searchtext; } else if (SearchCaseMatch == true && SearchWholeWordMatch == false) { return input.Contains(searchtext); } else if (SearchCaseMatch == false && SearchWholeWordMatch == true) { return input.ToLower() == searchtext.ToLower(); } else { return input.ToLower().Contains(searchtext.ToLower()); } } private string ReplaceSearch(string input, string searchtext, string replcetext) { if (SearchCaseMatch == true) { return input.Replace(searchtext, replcetext); } else { return Regex.Replace(input, searchtext, replcetext, RegexOptions.IgnoreCase); } } private void ExecutedSearchReplaceCommand(object obj) { if (obj is object[] array && array.Length == 2) { var items = SelectedItems.Where(p => SearchMatch(p.Text, array[0]?.ToString()) == true).ToList(); Dictionary infos = items.ToDictionary(p => p, p => p.Text); DoCommandManager.DoNewCommand(this.ToString(), () => { foreach (var item in items) { item.Text = ReplaceSearch(item.Text, array[0]?.ToString(), array[1]?.ToString()); } }, () => { foreach (var item in infos) { item.Key.Text = item.Value; } }); } } private void ExecutedSearchReplaceAllCommand(object obj) { if (obj is object[] array && array.Length == 2) { var items = Items.Where(p => SearchMatch(p.Text, array[0]?.ToString()) == true).ToList(); Dictionary infos = items.ToDictionary(p => p, p => p.Text); DoCommandManager.DoNewCommand(this.ToString(), () => { foreach (var item in items) { item.Text = ReplaceSearch(item.Text, array[0]?.ToString(), array[1]?.ToString()); } }, () => { foreach (var item in infos) { item.Key.Text = item.Value; } }); } } #endregion } }