From e0a26a76d2867eb3dee2fe0c98330252d42c8be9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=89=BE=E7=AB=B9?= Date: Wed, 5 Apr 2023 23:40:22 +0800 Subject: [PATCH] =?UTF-8?q?=E6=95=B4=E7=90=86Redo=E5=92=8CUndo=E5=91=BD?= =?UTF-8?q?=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controls/DesignerCanvas.cs | 7 +- .../BaseViewModel/DiagramViewModel.cs | 489 +++++++++++------- .../ViewModels/IDiagramViewModel.cs | 4 +- .../ViewModels/MindDiagramViewModel.cs | 11 +- 4 files changed, 314 insertions(+), 197 deletions(-) diff --git a/AIStudio.Wpf.DiagramDesigner/Controls/DesignerCanvas.cs b/AIStudio.Wpf.DiagramDesigner/Controls/DesignerCanvas.cs index 45443a7..a9abc1c 100644 --- a/AIStudio.Wpf.DiagramDesigner/Controls/DesignerCanvas.cs +++ b/AIStudio.Wpf.DiagramDesigner/Controls/DesignerCanvas.cs @@ -390,6 +390,8 @@ namespace AIStudio.Wpf.DiagramDesigner if (_viewModel.IsReadOnly) return; + this.Focus(); + Point currentPoint = e.GetPosition(this); _viewModel.CurrentPoint = new Point(ScreenHelper.WidthToMm(currentPoint.X), ScreenHelper.WidthToMm(currentPoint.Y)); var point = CursorPointManager.GetCursorPosition(); @@ -445,8 +447,9 @@ namespace AIStudio.Wpf.DiagramDesigner adornerLayer.Add(adorner); } } - } + } } + //e.Handled = true; } @@ -456,6 +459,8 @@ namespace AIStudio.Wpf.DiagramDesigner if (_viewModel.IsReadOnly) return; + this.Focus(); + if (_service.DrawModeViewModel.GetDrawMode() == DrawMode.DirectLine) { return; diff --git a/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/DiagramViewModel.cs b/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/DiagramViewModel.cs index 364fe7e..3a89d8d 100644 --- a/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/DiagramViewModel.cs +++ b/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/DiagramViewModel.cs @@ -639,12 +639,12 @@ namespace AIStudio.Wpf.DiagramDesigner #endregion #region 命令 - private ICommand _createNewDiagramCommand; - public ICommand CreateNewDiagramCommand + private ICommand _clearCommand; + public ICommand ClearCommand { get { - return this._createNewDiagramCommand ?? (this._createNewDiagramCommand = new SimpleCommand(ExecuteEnable, ExecuteCreateNewDiagramCommand)); + return this._clearCommand ?? (this._clearCommand = new SimpleCommand(ExecuteEnable, ExecuteClearCommand)); } } @@ -1050,7 +1050,7 @@ namespace AIStudio.Wpf.DiagramDesigner { 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(); @@ -1123,12 +1123,6 @@ namespace AIStudio.Wpf.DiagramDesigner private bool Undo(object para) { - var first = SelectedItems.OfType().FirstOrDefault(); - if (first != null && first.IsEditing == true) - { - return false; - } - DoCommandManager.UnDo(); return true; @@ -1141,11 +1135,6 @@ namespace AIStudio.Wpf.DiagramDesigner private bool Redo(object para) { - var first = SelectedItems.OfType().FirstOrDefault(); - if (first != null && first.IsEditing == true) - { - return false; - } DoCommandManager.ReDo(); return true; @@ -1165,7 +1154,7 @@ namespace AIStudio.Wpf.DiagramDesigner #region 属性改变 protected virtual void DiagramViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e) { - + } private void Items_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) @@ -1213,7 +1202,7 @@ namespace AIStudio.Wpf.DiagramDesigner } } - + //提供给标尺计算,延迟100ms,等布局改变再计算。 private void OnZoomValueChanged(string obj) @@ -1232,45 +1221,44 @@ namespace AIStudio.Wpf.DiagramDesigner } #region 新增,删除 - protected virtual void ExecuteCreateNewDiagramCommand(object parameter) + protected virtual void ExecuteClearCommand(object parameter) { - this.Items.Clear(); - } + var items = this.Items.ToList(); + DoCommandManager.DoNewCommand(this.ToString(), + () => { + this.Items.Clear(); + }, + () => { + foreach (var item in items) + { + Add(item); + } + }); + } private void ExecuteAddItemCommand(object parameter) { + List newitems = new List(); if (parameter is SelectableDesignerItemViewModelBase ite) { - if (AddVerify(ite) != true) return; - - DoCommandManager.DoNewCommand(this.ToString(), - () => { - ClearSelectedItems(); - Add(ite); - }, - () => { - Items.Remove(ite); - }); + newitems.Add(ite); } else if (parameter is IEnumerable items) { - if (items.Select(p => AddVerify(p)).Any() != true) return; - - DoCommandManager.DoNewCommand(this.ToString(), - () => { - ClearSelectedItems(); - foreach (var item in items) - { - Add(item); - } - }, - () => { - foreach (var item in items) - { - Items.Remove(item); - } - }); + newitems.AddRange(items); } + + DoCommandManager.DoNewCommand(this.ToString(), + () => { + ClearSelectedItems(); + Add(newitems); + }, + () => { + foreach (var item in newitems) + { + Items.Remove(item); + } + }); } public bool AddVerify(SelectableDesignerItemViewModelBase item) @@ -1282,13 +1270,13 @@ namespace AIStudio.Wpf.DiagramDesigner } //使用程序添加对象,比如Demo初始化 - public void Add(object parameter) + public void Add(object parameter, bool? isSelected = false) { if (parameter is SelectableDesignerItemViewModelBase ite) { if (AddVerify(ite) != true) return; - Add(ite, false); + Add(ite, isSelected); } else if (parameter is IEnumerable items) { @@ -1296,12 +1284,12 @@ namespace AIStudio.Wpf.DiagramDesigner foreach (var item in items) { - Add(item, false); + Add(item, isSelected); } } } - private void Add(SelectableDesignerItemViewModelBase item, bool isSelected = true) + private void Add(SelectableDesignerItemViewModelBase item, bool? isSelected = true) { item.Root = this; item.ZIndex = Items.Any() ? Items.Max(p => p.ZIndex) + 1 : 0; @@ -1322,8 +1310,11 @@ namespace AIStudio.Wpf.DiagramDesigner designerItemViewModelBase.SetCellAlignment(); } Items.Add(item); - item.IsSelected = isSelected; - } + if (isSelected != null) + { + item.IsSelected = isSelected.Value; + } + } public void Remove(object parameter) { @@ -1344,54 +1335,72 @@ namespace AIStudio.Wpf.DiagramDesigner private void ExecuteRemoveItemCommand(object parameter) { - if (parameter is SelectableDesignerItemViewModelBase ite) + List olditems = new List(); + if (parameter is SelectableDesignerItemViewModelBase node) { - DoCommandManager.DoNewCommand(this.ToString(), - () => { - ite.IsSelected = false; - Items.Remove(ite); - }, - () => { - Items.Add(ite); - }); + olditems.Add(node); } - else if (parameter is IEnumerable items) + else if (parameter is IEnumerable para) + { + olditems.AddRange(para); + } + else + { + olditems.AddRange(SelectedItems); + } + + if (olditems.Any()) { DoCommandManager.DoNewCommand(this.ToString(), - () => { - foreach (var item in items) - { - item.IsSelected = false; - Items.Remove(item); - } - - }, - () => { - foreach (var item in items) - { - Items.Add(item); - } - - }); + () => { + foreach (var item in olditems) + { + Items.Remove(item); + } + }, + () => { + foreach (var item in olditems) + { + Items.Add(item); + } + }); } } private void ExecuteClearSelectedItemsCommand(object parameter) { - IEnumerable selectedItems; - if (parameter is IEnumerable para) + List selectedItems = new List(); + if (parameter is SelectableDesignerItemViewModelBase node) { - selectedItems = para; + selectedItems.Add(node); + } + else if (parameter is IEnumerable para) + { + selectedItems.AddRange(para); } else { - selectedItems = this.SelectedItems.OfType(); + selectedItems.AddRange(SelectedItems); } - foreach (var item in selectedItems) + if (selectedItems.Any()) { - item.IsSelected = false; + Dictionary infos = selectedItems.ToDictionary(p => p, p => p.IsSelected); + DoCommandManager.DoNewCommand(this.ToString(), + () => { + foreach (var item in selectedItems) + { + item.IsSelected = false; + } + }, + () => { + foreach (var item in infos) + { + item.Key.IsSelected = item.Value; + } + }); } + } public void ClearSelectedItems() @@ -1404,39 +1413,93 @@ namespace AIStudio.Wpf.DiagramDesigner private void ExecuteSelectAllCommand(object parameter) { - foreach (var item in Items) + List selectedItems = Items.ToList(); + if (selectedItems.Any()) { - item.IsSelected = true; + Dictionary infos = selectedItems.ToDictionary(p => p, p => p.IsSelected); + DoCommandManager.DoNewCommand(this.ToString(), + () => { + foreach (var item in selectedItems) + { + item.IsSelected = true; + } + }, + () => { + foreach (var item in infos) + { + item.Key.IsSelected = item.Value; + } + }); } } private void ExecuteSelectInverseCommand(object parameter) { - foreach (var item in SelectedItems) + List selectedItems = new List(); + if (parameter is SelectableDesignerItemViewModelBase node) { - item.IsSelected = false; + selectedItems.Add(node); } - foreach (var item in Items.Except(SelectedItems)) + else if (parameter is IEnumerable para) { - item.IsSelected = true; + selectedItems.AddRange(para); + } + else + { + selectedItems.AddRange(Items); + } + + if (selectedItems.Any()) + { + Dictionary infos = selectedItems.ToDictionary(p => p, p => p.IsSelected); + DoCommandManager.DoNewCommand(this.ToString(), + () => { + foreach (var item in selectedItems) + { + item.IsSelected = !item.IsSelected; + } + }, + () => { + foreach (var item in infos) + { + item.Key.IsSelected = item.Value; + } + }); } } public void ExecuteSelectItemCommand(object parameter) { - if (parameter is ISelectable selectable) + List selectedItems = new List(); + if (parameter is SelectableDesignerItemViewModelBase node) { - foreach (var item in this.Items.ToList()) - { - if (object.Equals(selectable, item)) - { - item.IsSelected = true; - } - else - { - item.IsSelected = false; - } - } + selectedItems.Add(node); + } + else if (parameter is IEnumerable para) + { + selectedItems.AddRange(para); + } + else + { + selectedItems.AddRange(Items); + } + + if (selectedItems.Any()) + { + Dictionary infos = selectedItems.ToDictionary(p => p, p => p.IsSelected); + DoCommandManager.DoNewCommand(this.ToString(), + () => { + foreach (var item in selectedItems) + { + item.IsSelected = true; + } + }, + () => { + foreach (var item in infos) + { + item.Key.IsSelected = item.Value; + } + }); } } #endregion @@ -1447,58 +1510,52 @@ namespace AIStudio.Wpf.DiagramDesigner Copy(parameter); } - private bool Copy(object parameter) + private List Copy(object parameter) { - List selectedDesignerItems; - - List selectedConnections; - - if (parameter is IEnumerable para) + List selectedItems = new List(); + if (parameter is SelectableDesignerItemViewModelBase node) { - selectedDesignerItems = para.OfType().ToList(); - selectedConnections = para.OfType().ToList(); + selectedItems.Add(node); + } + else if (parameter is IEnumerable para) + { + selectedItems.AddRange(para); } else { - if (SelectedItems.Count == 0) - { - return false; - } - var first = SelectedItems.OfType().FirstOrDefault(); - if (first != null && first.IsEditing == true) - { - return false; - } - selectedDesignerItems = SelectedItems.OfType().ToList(); - selectedConnections = SelectedItems.OfType().ToList(); + selectedItems.AddRange(SelectedItems); } - - foreach (ConnectionViewModel connection in Items.OfType()) + if (selectedItems.Any()) { - if (!selectedConnections.Contains(connection)) + var selectedDesignerItems = selectedItems.OfType().ToList(); + var selectedConnections = selectedItems.OfType().ToList(); + + foreach (ConnectionViewModel connection in Items.OfType()) { - DesignerItemViewModelBase sourceItem = selectedDesignerItems.FirstOrDefault(p => p.Id == connection.SourceConnectorInfo.DataItem.Id); - DesignerItemViewModelBase sinkItem = selectedDesignerItems.FirstOrDefault(p => p.Id == connection.SinkConnectorInfoFully?.DataItem?.Id); - if (sourceItem != null && sinkItem != null && BelongToSameGroup(sourceItem, sinkItem)) + if (!selectedConnections.Contains(connection)) { - selectedConnections.Add(connection); + DesignerItemViewModelBase sourceItem = selectedDesignerItems.FirstOrDefault(p => p.Id == connection.SourceConnectorInfo.DataItem.Id); + DesignerItemViewModelBase sinkItem = selectedDesignerItems.FirstOrDefault(p => p.Id == connection.SinkConnectorInfoFully?.DataItem?.Id); + if (sourceItem != null && sinkItem != null && BelongToSameGroup(sourceItem, sinkItem)) + { + selectedConnections.Add(connection); + } } } + + string json = new SerializableObject + { + DesignerItems = selectedDesignerItems.Select(p => p.ToSerializableItem(".json")).Where(p => p != null).ToList(), + Connections = selectedConnections.Select(p => p.ToSerializableItem(".json")).Where(p => p != null).ToList(), + }.ToJson(); + + OffsetX = 0; + OffsetY = 0; + System.Windows.Clipboard.Clear(); + System.Windows.Clipboard.SetData(System.Windows.DataFormats.Serializable, json); } - - 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 true; + return selectedItems; } private void ExecutePasteCommand(object parameter) @@ -1506,20 +1563,21 @@ namespace AIStudio.Wpf.DiagramDesigner Paste(parameter); } - protected virtual bool Paste(object parameter) + protected virtual List Paste(object parameter, bool paste = true) { if (System.Windows.Clipboard.ContainsData(System.Windows.DataFormats.Serializable)) { string clipboardData = System.Windows.Clipboard.GetData(System.Windows.DataFormats.Serializable) as String; if (string.IsNullOrEmpty(clipboardData)) - return false; + return null; + + List items = new List(); try { OffsetX += 10; - OffsetY += 10; + OffsetY += 10; - List items = new List(); SerializableObject copyitem = JsonConvert.DeserializeObject(clipboardData); Dictionary mappingOldToNewIDs = new Dictionary(); @@ -1543,7 +1601,7 @@ namespace AIStudio.Wpf.DiagramDesigner { items.Add(newItem); } - } + } List connectors = new List(); foreach (var connection in copyitem.Connections) @@ -1578,27 +1636,45 @@ namespace AIStudio.Wpf.DiagramDesigner if (mappingOldToNewIDs.ContainsKey(item.ParentId)) item.ParentId = mappingOldToNewIDs[item.ParentId]; } - } - items.AddRange(connectors); - Add(items); - - FixOtherInfo(items); + } + items.AddRange(connectors); } catch (Exception e) { System.Windows.MessageBox.Show(e.StackTrace, e.Message, System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error); + return null; } - return true; + + 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 false; + return null; } } protected virtual void FixOtherInfo(List items) { - + } private bool ItemsToDeleteHasConnector(List itemsToRemove, ConnectorInfoBase connector) @@ -1616,42 +1692,70 @@ namespace AIStudio.Wpf.DiagramDesigner Cut(parameter); } - private bool Cut(object parameter) + private List Cut(object parameter, bool cut = true) { - if (Paste(null) == false) - return false; - - if (Delete(null) == false) - return false; + if (Copy(null) == null) + return null; - return true; + 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) { - Delete(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 bool Delete(object parameter) + protected virtual List Delete(object parameter, bool delete = true) { - List itemsToRemove; - - if (parameter is IEnumerable para) + List itemsToRemove = new List(); + if (parameter is SelectableDesignerItemViewModelBase node) { - itemsToRemove = para.OfType().ToList(); + itemsToRemove.Add(node); + } + else if (parameter is IEnumerable para) + { + itemsToRemove.AddRange(para); } else { - if (SelectedItems.Count == 0) - { - return false; - } - var first = SelectedItems.OfType().FirstOrDefault(); - if (first != null && first.IsEditing == true) - { - return false; - } - itemsToRemove = SelectedItems.OfType().ToList(); + itemsToRemove.AddRange(SelectedItems); } List connectionsToAlsoRemove = new List(); @@ -1671,9 +1775,17 @@ namespace AIStudio.Wpf.DiagramDesigner } itemsToRemove.AddRange(connectionsToAlsoRemove); - RemoveItemCommand.Execute(itemsToRemove); - - return true; + if (itemsToRemove.Any()) + { + if (delete) + { + foreach (var item in itemsToRemove) + { + Items.Remove(item); + } + } + } + return itemsToRemove; } #endregion @@ -2477,7 +2589,7 @@ namespace AIStudio.Wpf.DiagramDesigner groupItem = new GroupDesignerItemViewModel(); } - Add(groupItem); + Add(groupItem, true); foreach (DesignerItemViewModelBase item in items) item.ParentId = groupItem.Id; @@ -2524,22 +2636,27 @@ namespace AIStudio.Wpf.DiagramDesigner #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)) - { - return Copy(null); + { + return Copy(null) != null; } else if (DiagramOption.ShortcutOption.Paste(e)) { - return Paste(null); + return Paste(null) != null; } else if (DiagramOption.ShortcutOption.Cut(e)) { - return Cut(null); + return Cut(null) != null; } else if (DiagramOption.ShortcutOption.Undo(e)) { @@ -2551,7 +2668,7 @@ namespace AIStudio.Wpf.DiagramDesigner } else if (DiagramOption.ShortcutOption.Delete(e)) { - return Delete(null); + return Delete(null) != null; } else if (DiagramOption.ShortcutOption.LeftMove(e)) { @@ -2611,7 +2728,7 @@ namespace AIStudio.Wpf.DiagramDesigner } private void ExecutedSearchUpCommand(object obj) - { + { if (obj != null) { var selecteddesign = SelectedItem as DesignerItemViewModelBase; diff --git a/AIStudio.Wpf.DiagramDesigner/ViewModels/IDiagramViewModel.cs b/AIStudio.Wpf.DiagramDesigner/ViewModels/IDiagramViewModel.cs index 0d1f244..f1480cc 100644 --- a/AIStudio.Wpf.DiagramDesigner/ViewModels/IDiagramViewModel.cs +++ b/AIStudio.Wpf.DiagramDesigner/ViewModels/IDiagramViewModel.cs @@ -31,7 +31,7 @@ namespace AIStudio.Wpf.DiagramDesigner get; } - ICommand CreateNewDiagramCommand + ICommand ClearCommand { get; } @@ -335,7 +335,7 @@ namespace AIStudio.Wpf.DiagramDesigner void Init(bool initNew); - void Add(object parameter); + void Add(object parameter, bool? isSelected = false); void Remove(object parameter); diff --git a/AIStudio.Wpf.Mind/ViewModels/MindDiagramViewModel.cs b/AIStudio.Wpf.Mind/ViewModels/MindDiagramViewModel.cs index 25454dd..1339e35 100644 --- a/AIStudio.Wpf.Mind/ViewModels/MindDiagramViewModel.cs +++ b/AIStudio.Wpf.Mind/ViewModels/MindDiagramViewModel.cs @@ -774,7 +774,7 @@ namespace AIStudio.Wpf.Mind.ViewModels items.Select(p => p.RootNode).Distinct().ToList().ForEach(p => p.UpdatedLayout()); } - protected override bool Delete(object parameter) + protected override List Delete(object parameter, bool delete = true) { List items = new List(); List others = new List(); @@ -793,11 +793,6 @@ namespace AIStudio.Wpf.Mind.ViewModels others = SelectedItems.Where(p => !(p is MindNode)).ToList(); } - if (items.FirstOrDefault()?.IsEditing != false) - { - return false; - } - if (items.Any()) { //把子节点都加上 @@ -842,10 +837,10 @@ namespace AIStudio.Wpf.Mind.ViewModels items.Select(p => p.RootNode).Distinct().ToList().ForEach(p => p.UpdatedLayout()); }); - return true; + return items.OfType().ToList(); } else - return false; + return null; } #endregion