Комбінації клавіш у WPF


129

Я знаю про використання _замість &, але я переглядаю всі Ctrlярлики типу +.

Ctrl+ Zдля скасування, Ctrl+ Sдля збереження тощо

Чи існує "стандартний" спосіб їх застосування у додатках WPF? Або це випадок згорнути свої власні та підключити їх до будь-якої команди / контролю?

Відповіді:


170

Одним із способів є додавання клавіш швидкого доступу до самих команд їх як InputGestures. Команди реалізовані як RoutedCommands.

Це дає можливість клавішам швидкого доступу працювати, навіть якщо вони не підключені до будь-яких елементів керування. А оскільки пункти меню розуміють жести клавіатури, вони автоматично відображають вашу клавішу швидкого доступу в тексті пунктів меню, якщо ви підключите цю команду до пункту меню.

  1. Створіть статичний атрибут для вміщення команди (бажано як властивість статичного класу, який ви створюєте для команд - але для простого прикладу, просто використовуючи статичний атрибут у window.cs):

     public static RoutedCommand MyCommand = new RoutedCommand();
  2. Додайте клавіші швидкого доступу, які повинні викликати метод:

     MyCommand.InputGestures.Add(new KeyGesture(Key.S, ModifierKeys.Control));
  3. Створіть прив'язку команд, яка вказує на ваш метод для виклику Execute. Помістіть їх у прив’язки команд для елемента інтерфейсу, під яким він повинен працювати (наприклад, вікно) та методу:

     <Window.CommandBindings>
         <CommandBinding Command="{x:Static local:MyWindow.MyCommand}" Executed="MyCommandExecuted"/>
     </Window.CommandBindings>
    
     private void MyCommandExecuted(object sender, ExecutedRoutedEventArgs e) { ... }

4
Як я пов’язую команду з пунктом меню? Звичайно, це була б найважливіша інформація, яку слід включити до цієї відповіді, але вона відсутня.
Тімві

8
@Timwi: я використав код вище таким чином, щоб додати ярлик клавіатури до вже наявної події: RoutedCommand cmndSettings = новий RoutedCommand (); cmndSettings.InputGestures.Add (новий KeyGesture (Key.S, ModifierKeys.Control)); CommandBindings.Add (новий CommandBinding (cmndSettings, mnuSettings_Click));
itho

1
коментар itsho зробив цю роботу для мене, не міг зробити XML-код вище роботи.
gosr

1
На жаль, при такому підході Executedкод для команди опиниться в кодовій частині (вікна або керування користувачем), а не у моделі view, на відміну від звичайної команди (користувацька ICommandреалізація).
АБО Mapper


97

Я виявив, що це саме те, що я шукав, пов'язане з прив'язкою ключів у WPF:

<Window.InputBindings>
        <KeyBinding Modifiers="Control"
                    Key="N"
                    Command="{Binding CreateCustomerCommand}" />
</Window.InputBindings>

Дивіться повідомлення в блозі MVVM CommandReference та KeyBinding


Дуже приємно і просто!
злиття

1
Ви б не хотіли детальніше розглянути питання про те, що таке "CreateCustomerCommand" і як це потрібно реалізувати?
Вінц

Це все ще відповідь лише за посиланням, оскільки фрагмент копіюваного та вставленого коду описується написом "Результат буде винятком" у пов'язаній публікації блогу. : P
Мартін Шнайдер

Тут працює диво. Я спершу спробував додати "_" перед клавішею вмісту кнопки, як ОП, але це не вийшло. Найгірше, що він активується, коли я натискаю на сам ключ, коли я не зосереджувався на об'єкті інтерфейсу, що записується .. як "s" для збереження, а не ctrl-s.
Джей

14

Спробуйте цей код ...

Спочатку створіть об’єкт RoutedComand

  RoutedCommand newCmd = new RoutedCommand();
  newCmd.InputGestures.Add(new KeyGesture(Key.N, ModifierKeys.Control));
  CommandBindings.Add(new CommandBinding(newCmd, btnNew_Click));

9

Це залежить від того, де ви хочете їх використовувати.

TextBoxBase-похідні елементи керування вже реалізують ці ярлики. Якщо ви хочете використовувати спеціальні комбінації клавіш, слід ознайомитися з жестами команд та введення. Ось невеликий підручник із програми « Увімкнути код» : Підручник WPF - Прив’язки команд та спеціальні команди


8
Що підручник з дерьмом - не пояснює абсолютно найважливішого з усіх, що полягає в тому, як використовувати команду, яка, можливо, не є однією з їх заздалегідь визначеного набору з 20 "загальних" команд.
Тімві

6

Задокументуючи цю відповідь для інших, оскільки існує набагато простіший спосіб зробити це, на який посилаються рідко, і зовсім не потрібно торкатися XAML.

Щоб зв’язати комбінацію клавіш, у конструкторі Window просто додайте нову сполучення клавіш до колекції InputBindings. В якості команди введіть свій довільний клас команд, який реалізує ICommand. Для методу Execute просто реалізуйте будь-яку логіку, яка вам потрібна. У наведеному нижче прикладі мій клас WindowCommand приймає делегата, який він буде виконувати кожного разу, коли викликається. Коли я будую новий WindowCommand для передачі з моїм прив'язкою, я просто вказую в своєму ініціалізаторі метод, який я хочу виконати WindowCommand.

Ви можете використовувати цю схему, щоб створити власні швидкі комбінації клавіш.

public YourWindow() //inside any WPF Window constructor
{
   ...
   //add this one statement to bind a new keyboard command shortcut
   InputBindings.Add(new KeyBinding( //add a new key-binding, and pass in your command object instance which contains the Execute method which WPF will execute
      new WindowCommand(this)
      {
         ExecuteDelegate = TogglePause //REPLACE TogglePause with your method delegate
      }, new KeyGesture(Key.P, ModifierKeys.Control)));
   ...
}

Створіть простий клас WindowCommand, який приймає делегата виконання, щоб звільнити будь-який метод, встановлений на ньому.

public class WindowCommand : ICommand
{
    private MainWindow _window;

    //Set this delegate when you initialize a new object. This is the method the command will execute. You can also change this delegate type if you need to.
    public Action ExecuteDelegate { get; set; }

    //You don't have to add a parameter that takes a constructor. I've just added one in case I need access to the window directly.
    public WindowCommand(MainWindow window)
    {
        _window = window;
    }

    //always called before executing the command, mine just always returns true
    public bool CanExecute(object parameter)
    {
        return true; //mine always returns true, yours can use a new CanExecute delegate, or add custom logic to this method instead.
    }

    public event EventHandler CanExecuteChanged; //i'm not using this, but it's required by the interface

    //the important method that executes the actual command logic
    public void Execute(object parameter)
    {
        if (ExecuteDelegate != null)
        {
            ExecuteDelegate();
        }
        else
        {
            throw new InvalidOperationException();
        }
    }
}

5

У мене була подібна проблема, і відповідь @ Aliwa виявилося найбільш корисним та найелегантнішим рішенням; однак мені потрібна була певна комбінація клавіш Ctrl+ 1. На жаль, я отримав таку помилку:

'1' не можна використовувати як значення для 'Key'. Числа не є дійсними значеннями перерахування.

Трохи в подальшому пошуку я змінив відповідь @ aliwa на наступне:

<Window.InputBindings>
    <KeyBinding Gesture="Ctrl+1" Command="{Binding MyCommand}"/>
</Window.InputBindings>

Я виявив, що це чудово працює для будь-якої комбінації, яка мені потрібна.


Це працювало для мене<UserControl.InputBindings> <KeyBinding Gesture="Enter" Command="{Binding someCommand}"/> </UserControl.InputBindings>
fs_tigre

3

VB.NET:

Public Shared SaveCommand_AltS As New RoutedCommand

Всередині завантаженої події:

SaveCommand_AltS.InputGestures.Add(New KeyGesture(Key.S, ModifierKeys.Control))

Me.CommandBindings.Add(New CommandBinding(SaveCommand_AltS, AddressOf Me.save))

XAML не потрібен.


1

Хоча верхні відповіді правильні, мені особисто подобається працювати з доданими властивостями, щоб рішення можна було застосувати до будь-якого UIElement, особливо коли Windowне знають про елемент, на який слід зосередити увагу. На моєму досвіді я часто бачу композицію з декількох моделей перегляду та елементів керування користувачами, де вікно часто є не що інше, як кореневий контейнер.

Знімок

public sealed class AttachedProperties
{
    // Define the key gesture type converter
    [System.ComponentModel.TypeConverter(typeof(System.Windows.Input.KeyGestureConverter))]
    public static KeyGesture GetFocusShortcut(DependencyObject dependencyObject)
    {
        return (KeyGesture)dependencyObject?.GetValue(FocusShortcutProperty);
    }

    public static void SetFocusShortcut(DependencyObject dependencyObject, KeyGesture value)
    {
        dependencyObject?.SetValue(FocusShortcutProperty, value);
    }

    /// <summary>
    /// Enables window-wide focus shortcut for an <see cref="UIElement"/>.
    /// </summary>
    // Using a DependencyProperty as the backing store for FocusShortcut.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty FocusShortcutProperty =
        DependencyProperty.RegisterAttached("FocusShortcut", typeof(KeyGesture), typeof(AttachedProperties), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.None, new PropertyChangedCallback(OnFocusShortcutChanged)));

    private static void OnFocusShortcutChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (!(d is UIElement element) || e.NewValue == e.OldValue)
            return;

        var window = FindParentWindow(d);
        if (window == null)
            return;

        var gesture = GetFocusShortcut(d);
        if (gesture == null)
        {
            // Remove previous added input binding.
            for (int i = 0; i < window.InputBindings.Count; i++)
            {
                if (window.InputBindings[i].Gesture == e.OldValue && window.InputBindings[i].Command is FocusElementCommand)
                    window.InputBindings.RemoveAt(i--);
            }
        }
        else
        {
            // Add new input binding with the dedicated FocusElementCommand.
            // see: https://gist.github.com/shuebner20/349d044ed5236a7f2568cb17f3ed713d
            var command = new FocusElementCommand(element);
            window.InputBindings.Add(new InputBinding(command, gesture));
        }
    }
}

За допомогою цього доданого властивості ви можете визначити ярлик фокусу для будь-якого UIElement. Він автоматично зареєструє прив'язку входу у вікні, що містить елемент.

Використання (XAML)

<TextBox x:Name="SearchTextBox"
         Text={Binding Path=SearchText}
         local:AttachedProperties.FocusShortcutKey="Ctrl+Q"/>

Вихідний код

Повний зразок, включаючи реалізацію FocusElementCommand, доступний у вигляді суті: https://gist.github.com/shuebner20/c6a5191be23da549d5004ee56bcc352d

Відмова від відповідальності: Ви можете користуватися цим кодом скрізь і безкоштовно. Майте на увазі, що це зразок, який не підходить для інтенсивного використання. Наприклад, немає збирання сміття видалених елементів, оскільки команда буде чітко посилатися на елемент.


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.