快捷键支持

This commit is contained in:
艾竹
2023-02-04 20:21:18 +08:00
parent 285c015e83
commit 5b513370ff
13 changed files with 318 additions and 59 deletions

View File

@@ -6,7 +6,7 @@
xmlns:ac="https://gitee.com/akwkevin/AI-wpf-controls"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<ac:OptionsPanel HeaderText="{Binding Title}" HorizontalAlignment="Right" VerticalAlignment="Top" BorderBrush="#b8daff" BorderThickness="1" Background="#cce5ff" ac:ControlAttach.CornerRadius="3">
<ac:OptionsPanel HeaderText="{Binding Title}" HorizontalAlignment="Right" VerticalAlignment="Bottom" BorderBrush="#b8daff" BorderThickness="1" Background="#cce5ff" ac:ControlAttach.CornerRadius="3">
<TextBlock MaxWidth="350" Grid.Row="1" Text="{Binding Info}" Margin="10" TextWrapping="WrapWithOverflow" Foreground="#004085" />
</ac:OptionsPanel>
</UserControl>

View File

@@ -81,8 +81,9 @@ namespace AIStudio.Wpf.DiagramDesigner.Demo
new MenuItemViewModel(){Title = "Groups",
Children=new List<MenuItemViewModel>
{
new MenuItemViewModel(){Title = "Grouping"},
new MenuItemViewModel(){Title = "Group"},
new MenuItemViewModel(){Title = "CustomDefinedGroup"},
new MenuItemViewModel(){Title = "CustomShortcutGroup"},
}
},
new MenuItemViewModel(){Title = "Customization",
@@ -106,7 +107,7 @@ namespace AIStudio.Wpf.DiagramDesigner.Demo
new MenuItemViewModel(){Title = "PathAnimation"},
new MenuItemViewModel(){Title = "LineAnimation"},
}
},
},
new MenuItemViewModel(){Title = "Editor",
Children=new List<MenuItemViewModel>
{

View File

@@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Input;
namespace AIStudio.Wpf.DiagramDesigner.Demo.ViewModels
{
class CustomShortcutGroupViewModel : BaseViewModel
{
public CustomShortcutGroupViewModel()
{
Title = "Custom Shortcut";
Info = "You can customize what needs to be pressed to group selected nodes. CTRL+SHIFT+K in this example.";
DiagramViewModel = new DiagramViewModel();
DiagramViewModel.PageSizeType = PageSizeType.Custom;
DiagramViewModel.PageSize = new Size(double.NaN, double.NaN);
DiagramViewModel.ColorViewModel = new ColorViewModel();
DiagramViewModel.ColorViewModel.FillColor.Color = System.Windows.Media.Colors.Orange;
DiagramViewModel.DiagramOption.ShortcutOption.Group = e => e.KeyboardDevice.Modifiers == (ModifierKeys.Control | ModifierKeys.Shift) && e.Key == Key.K;
DefaultDesignerItemViewModel node1 = new DefaultDesignerItemViewModel(DiagramViewModel) { Left = 50, Top = 50, Text = "1" };
DiagramViewModel.DirectAddItemCommand.Execute(node1);
DefaultDesignerItemViewModel node2 = new DefaultDesignerItemViewModel(DiagramViewModel) { Left = 300, Top = 300, Text = "2" };
DiagramViewModel.DirectAddItemCommand.Execute(node2);
DefaultDesignerItemViewModel node3 = new DefaultDesignerItemViewModel(DiagramViewModel) { Left = 300, Top = 50, Text = "3" };
DiagramViewModel.DirectAddItemCommand.Execute(node3);
ConnectionViewModel connector1 = new ConnectionViewModel(DiagramViewModel, node1.RightConnector, node2.LeftConnector, DrawMode.ConnectingLineSmooth, RouterMode.RouterNormal);
DiagramViewModel.DirectAddItemCommand.Execute(connector1);
ConnectionViewModel connector2 = new ConnectionViewModel(DiagramViewModel, node2.RightConnector, node3.RightConnector, DrawMode.ConnectingLineStraight, RouterMode.RouterOrthogonal);
DiagramViewModel.DirectAddItemCommand.Execute(connector2);
DiagramViewModel.GroupCommand.Execute(new List<DesignerItemViewModelBase> { node1, node2 });
DiagramViewModel.ClearSelectedItemsCommand.Execute(null);
}
}
}

View File

@@ -5,9 +5,9 @@ using System.Windows;
namespace AIStudio.Wpf.DiagramDesigner.Demo.ViewModels
{
class GroupingViewModel : BaseViewModel
class GroupViewModel : BaseViewModel
{
public GroupingViewModel()
public GroupViewModel()
{
Title = "Grouping";
Info = "You can (un)group nodes using CTRL+ALT+G.<br>" +

View File

@@ -0,0 +1,16 @@
<UserControl x:Class="AIStudio.Wpf.DiagramDesigner.Demo.Views.CustomShortcutGroupView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:dd="https://gitee.com/akwkevin/aistudio.-wpf.-diagram"
xmlns:controls="clr-namespace:AIStudio.Wpf.DiagramDesigner.Demo.Controls"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<!-- Diagram Control -->
<dd:DiagramControl x:Name="diagram" DataContext="{Binding DiagramViewModel}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
<controls:TitleControl/>
</Grid>
</UserControl>

View File

@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace AIStudio.Wpf.DiagramDesigner.Demo.Views
{
/// <summary>
/// CustomShortcutGroupView.xaml 的交互逻辑
/// </summary>
public partial class CustomShortcutGroupView : UserControl
{
public CustomShortcutGroupView()
{
InitializeComponent();
}
}
}

View File

@@ -1,4 +1,4 @@
<UserControl x:Class="AIStudio.Wpf.DiagramDesigner.Demo.Views.GroupingView"
<UserControl x:Class="AIStudio.Wpf.DiagramDesigner.Demo.Views.GroupView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

View File

@@ -16,9 +16,9 @@ namespace AIStudio.Wpf.DiagramDesigner.Demo.Views
/// <summary>
/// GroupingView.xaml 的交互逻辑
/// </summary>
public partial class GroupingView : UserControl
public partial class GroupView : UserControl
{
public GroupingView()
public GroupView()
{
InitializeComponent();
}

View File

@@ -188,7 +188,6 @@ namespace AIStudio.Wpf.DiagramDesigner
public DesignerCanvas()
{
this.Focusable = true;
this.AllowDrop = true;
Mediator.Instance.Register(this);
@@ -500,32 +499,7 @@ namespace AIStudio.Wpf.DiagramDesigner
sourceConnectorInfo = null;
_service.DrawModeViewModel.ResetDrawMode();
}
protected override void OnPreviewKeyDown(KeyEventArgs e)
{
base.OnPreviewKeyDown(e);
bool executed = true;
var para = e.KeyboardDevice.Modifiers == ModifierKeys.None ? e.Key.ToString() : e.KeyboardDevice.Modifiers.ToString() + "+" + e.Key.ToString();
switch (para)
{
case "Control+A": _viewModel.SelectAllCommand.Execute(null); break;
case "Control+C": _viewModel.CopyCommand.Execute(null); break;
case "Control+V": _viewModel.PasteCommand.Execute(null); break;
case "Control+X": _viewModel.CutCommand.Execute(null); break;
case "Control+Z": _viewModel.UndoCommand.Execute(null); break;
case "Control+Y": _viewModel.RedoCommand.Execute(null); break;
case "Delete": _viewModel.DeleteCommand.Execute(null); break;
case "Left": _viewModel.LeftMoveCommand.Execute(null); break;
case "Right": _viewModel.RightMoveCommand.Execute(null); break;
case "Up": _viewModel.UpMoveCommand.Execute(null); break;
case "Down": _viewModel.DownMoveCommand.Execute(null); break;
default: executed = false; break;
}
e.Handled = executed;
}
}
protected override Size MeasureOverride(Size constraint)
{

View File

@@ -27,6 +27,8 @@ namespace AIStudio.Wpf.DiagramDesigner
{
this.Resources.MergedDictionaries.Add(ResourceDictionary);
}
this.Focusable = true;
}
public static readonly DependencyProperty ResourceDictionaryProperty = DependencyProperty.Register(nameof(ResourceDictionary), typeof(ResourceDictionary), typeof(DiagramControl), new UIPropertyMetadata(null, OnResourceDictionaryChanged));
@@ -71,9 +73,7 @@ namespace AIStudio.Wpf.DiagramDesigner
private void DesignerCanvas_Loaded(object sender, RoutedEventArgs e)
{
//DesignerCanvas myDesignerCanvas = sender as DesignerCanvas;
//zoomBox.DesignerCanvas = myDesignerCanvas;
//zoomBox.DesignerCanvas = myDesignerCanvas;
}
private async void ScaleTransform_Changed(object sender, EventArgs e)
@@ -81,5 +81,91 @@ namespace AIStudio.Wpf.DiagramDesigner
await System.Threading.Tasks.Task.Delay(100);
ZoomValue = scale.ScaleX;
}
private IDiagramViewModel DiagramViewModel
{
get
{
return DataContext as IDiagramViewModel;
}
}
protected override void OnPreviewKeyDown(KeyEventArgs e)
{
base.OnPreviewKeyDown(e);
if (DiagramViewModel.DiagramOption.ShortcutOption.SelectAll(e))
{
DiagramViewModel.SelectAllCommand.Execute(null);
e.Handled = true;
return;
}
else if (DiagramViewModel.DiagramOption.ShortcutOption.Copy(e))
{
DiagramViewModel.CopyCommand.Execute(null);
e.Handled = true;
return;
}
else if (DiagramViewModel.DiagramOption.ShortcutOption.Paste(e))
{
DiagramViewModel.PasteCommand.Execute(null);
e.Handled = true;
return;
}
else if (DiagramViewModel.DiagramOption.ShortcutOption.Cut(e))
{
DiagramViewModel.CutCommand.Execute(null);
e.Handled = true;
return;
}
else if (DiagramViewModel.DiagramOption.ShortcutOption.Undo(e))
{
DiagramViewModel.UndoCommand.Execute(null);
e.Handled = true;
return;
}
else if (DiagramViewModel.DiagramOption.ShortcutOption.Redo(e))
{
DiagramViewModel.RedoCommand.Execute(null);
e.Handled = true;
return;
}
else if (DiagramViewModel.DiagramOption.ShortcutOption.Delete(e))
{
DiagramViewModel.DeleteCommand.Execute(null);
e.Handled = true;
return;
}
else if (DiagramViewModel.DiagramOption.ShortcutOption.LeftMove(e))
{
DiagramViewModel.LeftMoveCommand.Execute(null);
e.Handled = true;
return;
}
else if (DiagramViewModel.DiagramOption.ShortcutOption.RightMove(e))
{
DiagramViewModel.RightMoveCommand.Execute(null);
e.Handled = true;
return;
}
else if (DiagramViewModel.DiagramOption.ShortcutOption.UpMove(e))
{
DiagramViewModel.UpMoveCommand.Execute(null);
e.Handled = true;
return;
}
else if (DiagramViewModel.DiagramOption.ShortcutOption.DownMove(e))
{
DiagramViewModel.DownMoveCommand.Execute(null);
e.Handled = true;
return;
}
else if (DiagramViewModel.DiagramOption.ShortcutOption.Group(e))
{
DiagramViewModel.GroupCommand.Execute(null);
e.Handled = true;
return;
}
}
}
}

View File

@@ -0,0 +1,92 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Windows.Input;
namespace AIStudio.Wpf.DiagramDesigner
{
public class DiagramOption
{
public ShortcutOption ShortcutOption
{
get; set;
} = new ShortcutOption();
}
public class ShortcutOption
{
[Description("Select All shortcut (CTRL+A by default)")]
public Func<KeyEventArgs, bool> SelectAll
{
get; set;
} = e => e.KeyboardDevice.Modifiers == ModifierKeys.Control && e.Key == Key.A;
[Description("Copy shortcut (CTRL+C by default)")]
public Func<KeyEventArgs, bool> Copy
{
get; set;
} = e => e.KeyboardDevice.Modifiers == ModifierKeys.Control && e.Key == Key.C;
[Description("Paste shortcut (CTRL+V by default)")]
public Func<KeyEventArgs, bool> Paste
{
get; set;
} = e => e.KeyboardDevice.Modifiers == ModifierKeys.Control && e.Key == Key.V;
[Description("Cut shortcut (CTRL+X by default)")]
public Func<KeyEventArgs, bool> Cut
{
get; set;
} = e => e.KeyboardDevice.Modifiers == ModifierKeys.Control && e.Key == Key.X;
[Description("Undo shortcut (CTRL+Z by default)")]
public Func<KeyEventArgs, bool> Undo
{
get; set;
} = e => e.KeyboardDevice.Modifiers == ModifierKeys.Control && e.Key == Key.Z;
[Description("Undo shortcut (CTRL+Y by default)")]
public Func<KeyEventArgs, bool> Redo
{
get; set;
} = e => e.KeyboardDevice.Modifiers == ModifierKeys.Control && e.Key == Key.Y;
[Description("Delete shortcut (Delete by default)")]
public Func<KeyEventArgs, bool> Delete
{
get; set;
} = e => e.KeyboardDevice.Modifiers == ModifierKeys.None && e.Key == Key.Delete;
[Description("Left Move shortcut (Left by default)")]
public Func<KeyEventArgs, bool> LeftMove
{
get; set;
} = e => e.KeyboardDevice.Modifiers == ModifierKeys.None && e.Key == Key.Left;
[Description("Right Move shortcut (Right by default)")]
public Func<KeyEventArgs, bool> RightMove
{
get; set;
} = e => e.KeyboardDevice.Modifiers == ModifierKeys.None && e.Key == Key.Right;
[Description("Up Move shortcut (Up by default)")]
public Func<KeyEventArgs, bool> UpMove
{
get; set;
} = e => e.KeyboardDevice.Modifiers == ModifierKeys.None && e.Key == Key.Up;
[Description("Down Move shortcut (Down by default)")]
public Func<KeyEventArgs, bool> DownMove
{
get; set;
} = e => e.KeyboardDevice.Modifiers == ModifierKeys.None && e.Key == Key.Down;
[Description("Group Keyboard shortcut (CTRL+Shift+G by default)")]
public Func<KeyEventArgs, bool> Group
{
get; set;
} = e => e.KeyboardDevice.Modifiers == (ModifierKeys.Control | ModifierKeys.Shift) && e.Key == Key.G;
}
}

View File

@@ -4,7 +4,6 @@ using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Reactive.Linq;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
@@ -408,6 +407,11 @@ namespace AIStudio.Wpf.DiagramDesigner
}
}
public DiagramOption DiagramOption
{
get; set;
} = new DiagramOption();
/// <summary>
/// 用于wpf大小与物理像素之间转换
/// </summary>
@@ -1460,7 +1464,7 @@ namespace AIStudio.Wpf.DiagramDesigner
}
}
DirectAddItemCommand.Execute(items);
OffsetX += 10;
OffsetY += 10;
@@ -1476,11 +1480,11 @@ namespace AIStudio.Wpf.DiagramDesigner
connectionItem.SourceType = System.Type.GetType(connectionItem.SourceTypeName);
connectionItem.SinkType = System.Type.GetType(connectionItem.SinkTypeName);
DesignerItemViewModelBase sourceItem = GetConnectorDataItem(this, connectionItem.SourceId, connectionItem.SourceType);
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 = GetConnectorDataItem(this, connectionItem.SinkId, connectionItem.SinkType);
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);
@@ -1488,8 +1492,6 @@ namespace AIStudio.Wpf.DiagramDesigner
connectors.Add(connectionVM);
}
DirectAddItemCommand.Execute(connectors);
//修复父级的引用
foreach (var item in items)
{
@@ -1499,19 +1501,17 @@ namespace AIStudio.Wpf.DiagramDesigner
item.ParentId = mappingOldToNewIDs[item.ParentId];
}
}
items.AddRange(connectors);
DirectAddItemCommand.Execute(items);
}
catch (Exception e)
{
System.Windows.MessageBox.Show(e.StackTrace, e.Message, System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error);
}
}
}
private DesignerItemViewModelBase GetConnectorDataItem(IDiagramViewModel diagramViewModel, Guid conectorDataItemId, Type connectorDataItemType)
{
DesignerItemViewModelBase dataItem = diagramViewModel.Items.OfType<DesignerItemViewModelBase>().Single(x => x.Id == conectorDataItemId);
return dataItem;
}
}
private bool ItemsToDeleteHasConnector(List<SelectableDesignerItemViewModelBase> itemsToRemove, ConnectorInfoBase connector)
{
@@ -1678,7 +1678,16 @@ namespace AIStudio.Wpf.DiagramDesigner
}
else
{
items = SelectedItems.OfType<DesignerItemViewModelBase>().Where(p => p.ParentId == Guid.Empty).ToList();
items = SelectedItems?.OfType<DesignerItemViewModelBase>().Where(p => p.ParentId == Guid.Empty).ToList();
}
var groups = items.OfType<DesignerItemViewModelBase>().Where(p => p.IsGroup && p.ParentId == Guid.Empty).ToList();
//解除分组
if (groupItem == null && groups.Count > 0)
{
ExecuteUngroupCommand(groups);
return;
}
RectangleBase rect = GetBoundingRectangle(items);
@@ -1706,9 +1715,15 @@ namespace AIStudio.Wpf.DiagramDesigner
private void ExecuteUngroupCommand(object parameter)
{
var groups = (from item in SelectedItems.OfType<DesignerItemViewModelBase>()
where item.IsGroup && item.ParentId == Guid.Empty
select item).ToArray();
List<DesignerItemViewModelBase> groups;
if (parameter is IEnumerable<DesignerItemViewModelBase> para)
{
groups = para.ToList();
}
else
{
groups = SelectedItems?.OfType<DesignerItemViewModelBase>().Where(p => p.IsGroup && p.ParentId == Guid.Empty).ToList();
}
foreach (DesignerItemViewModelBase groupRoot in groups)
{

View File

@@ -1,11 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Media;
using System.ComponentModel;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
namespace AIStudio.Wpf.DiagramDesigner
{
@@ -267,6 +266,13 @@ namespace AIStudio.Wpf.DiagramDesigner
get; set;
}
#endregion
#region
DiagramOption DiagramOption
{
get; set;
}
#endregion
//用于wpf大小与物理像素之间转换
double ScreenScale
{