From 839250e87fc3e3108ae6392a9fab95542d4c6b3a Mon Sep 17 00:00:00 2001 From: Max Katz Date: Mon, 18 Mar 2024 21:01:51 -0700 Subject: [PATCH 1/2] Use CommandManager from Labs --- src/AvaloniaEdit/AvaloniaEdit.csproj | 1 + src/AvaloniaEdit/AvaloniaEditCommands.cs | 11 +- .../Editing/CaretNavigationCommandHandler.cs | 5 +- .../Editing/EditingCommandHandler.cs | 7 +- .../Editing/RectangleSelection.cs | 1 + src/AvaloniaEdit/Editing/TextArea.cs | 5 +- .../Editing/TextAreaDefaultInputHandlers.cs | 3 +- .../Editing/TextAreaInputHandler.cs | 19 +- src/AvaloniaEdit/RoutedCommand.cs | 194 ------------------ src/AvaloniaEdit/Search/SearchCommands.cs | 27 +-- src/AvaloniaEdit/Search/SearchPanel.cs | 21 +- 11 files changed, 53 insertions(+), 241 deletions(-) delete mode 100644 src/AvaloniaEdit/RoutedCommand.cs diff --git a/src/AvaloniaEdit/AvaloniaEdit.csproj b/src/AvaloniaEdit/AvaloniaEdit.csproj index 6605d29f..553b2285 100644 --- a/src/AvaloniaEdit/AvaloniaEdit.csproj +++ b/src/AvaloniaEdit/AvaloniaEdit.csproj @@ -17,6 +17,7 @@ + diff --git a/src/AvaloniaEdit/AvaloniaEditCommands.cs b/src/AvaloniaEdit/AvaloniaEditCommands.cs index dd87f17b..5b523d6f 100644 --- a/src/AvaloniaEdit/AvaloniaEditCommands.cs +++ b/src/AvaloniaEdit/AvaloniaEditCommands.cs @@ -20,7 +20,7 @@ using System.Runtime.InteropServices; using Avalonia; using Avalonia.Input; -using Avalonia.Platform; +using Avalonia.Labs.Input; namespace AvaloniaEdit { @@ -115,13 +115,8 @@ public static class ApplicationCommands public static RoutedCommand Replace { get; } = new RoutedCommand(nameof(Replace), GetReplaceKeyGesture()); private static KeyModifiers GetPlatformCommandKey() - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - return KeyModifiers.Meta; - } - - return KeyModifiers.Control; + { + return Application.Current?.PlatformSettings?.HotkeyConfiguration.CommandModifiers ?? KeyModifiers.Control; } private static KeyGesture GetReplaceKeyGesture() diff --git a/src/AvaloniaEdit/Editing/CaretNavigationCommandHandler.cs b/src/AvaloniaEdit/Editing/CaretNavigationCommandHandler.cs index dc7c3710..100211c9 100644 --- a/src/AvaloniaEdit/Editing/CaretNavigationCommandHandler.cs +++ b/src/AvaloniaEdit/Editing/CaretNavigationCommandHandler.cs @@ -25,6 +25,7 @@ using AvaloniaEdit.Utils; using Avalonia.Input; using Avalonia.Input.Platform; +using Avalonia.Labs.Input; using Avalonia.Media.TextFormatting; using LogicalDirection = AvaloniaEdit.Document.LogicalDirection; @@ -61,12 +62,12 @@ public static TextAreaInputHandler Create(TextArea textArea) return handler; } - static readonly List CommandBindings = new List(); + static readonly List CommandBindings = new List(); static readonly List KeyBindings = new List(); private static void AddBinding(RoutedCommand command, EventHandler handler) { - CommandBindings.Add(new RoutedCommandBinding(command, handler)); + CommandBindings.Add(new CommandBinding(command, handler)); } private static void AddBinding(RoutedCommand command, KeyModifiers modifiers, Key key, EventHandler handler) diff --git a/src/AvaloniaEdit/Editing/EditingCommandHandler.cs b/src/AvaloniaEdit/Editing/EditingCommandHandler.cs index 50940a74..6f5395f6 100644 --- a/src/AvaloniaEdit/Editing/EditingCommandHandler.cs +++ b/src/AvaloniaEdit/Editing/EditingCommandHandler.cs @@ -25,6 +25,7 @@ using Avalonia.Input; using AvaloniaEdit.Utils; using Avalonia.Controls; +using Avalonia.Labs.Input; namespace AvaloniaEdit.Editing { @@ -45,19 +46,19 @@ public static TextAreaInputHandler Create(TextArea textArea) return handler; } - private static readonly List CommandBindings = new List(); + private static readonly List CommandBindings = new List(); private static readonly List KeyBindings = new List(); private static void AddBinding(RoutedCommand command, KeyModifiers modifiers, Key key, EventHandler handler) { - CommandBindings.Add(new RoutedCommandBinding(command, handler)); + CommandBindings.Add(new CommandBinding(command, handler)); KeyBindings.Add(TextAreaDefaultInputHandler.CreateKeyBinding(command, modifiers, key)); } private static void AddBinding(RoutedCommand command, EventHandler handler, EventHandler canExecuteHandler = null) { - CommandBindings.Add(new RoutedCommandBinding(command, handler, canExecuteHandler)); + CommandBindings.Add(new CommandBinding(command, handler, canExecuteHandler)); } static EditingCommandHandler() diff --git a/src/AvaloniaEdit/Editing/RectangleSelection.cs b/src/AvaloniaEdit/Editing/RectangleSelection.cs index 0c53fa2a..c33dd689 100644 --- a/src/AvaloniaEdit/Editing/RectangleSelection.cs +++ b/src/AvaloniaEdit/Editing/RectangleSelection.cs @@ -21,6 +21,7 @@ using System.Linq; using System.Text; using Avalonia; +using Avalonia.Labs.Input; using AvaloniaEdit.Document; using AvaloniaEdit.Utils; diff --git a/src/AvaloniaEdit/Editing/TextArea.cs b/src/AvaloniaEdit/Editing/TextArea.cs index cf300858..08c431c6 100644 --- a/src/AvaloniaEdit/Editing/TextArea.cs +++ b/src/AvaloniaEdit/Editing/TextArea.cs @@ -39,13 +39,14 @@ using System.ComponentModel; using System.Diagnostics; using System.Linq; +using Avalonia.Labs.Input; namespace AvaloniaEdit.Editing { /// /// Control that wraps a TextView and adds support for user input and the caret. /// - public class TextArea : TemplatedControl, ITextEditorComponent, IRoutedCommandBindable, ILogicalScrollable + public class TextArea : TemplatedControl, ITextEditorComponent, ILogicalScrollable { /// /// This is the extra scrolling space that occurs after the last line. @@ -1075,7 +1076,7 @@ internal void OnTextCopied(TextEventArgs e) TextCopied?.Invoke(this, e); } - public IList CommandBindings { get; } = new List(); + public IList CommandBindings => CommandManager.GetCommandBindings(this); bool ILogicalScrollable.IsLogicalScrollEnabled => _logicalScrollable?.IsLogicalScrollEnabled ?? default(bool); diff --git a/src/AvaloniaEdit/Editing/TextAreaDefaultInputHandlers.cs b/src/AvaloniaEdit/Editing/TextAreaDefaultInputHandlers.cs index c0e796f9..31d56cbf 100644 --- a/src/AvaloniaEdit/Editing/TextAreaDefaultInputHandlers.cs +++ b/src/AvaloniaEdit/Editing/TextAreaDefaultInputHandlers.cs @@ -20,6 +20,7 @@ using System.Windows.Input; using AvaloniaEdit.Document; using Avalonia.Input; +using Avalonia.Labs.Input; namespace AvaloniaEdit.Editing { @@ -58,7 +59,7 @@ public TextAreaDefaultInputHandler(TextArea textArea) : base(textArea) private void AddBinding(RoutedCommand command, EventHandler handler, EventHandler canExecuteHandler = null) { - CommandBindings.Add(new RoutedCommandBinding(command, handler, canExecuteHandler)); + CommandBindings.Add(new CommandBinding(command, handler, canExecuteHandler)); } internal static KeyBinding CreateKeyBinding(ICommand command, KeyModifiers modifiers, Key key) diff --git a/src/AvaloniaEdit/Editing/TextAreaInputHandler.cs b/src/AvaloniaEdit/Editing/TextAreaInputHandler.cs index ce7aa252..f00e53a0 100644 --- a/src/AvaloniaEdit/Editing/TextAreaInputHandler.cs +++ b/src/AvaloniaEdit/Editing/TextAreaInputHandler.cs @@ -18,8 +18,10 @@ using System; using System.Collections.Generic; +using System.Linq; using AvaloniaEdit.Utils; using Avalonia.Input; +using Avalonia.Labs.Input; namespace AvaloniaEdit.Editing { @@ -108,7 +110,7 @@ public virtual void OnPreviewKeyUp(KeyEventArgs e) /// public class TextAreaInputHandler : ITextAreaInputHandler { - private readonly ObserveAddRemoveCollection _commandBindings; + private readonly ObserveAddRemoveCollection _commandBindings; private readonly List _keyBindings; private readonly ObserveAddRemoveCollection _nestedInputHandlers; @@ -118,7 +120,7 @@ public class TextAreaInputHandler : ITextAreaInputHandler public TextAreaInputHandler(TextArea textArea) { TextArea = textArea ?? throw new ArgumentNullException(nameof(textArea)); - _commandBindings = new ObserveAddRemoveCollection(CommandBinding_Added, CommandBinding_Removed); + _commandBindings = new ObserveAddRemoveCollection(CommandBinding_Added, CommandBinding_Removed); _keyBindings = new List(); _nestedInputHandlers = new ObserveAddRemoveCollection(NestedInputHandler_Added, NestedInputHandler_Removed); } @@ -135,15 +137,15 @@ public TextAreaInputHandler(TextArea textArea) /// /// Gets the command bindings of this input handler. /// - public ICollection CommandBindings => _commandBindings; + public ICollection CommandBindings => _commandBindings; - private void CommandBinding_Added(RoutedCommandBinding commandBinding) + private void CommandBinding_Added(CommandBinding commandBinding) { if (IsAttached) TextArea.CommandBindings.Add(commandBinding); } - private void CommandBinding_Removed(RoutedCommandBinding commandBinding) + private void CommandBinding_Removed(CommandBinding commandBinding) { if (IsAttached) TextArea.CommandBindings.Remove(commandBinding); @@ -175,7 +177,7 @@ private void CommandBinding_Removed(RoutedCommandBinding commandBinding) /// The event handler to run when the command is executed. public void AddBinding(RoutedCommand command, KeyModifiers modifiers, Key key, EventHandler handler) { - CommandBindings.Add(new RoutedCommandBinding(command, handler)); + CommandBindings.Add(new CommandBinding(command, handler)); KeyBindings.Add(new KeyBinding { Command = command, Gesture = new KeyGesture (key, modifiers) }); } #endregion @@ -218,9 +220,10 @@ private void TextAreaOnKeyDown(object sender, KeyEventArgs keyEventArgs) foreach (var commandBinding in CommandBindings) { - if (commandBinding.Command.Gesture?.Matches(keyEventArgs) == true) + if (commandBinding.Command is RoutedCommand routedCommand + && routedCommand.Gestures.Any(g => g.Matches(keyEventArgs))) { - commandBinding.Command.Execute(null, (IInputElement)sender); + routedCommand.Execute(null, (IInputElement)sender); keyEventArgs.Handled = true; break; } diff --git a/src/AvaloniaEdit/RoutedCommand.cs b/src/AvaloniaEdit/RoutedCommand.cs deleted file mode 100644 index 7a204d76..00000000 --- a/src/AvaloniaEdit/RoutedCommand.cs +++ /dev/null @@ -1,194 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Windows.Input; -using Avalonia.Input; -using Avalonia.Interactivity; - -namespace AvaloniaEdit -{ - public class RoutedCommand : ICommand - { - private static IInputElement _inputElement; - - public string Name { get; } - public KeyGesture Gesture { get; } - - public RoutedCommand(string name, KeyGesture keyGesture = null) - { - Name = name; - Gesture = keyGesture; - } - - static RoutedCommand() - { - CanExecuteEvent.AddClassHandler(CanExecuteEventHandler); - ExecutedEvent.AddClassHandler(ExecutedEventHandler); - InputElement.GotFocusEvent.AddClassHandler(GotFocusEventHandler); - } - - private static void CanExecuteEventHandler(Interactive control, CanExecuteRoutedEventArgs args) - { - if (control is IRoutedCommandBindable bindable) - { - var binding = bindable.CommandBindings.Where(c => c != null) - .FirstOrDefault(c => c.Command == args.Command && c.DoCanExecute(control, args)); - args.CanExecute = binding != null; - } - } - - private static void ExecutedEventHandler(Interactive control, ExecutedRoutedEventArgs args) - { - if (control is IRoutedCommandBindable bindable) - { - // ReSharper disable once UnusedVariable - var binding = bindable.CommandBindings.Where(c => c != null) - .FirstOrDefault(c => c.Command == args.Command && c.DoExecuted(control, args)); - - } - } - - private static void GotFocusEventHandler(Interactive control, GotFocusEventArgs args) - { - _inputElement = args.Source as IInputElement; - } - - public static RoutedEvent CanExecuteEvent { get; } = RoutedEvent.Register(nameof(CanExecuteEvent), RoutingStrategies.Bubble, typeof(RoutedCommand)); - - public bool CanExecute(object parameter, IInputElement target) - { - if (target == null) return false; - - var args = new CanExecuteRoutedEventArgs(this, parameter); - target.RaiseEvent(args); - - return args.CanExecute; - } - - bool ICommand.CanExecute(object parameter) - { - return CanExecute(parameter, _inputElement); - } - - public static RoutedEvent ExecutedEvent { get; } = RoutedEvent.Register(nameof(ExecutedEvent), RoutingStrategies.Bubble, typeof(RoutedCommand)); - - public void Execute(object parameter, IInputElement target) - { - if (target == null) return; - - var args = new ExecutedRoutedEventArgs(this, parameter); - target.RaiseEvent(args); - } - - void ICommand.Execute(object parameter) - { - Execute(parameter, _inputElement); - } - - // TODO - event EventHandler ICommand.CanExecuteChanged - { - add { } - remove { } - } - } - - public interface IRoutedCommandBindable - { - IList CommandBindings { get; } - } - - public class RoutedCommandBinding - { - public RoutedCommandBinding(RoutedCommand command, - EventHandler executed = null, - EventHandler canExecute = null) - { - Command = command; - if (executed != null) Executed += executed; - if (canExecute != null) CanExecute += canExecute; - } - - public RoutedCommand Command { get; } - - public event EventHandler CanExecute; - - public event EventHandler Executed; - - internal bool DoCanExecute(object sender, CanExecuteRoutedEventArgs e) - { - if (e.Handled) return true; - - var canExecute = CanExecute; - if (canExecute == null) - { - if (Executed != null) - { - e.Handled = true; - e.CanExecute = true; - } - } - else - { - canExecute(sender, e); - - if (e.CanExecute) - { - e.Handled = true; - } - } - - return e.CanExecute; - } - - internal bool DoExecuted(object sender, ExecutedRoutedEventArgs e) - { - if (!e.Handled) - { - var executed = Executed; - - if (executed != null) - { - if (DoCanExecute(sender, new CanExecuteRoutedEventArgs(e.Command, e.Parameter))) - { - executed(sender, e); - e.Handled = true; - return true; - } - } - } - - return false; - } - } - - public sealed class CanExecuteRoutedEventArgs : RoutedEventArgs - { - public ICommand Command { get; } - - public object Parameter { get; } - - public bool CanExecute { get; set; } - - internal CanExecuteRoutedEventArgs(ICommand command, object parameter) - { - Command = command ?? throw new ArgumentNullException(nameof(command)); - Parameter = parameter; - RoutedEvent = RoutedCommand.CanExecuteEvent; - } - } - - public sealed class ExecutedRoutedEventArgs : RoutedEventArgs - { - public ICommand Command { get; } - - public object Parameter { get; } - - internal ExecutedRoutedEventArgs(ICommand command, object parameter) - { - Command = command ?? throw new ArgumentNullException(nameof(command)); - Parameter = parameter; - RoutedEvent = RoutedCommand.ExecutedEvent; - } - } -} \ No newline at end of file diff --git a/src/AvaloniaEdit/Search/SearchCommands.cs b/src/AvaloniaEdit/Search/SearchCommands.cs index 3303f654..c01411f3 100644 --- a/src/AvaloniaEdit/Search/SearchCommands.cs +++ b/src/AvaloniaEdit/Search/SearchCommands.cs @@ -19,6 +19,7 @@ using System; using System.Collections.Generic; using Avalonia.Input; +using Avalonia.Labs.Input; using Avalonia.Threading; using AvaloniaEdit.Editing; @@ -67,23 +68,23 @@ public SearchInputHandler(TextArea textArea, SearchPanel panel) _panel = panel; } - internal void RegisterGlobalCommands(ICollection commandBindings) + internal void RegisterGlobalCommands(ICollection commandBindings) { - commandBindings.Add(new RoutedCommandBinding(ApplicationCommands.Find, ExecuteFind)); - CommandBindings.Add(new RoutedCommandBinding(ApplicationCommands.Replace, ExecuteReplace)); - commandBindings.Add(new RoutedCommandBinding(SearchCommands.FindNext, ExecuteFindNext, CanExecuteWithOpenSearchPanel)); - commandBindings.Add(new RoutedCommandBinding(SearchCommands.FindPrevious, ExecuteFindPrevious, CanExecuteWithOpenSearchPanel)); + commandBindings.Add(new CommandBinding(ApplicationCommands.Find, ExecuteFind)); + CommandBindings.Add(new CommandBinding(ApplicationCommands.Replace, ExecuteReplace)); + commandBindings.Add(new CommandBinding(SearchCommands.FindNext, ExecuteFindNext, CanExecuteWithOpenSearchPanel)); + commandBindings.Add(new CommandBinding(SearchCommands.FindPrevious, ExecuteFindPrevious, CanExecuteWithOpenSearchPanel)); } - private void RegisterCommands(ICollection commandBindings) + private void RegisterCommands(ICollection commandBindings) { - commandBindings.Add(new RoutedCommandBinding(ApplicationCommands.Find, ExecuteFind)); - CommandBindings.Add(new RoutedCommandBinding(ApplicationCommands.Replace, ExecuteReplace)); - commandBindings.Add(new RoutedCommandBinding(SearchCommands.FindNext, ExecuteFindNext, CanExecuteWithOpenSearchPanel)); - commandBindings.Add(new RoutedCommandBinding(SearchCommands.FindPrevious, ExecuteFindPrevious, CanExecuteWithOpenSearchPanel)); - CommandBindings.Add(new RoutedCommandBinding(SearchCommands.ReplaceNext, ExecuteReplaceNext, CanExecuteWithOpenSearchPanel)); - CommandBindings.Add(new RoutedCommandBinding(SearchCommands.ReplaceAll, ExecuteReplaceAll, CanExecuteWithOpenSearchPanel)); - commandBindings.Add(new RoutedCommandBinding(SearchCommands.CloseSearchPanel, ExecuteCloseSearchPanel, CanExecuteWithOpenSearchPanel)); + commandBindings.Add(new CommandBinding(ApplicationCommands.Find, ExecuteFind)); + CommandBindings.Add(new CommandBinding(ApplicationCommands.Replace, ExecuteReplace)); + commandBindings.Add(new CommandBinding(SearchCommands.FindNext, ExecuteFindNext, CanExecuteWithOpenSearchPanel)); + commandBindings.Add(new CommandBinding(SearchCommands.FindPrevious, ExecuteFindPrevious, CanExecuteWithOpenSearchPanel)); + CommandBindings.Add(new CommandBinding(SearchCommands.ReplaceNext, ExecuteReplaceNext, CanExecuteWithOpenSearchPanel)); + CommandBindings.Add(new CommandBinding(SearchCommands.ReplaceAll, ExecuteReplaceAll, CanExecuteWithOpenSearchPanel)); + commandBindings.Add(new CommandBinding(SearchCommands.CloseSearchPanel, ExecuteCloseSearchPanel, CanExecuteWithOpenSearchPanel)); } private readonly SearchPanel _panel; diff --git a/src/AvaloniaEdit/Search/SearchPanel.cs b/src/AvaloniaEdit/Search/SearchPanel.cs index 1dd23585..66224ede 100644 --- a/src/AvaloniaEdit/Search/SearchPanel.cs +++ b/src/AvaloniaEdit/Search/SearchPanel.cs @@ -23,6 +23,7 @@ using Avalonia.Controls; using Avalonia.Controls.Primitives; using Avalonia.Input; +using Avalonia.Labs.Input; using Avalonia.Media; using AvaloniaEdit.Document; @@ -35,7 +36,7 @@ namespace AvaloniaEdit.Search /// /// Provides search functionality for AvalonEdit. It is displayed in the top-right corner of the TextArea. /// - public class SearchPanel : TemplatedControl, IRoutedCommandBindable + public class SearchPanel : TemplatedControl { private TextArea _textArea; private SearchInputHandler _handler; @@ -198,7 +199,7 @@ public static SearchPanel Install(TextEditor editor) /// /// Adds the commands used by SearchPanel to the given CommandBindingCollection. /// - public void RegisterCommands(ICollection commandBindings) + public void RegisterCommands(ICollection commandBindings) { _handler.RegisterGlobalCommands(commandBindings); } @@ -227,18 +228,18 @@ private void AttachInternal(TextEditor textEditor) _textArea.DocumentChanged += TextArea_DocumentChanged; KeyDown += SearchLayerKeyDown; - CommandBindings.Add(new RoutedCommandBinding(SearchCommands.FindNext, (sender, e) => FindNext())); - CommandBindings.Add(new RoutedCommandBinding(SearchCommands.FindPrevious, (sender, e) => FindPrevious())); - CommandBindings.Add(new RoutedCommandBinding(SearchCommands.CloseSearchPanel, (sender, e) => Close())); + CommandBindings.Add(new CommandBinding(SearchCommands.FindNext, (sender, e) => FindNext())); + CommandBindings.Add(new CommandBinding(SearchCommands.FindPrevious, (sender, e) => FindPrevious())); + CommandBindings.Add(new CommandBinding(SearchCommands.CloseSearchPanel, (sender, e) => Close())); - CommandBindings.Add(new RoutedCommandBinding(ApplicationCommands.Find, (sender, e) => + CommandBindings.Add(new CommandBinding(ApplicationCommands.Find, (sender, e) => { IsReplaceMode = false; Reactivate(); })); - CommandBindings.Add(new RoutedCommandBinding(ApplicationCommands.Replace, (sender, e) => IsReplaceMode = true)); - CommandBindings.Add(new RoutedCommandBinding(SearchCommands.ReplaceNext, (sender, e) => ReplaceNext(), (sender, e) => e.CanExecute = IsReplaceMode)); - CommandBindings.Add(new RoutedCommandBinding(SearchCommands.ReplaceAll, (sender, e) => ReplaceAll(), (sender, e) => e.CanExecute = IsReplaceMode)); + CommandBindings.Add(new CommandBinding(ApplicationCommands.Replace, (sender, e) => IsReplaceMode = true)); + CommandBindings.Add(new CommandBinding(SearchCommands.ReplaceNext, (sender, e) => ReplaceNext(), (sender, e) => e.CanExecute = IsReplaceMode)); + CommandBindings.Add(new CommandBinding(SearchCommands.ReplaceAll, (sender, e) => ReplaceAll(), (sender, e) => e.CanExecute = IsReplaceMode)); IsClosed = true; } @@ -559,7 +560,7 @@ protected virtual void OnSearchOptionsChanged(SearchOptionsChangedEventArgs e) SearchOptionsChanged?.Invoke(this, e); } - public IList CommandBindings { get; } = new List(); + public IList CommandBindings { get; } = new List(); } /// From 947f5c3eac9ea77c5524aef861f90b7dbe3b0245 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Mon, 18 Mar 2024 21:05:42 -0700 Subject: [PATCH 2/2] Fix after self-review --- src/AvaloniaEdit/Search/SearchPanel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AvaloniaEdit/Search/SearchPanel.cs b/src/AvaloniaEdit/Search/SearchPanel.cs index 66224ede..42f88896 100644 --- a/src/AvaloniaEdit/Search/SearchPanel.cs +++ b/src/AvaloniaEdit/Search/SearchPanel.cs @@ -560,7 +560,7 @@ protected virtual void OnSearchOptionsChanged(SearchOptionsChangedEventArgs e) SearchOptionsChanged?.Invoke(this, e); } - public IList CommandBindings { get; } = new List(); + public IList CommandBindings => CommandManager.GetCommandBindings(this); } ///