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;
using static System.Net.Mime.MediaTypeNames;

namespace AIStudio.Wpf.DiagramDesigner
{
    public class DiagramViewModel : BindableBase, IDiagramViewModel
    {
        #region 属性
        public ObservableCollection<SelectableDesignerItemViewModelBase> Items { get; set; } = new ObservableCollection<SelectableDesignerItemViewModelBase>();
        public List<SelectableDesignerItemViewModelBase> 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<CinchMenuItem> menuOptions;
        public IEnumerable<CinchMenuItem> 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 _nextCommand;
        public ICommand NextCommand
        {
            get
            {
                return this._nextCommand ?? (this._nextCommand = new SimpleCommand(ExecuteEnable, ExecuteNextCommand));
            }
        }

        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>();
            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<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");
        }

        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<DesignerItemViewModelBase>())
            {
                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<SelectableDesignerItemViewModelBase> newitems = new List<SelectableDesignerItemViewModelBase>();
            if (parameter is SelectableDesignerItemViewModelBase ite)
            {
                newitems.Add(ite);
            }
            else if (parameter is IEnumerable<SelectableDesignerItemViewModelBase> 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.Verify() == 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<SelectableDesignerItemViewModelBase> 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<LogicalGateItemViewModelBase>().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<SelectableDesignerItemViewModelBase> items)
            {
                foreach (var item in items)
                {
                    item.IsSelected = false;
                    item.Dispose();
                    Items.Remove(item);
                }
            }
        }

        private void ExecuteRemoveItemCommand(object parameter)
        {
            List<SelectableDesignerItemViewModelBase> olditems = new List<SelectableDesignerItemViewModelBase>();
            if (parameter is SelectableDesignerItemViewModelBase node)
            {
                olditems.Add(node);
            }
            else if (parameter is IEnumerable<SelectableDesignerItemViewModelBase> 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<SelectableDesignerItemViewModelBase> selectedItems = new List<SelectableDesignerItemViewModelBase>();
            if (parameter is SelectableDesignerItemViewModelBase node)
            {
                selectedItems.Add(node);
            }
            else if (parameter is IEnumerable<SelectableDesignerItemViewModelBase> para)
            {
                selectedItems.AddRange(para);
            }
            else
            {
                selectedItems.AddRange(SelectedItems);
            }

            if (selectedItems.Any())
            {
                Dictionary<SelectableDesignerItemViewModelBase, bool> 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;
            }
        }

        public virtual void ExecuteNextCommand(object parameter)
        {
        
        }

        private void ExecuteSelectAllCommand(object parameter)
        {
            List<SelectableDesignerItemViewModelBase> selectedItems = Items.ToList();
            if (selectedItems.Any())
            {
                Dictionary<SelectableDesignerItemViewModelBase, bool> 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<SelectableDesignerItemViewModelBase> selectedItems = new List<SelectableDesignerItemViewModelBase>();
            if (parameter is SelectableDesignerItemViewModelBase node)
            {
                selectedItems.Add(node);
            }
            else if (parameter is IEnumerable<SelectableDesignerItemViewModelBase> para)
            {
                selectedItems.AddRange(para);
            }
            else
            {
                selectedItems.AddRange(Items);
            }

            if (selectedItems.Any())
            {
                Dictionary<SelectableDesignerItemViewModelBase, bool> 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<SelectableDesignerItemViewModelBase> selectedItems = new List<SelectableDesignerItemViewModelBase>();
            if (parameter is SelectableDesignerItemViewModelBase node)
            {
                selectedItems.Add(node);
            }
            else if (parameter is IEnumerable<SelectableDesignerItemViewModelBase> para)
            {
                selectedItems.AddRange(para);
            }
            else
            {
                selectedItems.AddRange(Items);
            }

            if (selectedItems.Any())
            {
                Dictionary<SelectableDesignerItemViewModelBase, bool> 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<SelectableDesignerItemViewModelBase> Copy(object parameter)
        {
            List<SelectableDesignerItemViewModelBase> selectedItems = new List<SelectableDesignerItemViewModelBase>();
            if (parameter is SelectableDesignerItemViewModelBase node)
            {
                selectedItems.Add(node);
            }
            else if (parameter is IEnumerable<SelectableDesignerItemViewModelBase> para)
            {
                selectedItems.AddRange(para);
            }
            else
            {
                selectedItems.AddRange(SelectedItems);
            }

            if (selectedItems.Any())
            {
                var selectedDesignerItems = selectedItems.OfType<DesignerItemViewModelBase>().ToList();
                var selectedConnections = selectedItems.OfType<ConnectionViewModel>().ToList();

                foreach (ConnectionViewModel connection in Items.OfType<ConnectionViewModel>())
                {
                    if (!selectedConnections.Contains(connection))
                    {
                        DesignerItemViewModelBase sourceItem = selectedDesignerItems.FirstOrDefault(p => p.Id == connection.SourceConnectorInfoFully?.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<SelectableDesignerItemViewModelBase> 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<SelectableDesignerItemViewModelBase> items = new List<SelectableDesignerItemViewModelBase>();
                try
                {
                    OffsetX += 10;
                    OffsetY += 10;

                    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.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<SelectableDesignerItemViewModelBase> connectors = new List<SelectableDesignerItemViewModelBase>();
                    foreach (var connection in copyitem.Connections)
                    {
                        var connectionItem = JsonConvert.DeserializeObject<ConnectionItem>(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<SelectableDesignerItemViewModelBase> items)
        {

        }

        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)
        {
            Cut(parameter);
        }

        private List<SelectableDesignerItemViewModelBase> 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<SelectableDesignerItemViewModelBase> Delete(object parameter, bool delete = true)
        {
            List<SelectableDesignerItemViewModelBase> itemsToRemove = new List<SelectableDesignerItemViewModelBase>();
            if (parameter is SelectableDesignerItemViewModelBase node)
            {
                itemsToRemove.Add(node);
            }
            else if (parameter is IEnumerable<SelectableDesignerItemViewModelBase> para)
            {
                itemsToRemove.AddRange(para);
            }
            else
            {
                itemsToRemove.AddRange(SelectedItems);
            }

            List<SelectableDesignerItemViewModelBase> connectionsToAlsoRemove = new List<SelectableDesignerItemViewModelBase>();

            foreach (var connector in Items.OfType<ConnectionViewModel>())
            {
                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<DesignerItemViewModelBase> selectedItems = new List<DesignerItemViewModelBase>();
            if (parameter is DesignerItemViewModelBase node)
            {
                selectedItems.Add(node);
            }
            else if (parameter is IEnumerable<DesignerItemViewModelBase> para)
            {
                selectedItems.AddRange(para);
            }
            else
            {
                selectedItems.AddRange(SelectedItems.OfType<DesignerItemViewModelBase>());
            }

            if (selectedItems.Any())
            {
                Dictionary<DesignerItemViewModelBase, double> 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<DesignerItemViewModelBase> selectedItems = new List<DesignerItemViewModelBase>();
            if (parameter is DesignerItemViewModelBase node)
            {
                selectedItems.Add(node);
            }
            else if (parameter is IEnumerable<DesignerItemViewModelBase> para)
            {
                selectedItems.AddRange(para);
            }
            else
            {
                selectedItems.AddRange(SelectedItems.OfType<DesignerItemViewModelBase>());
            }

            if (selectedItems.Any())
            {
                Dictionary<DesignerItemViewModelBase, double> 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<DesignerItemViewModelBase> selectedItems = new List<DesignerItemViewModelBase>();
            if (parameter is DesignerItemViewModelBase node)
            {
                selectedItems.Add(node);
            }
            else if (parameter is IEnumerable<DesignerItemViewModelBase> para)
            {
                selectedItems.AddRange(para);
            }
            else
            {
                selectedItems.AddRange(SelectedItems.OfType<DesignerItemViewModelBase>());
            }

            if (selectedItems.Any())
            {
                Dictionary<DesignerItemViewModelBase, double> 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<DesignerItemViewModelBase> selectedItems = new List<DesignerItemViewModelBase>();
            if (parameter is DesignerItemViewModelBase node)
            {
                selectedItems.Add(node);
            }
            else if (parameter is IEnumerable<DesignerItemViewModelBase> para)
            {
                selectedItems.AddRange(para);
            }
            else
            {
                selectedItems.AddRange(SelectedItems.OfType<DesignerItemViewModelBase>());
            }

            if (selectedItems.Any())
            {
                Dictionary<DesignerItemViewModelBase, double> 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<DesignerItemViewModelBase> selectedItems = new List<DesignerItemViewModelBase>();
            if (parameter is DesignerItemViewModelBase node)
            {
                selectedItems.Add(node);
            }
            else if (parameter is IEnumerable<DesignerItemViewModelBase> para)
            {
                selectedItems.AddRange(para);
            }
            else
            {
                selectedItems.AddRange(SelectedItems.OfType<DesignerItemViewModelBase>());
            }

            if (selectedItems.Any())
            {
                Dictionary<DesignerItemViewModelBase, double> 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<DesignerItemViewModelBase> selectedItems = new List<DesignerItemViewModelBase>();
            if (parameter is DesignerItemViewModelBase node)
            {
                selectedItems.Add(node);
            }
            else if (parameter is IEnumerable<DesignerItemViewModelBase> para)
            {
                selectedItems.AddRange(para);
            }
            else
            {
                selectedItems.AddRange(SelectedItems.OfType<DesignerItemViewModelBase>());
            }

            if (selectedItems.Any())
            {
                Dictionary<DesignerItemViewModelBase, double> 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<SelectableDesignerItemViewModelBase> ordered = new List<SelectableDesignerItemViewModelBase>();
            if (parameter is SelectableDesignerItemViewModelBase node)
            {
                ordered.Add(node);
            }
            else if (parameter is IEnumerable<SelectableDesignerItemViewModelBase> para)
            {
                ordered.AddRange(para.OrderByDescending(p => p.ZIndex));
            }
            else
            {
                ordered.AddRange(SelectedItems.OrderByDescending(p => p.ZIndex));
            }

            if (ordered.Any())
            {
                Dictionary<SelectableDesignerItemViewModelBase, int> 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<SelectableDesignerItemViewModelBase> 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<SelectableDesignerItemViewModelBase> selectionSorted = new List<SelectableDesignerItemViewModelBase>();
            if (parameter is SelectableDesignerItemViewModelBase node)
            {
                selectionSorted.Add(node);
            }
            else if (parameter is IEnumerable<SelectableDesignerItemViewModelBase> para)
            {
                selectionSorted.AddRange(para.OrderByDescending(p => p.ZIndex));
            }
            else
            {
                selectionSorted.AddRange(SelectedItems.OrderByDescending(p => p.ZIndex));
            }

            if (selectionSorted.Any())
            {
                List<SelectableDesignerItemViewModelBase> childrenSorted = Items.OrderByDescending(p => p.ZIndex).ToList();
                Dictionary<SelectableDesignerItemViewModelBase, int> 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<SelectableDesignerItemViewModelBase> ordered = new List<SelectableDesignerItemViewModelBase>();
            if (parameter is SelectableDesignerItemViewModelBase node)
            {
                ordered.Add(node);
            }
            else if (parameter is IEnumerable<SelectableDesignerItemViewModelBase> para)
            {
                ordered.AddRange(para.OrderBy(p => p.ZIndex));
            }
            else
            {
                ordered.AddRange(SelectedItems.OrderBy(p => p.ZIndex));
            }

            if (ordered.Any())
            {
                Dictionary<SelectableDesignerItemViewModelBase, int> 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<SelectableDesignerItemViewModelBase> 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<SelectableDesignerItemViewModelBase> selectionSorted = new List<SelectableDesignerItemViewModelBase>();
            if (parameter is SelectableDesignerItemViewModelBase node)
            {
                selectionSorted.Add(node);
            }
            else if (parameter is IEnumerable<SelectableDesignerItemViewModelBase> para)
            {
                selectionSorted.AddRange(para.OrderByDescending(p => p.ZIndex));
            }
            else
            {
                selectionSorted.AddRange(SelectedItems.OrderByDescending(p => p.ZIndex));
            }

            if (selectionSorted.Any())
            {
                List<SelectableDesignerItemViewModelBase> childrenSorted = Items.OrderByDescending(p => p.ZIndex).ToList();
                Dictionary<SelectableDesignerItemViewModelBase, int> 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<DesignerItemViewModelBase> selectedItems = new List<DesignerItemViewModelBase>();
            if (parameter is DesignerItemViewModelBase node)
            {
                selectedItems.Add(node);
            }
            else if (parameter is IEnumerable<DesignerItemViewModelBase> para)
            {
                selectedItems.AddRange(para);
            }
            else
            {
                selectedItems.AddRange(SelectedItems.OfType<DesignerItemViewModelBase>());
            }

            if (selectedItems.Count > 1)
            {
                Dictionary<DesignerItemViewModelBase, double> 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<DesignerItemViewModelBase> selectedItems = new List<DesignerItemViewModelBase>();
            if (parameter is DesignerItemViewModelBase node)
            {
                selectedItems.Add(node);
            }
            else if (parameter is IEnumerable<DesignerItemViewModelBase> para)
            {
                selectedItems.AddRange(para);
            }
            else
            {
                selectedItems.AddRange(SelectedItems.OfType<DesignerItemViewModelBase>());
            }

            if (selectedItems.Count > 1)
            {
                Dictionary<DesignerItemViewModelBase, double> 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<DesignerItemViewModelBase> selectedItems = new List<DesignerItemViewModelBase>();
            if (parameter is DesignerItemViewModelBase node)
            {
                selectedItems.Add(node);
            }
            else if (parameter is IEnumerable<DesignerItemViewModelBase> para)
            {
                selectedItems.AddRange(para);
            }
            else
            {
                selectedItems.AddRange(SelectedItems.OfType<DesignerItemViewModelBase>());
            }

            if (selectedItems.Any())
            {
                Dictionary<DesignerItemViewModelBase, double> 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<DesignerItemViewModelBase> selectedItems = new List<DesignerItemViewModelBase>();
            if (parameter is DesignerItemViewModelBase node)
            {
                selectedItems.Add(node);
            }
            else if (parameter is IEnumerable<DesignerItemViewModelBase> para)
            {
                selectedItems.AddRange(para);
            }
            else
            {
                selectedItems.AddRange(SelectedItems.OfType<DesignerItemViewModelBase>());
            }

            if (selectedItems.Any())
            {
                Dictionary<DesignerItemViewModelBase, double> 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<DesignerItemViewModelBase> selectedItems;
            if (parameter is IEnumerable<DesignerItemViewModelBase> para)
            {
                selectedItems = para;
            }
            else
            {
                selectedItems = this.SelectedItems.OfType<DesignerItemViewModelBase>();
            }

            foreach (var item in selectedItems.OfType<DesignerItemViewModelBase>())
            {
                item.Top -= 0.5;
            }
        }

        private void ExecuteDownMoveCommand(object parameter)
        {
            List<DesignerItemViewModelBase> selectedItems = new List<DesignerItemViewModelBase>();
            if (parameter is DesignerItemViewModelBase node)
            {
                selectedItems.Add(node);
            }
            else if (parameter is IEnumerable<DesignerItemViewModelBase> para)
            {
                selectedItems.AddRange(para);
            }
            else
            {
                selectedItems.AddRange(SelectedItems.OfType<DesignerItemViewModelBase>());
            }

            if (selectedItems.Any())
            {
                Dictionary<DesignerItemViewModelBase, double> infos = selectedItems.ToDictionary(p => p, p => p.Top);

                DoCommandManager.DoNewCommand(this.ToString(),
                () => {
                    foreach (var item in selectedItems.OfType<DesignerItemViewModelBase>())
                    {
                        item.Top += 0.5;
                    }
                },
                () => {
                    foreach (var item in infos)
                    {
                        item.Key.Top = item.Value;
                    }
                });
            }
        }

        protected virtual void ExecuteCenterMoveCommand(object parameter)
        {
            List<DesignerItemViewModelBase> selectedItems = new List<DesignerItemViewModelBase>();
            if (parameter is DesignerItemViewModelBase node)
            {
                selectedItems.Add(node);
            }
            else if (parameter is IEnumerable<DesignerItemViewModelBase> para)
            {
                selectedItems.AddRange(para);
            }
            else
            {
                selectedItems.AddRange(SelectedItems.OfType<DesignerItemViewModelBase>());
            }

            if (selectedItems.Any())
            {
                Dictionary<DesignerItemViewModelBase, PointBase> 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<DesignerItemViewModelBase>())
                    {
                        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<SelectableDesignerItemViewModelBase> 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<DesignerItemViewModelBase> selectedItems = new List<DesignerItemViewModelBase>();
            if (parameter is DesignerItemViewModelBase node)
            {
                selectedItems.Add(node);
            }
            else if (parameter is IEnumerable<DesignerItemViewModelBase> para)
            {
                selectedItems.AddRange(para);
            }
            else
            {
                selectedItems.AddRange(SelectedItems.OfType<DesignerItemViewModelBase>());
            }

            if (selectedItems.Count > 1)
            {
                Dictionary<DesignerItemViewModelBase, SizeBase> 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<DesignerItemViewModelBase> selectedItems = new List<DesignerItemViewModelBase>();
            if (parameter is DesignerItemViewModelBase node)
            {
                selectedItems.Add(node);
            }
            else if (parameter is IEnumerable<DesignerItemViewModelBase> para)
            {
                selectedItems.AddRange(para);
            }
            else
            {
                selectedItems.AddRange(SelectedItems.OfType<DesignerItemViewModelBase>());
            }

            if (selectedItems.Count > 1)
            {
                Dictionary<DesignerItemViewModelBase, double> 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<DesignerItemViewModelBase> selectedItems = new List<DesignerItemViewModelBase>();
            if (parameter is DesignerItemViewModelBase node)
            {
                selectedItems.Add(node);
            }
            else if (parameter is IEnumerable<DesignerItemViewModelBase> para)
            {
                selectedItems.AddRange(para);
            }
            else
            {
                selectedItems.AddRange(SelectedItems.OfType<DesignerItemViewModelBase>());
            }

            if (selectedItems.Count > 1)
            {
                Dictionary<DesignerItemViewModelBase, double> 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<DesignerItemViewModelBase> selectedItems = new List<DesignerItemViewModelBase>();
            if (parameter is DesignerItemViewModelBase node)
            {
                selectedItems.Add(node);
            }
            else if (parameter is IEnumerable<DesignerItemViewModelBase> para)
            {
                selectedItems.AddRange(para);
            }
            else
            {
                selectedItems.AddRange(SelectedItems.OfType<DesignerItemViewModelBase>());
            }

            if (selectedItems.Count > 1)
            {
                Dictionary<DesignerItemViewModelBase, double> 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<DesignerItemViewModelBase>()), FitMode = FitMode.FitAuto };
            }
        }

        private void ExecuteFitWidthCommand(object parameter)
        {
            if (Items.Any())
            {
                FitViewModel = new FitViewModel() { BoundingRect = DiagramViewModelHelper.GetBoundingRectangle(Items.OfType<DesignerItemViewModelBase>()), FitMode = FitMode.FitWidth };
            }
        }

        private void ExecuteFitHeightCommand(object parameter)
        {
            if (Items.Any())
            {
                FitViewModel = new FitViewModel() { BoundingRect = DiagramViewModelHelper.GetBoundingRectangle(Items.OfType<DesignerItemViewModelBase>()), FitMode = FitMode.FitHeight };
            }
        }
        #endregion

        #region 分组
        private void ExecuteGroupCommand(object parameter)
        {
            List<DesignerItemViewModelBase> items;
            GroupDesignerItemViewModel groupItem = null;
            if (parameter is IEnumerable<DesignerItemViewModelBase> para)
            {
                if (para.FirstOrDefault() is GroupDesignerItemViewModel groupDesignerItemViewModel)
                {
                    groupItem = groupDesignerItemViewModel;
                    items = para.Skip(1).ToList();
                }
                else
                {
                    items = para.ToList();
                }
            }
            else
            {
                items = SelectedItems?.OfType<DesignerItemViewModelBase>().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<DesignerItemViewModelBase> groups;
            if (parameter is IEnumerable<DesignerItemViewModelBase> para)
            {
                groups = para.Where(p => p.IsGroup && p.ParentId == Guid.Empty).ToList();
            }
            else
            {
                groups = SelectedItems?.OfType<DesignerItemViewModelBase>().Where(p => p.IsGroup && p.ParentId == Guid.Empty).ToList();
            }

            Dictionary<DesignerItemViewModelBase, Tuple<Guid, int>> items = new Dictionary<DesignerItemViewModelBase, Tuple<Guid, int>>();
            foreach (DesignerItemViewModelBase groupRoot in groups)
            {
                var children = SelectedItems.OfType<DesignerItemViewModelBase>().Where(p => p.ParentId == groupRoot.Id);
                foreach (DesignerItemViewModelBase child in children)
                    items.Add(child, new Tuple<Guid, int>(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<SelectableDesignerItemViewModelBase> items)
        {
            if (items.Any())
            {
                Dictionary<SelectableDesignerItemViewModelBase, object> 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<SelectableDesignerItemViewModelBase> items)
        {
            if (items.Any())
            {
                Dictionary<SelectableDesignerItemViewModelBase, object> 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<SelectableDesignerItemViewModelBase> items)
        {
            if (items.Any())
            {
                Dictionary<SelectableDesignerItemViewModelBase, object> 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<SelectableDesignerItemViewModelBase> items)
        {
            if (items.Any())
            {
                Dictionary<SelectableDesignerItemViewModelBase, object> 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<SelectableDesignerItemViewModelBase> items)
        {
            if (items.Any())
            {
                Dictionary<SelectableDesignerItemViewModelBase, object> 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<SelectableDesignerItemViewModelBase> items)
        {
            if (propertyName == nameof(QuickTheme) && quickThemeViewModel.QuickTheme != null)
            {
                if (items.Any())
                {
                    Dictionary<SelectableDesignerItemViewModelBase, Tuple<object, object, object, object>> infos
                        = items.ToDictionary(p => p, p => new Tuple<object, object, object, object>(
                            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<SelectableDesignerItemViewModelBase> 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;
            }
            else if (DiagramOption.ShortcutOption.Next(e))
            {
                NextCommand.Execute(null);
                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<SelectableDesignerItemViewModelBase>().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<SelectableDesignerItemViewModelBase>().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<SelectableDesignerItemViewModelBase, string> 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<SelectableDesignerItemViewModelBase, string> 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

        #region 自动依附节点
        public FullyCreatedConnectorInfo FindNearPortToAttachTo(ConnectionViewModel partialConnection, ConnectorVertexType connectorVertexType)
        {
            if (partialConnection == null)
                return null;

            ClearNearPort();
            foreach (var port in Items.OfType<DesignerItemViewModelBase>().ToList().SelectMany(n => n.Connectors))
            {
                if (connectorVertexType == ConnectorVertexType.Start)
                {
                    if (partialConnection.SourceConnectorInfo.Position.DistanceTo(port.Position) < DiagramOption.SnappingOption.SnappingRadius)
                    {
                        if (partialConnection.SinkConnectorInfo?.CanAttachTo(port) == true)
                        {
                            port.DataItem.ShowConnectors = true;
                            port.BeAttachTo = true;
                            return port;
                        }
                        else
                        {
                            port.DataItem.ShowConnectors = true;
                            port.DisableAttachTo = true;
                            return null;
                        }
                    }
                }
                else if (connectorVertexType == ConnectorVertexType.End)
                {
                    if (partialConnection.SinkConnectorInfo.Position.DistanceTo(port.Position) < DiagramOption.SnappingOption.SnappingRadius)
                    {
                        if (partialConnection.SourceConnectorInfo?.CanAttachTo(port) == true)
                        {
                            port.DataItem.ShowConnectors = true;
                            port.BeAttachTo = true;
                            return port;
                        }
                        else
                        {
                            port.DataItem.ShowConnectors = true;
                            port.DisableAttachTo = true;
                            return null;
                        }
                    }
                }
            }

            return null;
        }

        public FullyCreatedConnectorInfo FindNearPortToAttachTo(ConnectionViewModel partialConnection)
        {
            if (partialConnection == null)
                return null;

            ClearNearPort();
            foreach (var port in Items.OfType<DesignerItemViewModelBase>().ToList().SelectMany(n => n.Connectors))
            {
                if (partialConnection.OnGoingPosition.DistanceTo(port.Position) < DiagramOption.SnappingOption.SnappingRadius)
                {
                    port.DataItem.ShowConnectors = true;
                    if (partialConnection.SourceConnectorInfo?.CanAttachTo(port) == true)
                    {
                        port.BeAttachTo = true;
                        return port;
                    }
                    else
                    {
                        port.DisableAttachTo = true;
                        return null;
                    }
                   
                }
            }

            return null;
        }

        public void ClearNearPort()
        {
            Items.OfType<DesignerItemViewModelBase>().ToList().SelectMany(n => n.Connectors).Where(p => p.BeAttachTo == true || p.DisableAttachTo == true).ToList()
                .ForEach(p => {
                    p.DisableAttachTo = false;
                    p.BeAttachTo = false;
                });
        }
        #endregion
    }
}
