Відповіді:
Одним із способів є додавання клавіш швидкого доступу до самих команд їх як InputGestures
. Команди реалізовані як RoutedCommands
.
Це дає можливість клавішам швидкого доступу працювати, навіть якщо вони не підключені до будь-яких елементів керування. А оскільки пункти меню розуміють жести клавіатури, вони автоматично відображають вашу клавішу швидкого доступу в тексті пунктів меню, якщо ви підключите цю команду до пункту меню.
Створіть статичний атрибут для вміщення команди (бажано як властивість статичного класу, який ви створюєте для команд - але для простого прикладу, просто використовуючи статичний атрибут у window.cs):
public static RoutedCommand MyCommand = new RoutedCommand();
Додайте клавіші швидкого доступу, які повинні викликати метод:
MyCommand.InputGestures.Add(new KeyGesture(Key.S, ModifierKeys.Control));
Створіть прив'язку команд, яка вказує на ваш метод для виклику Execute. Помістіть їх у прив’язки команд для елемента інтерфейсу, під яким він повинен працювати (наприклад, вікно) та методу:
<Window.CommandBindings>
<CommandBinding Command="{x:Static local:MyWindow.MyCommand}" Executed="MyCommandExecuted"/>
</Window.CommandBindings>
private void MyCommandExecuted(object sender, ExecutedRoutedEventArgs e) { ... }
Executed
код для команди опиниться в кодовій частині (вікна або керування користувачем), а не у моделі view, на відміну від звичайної команди (користувацька ICommand
реалізація).
Я виявив, що це саме те, що я шукав, пов'язане з прив'язкою ключів у WPF:
<Window.InputBindings>
<KeyBinding Modifiers="Control"
Key="N"
Command="{Binding CreateCustomerCommand}" />
</Window.InputBindings>
Дивіться повідомлення в блозі MVVM CommandReference та KeyBinding
Спробуйте цей код ...
Спочатку створіть об’єкт RoutedComand
RoutedCommand newCmd = new RoutedCommand();
newCmd.InputGestures.Add(new KeyGesture(Key.N, ModifierKeys.Control));
CommandBindings.Add(new CommandBinding(newCmd, btnNew_Click));
Це залежить від того, де ви хочете їх використовувати.
TextBoxBase
-похідні елементи керування вже реалізують ці ярлики. Якщо ви хочете використовувати спеціальні комбінації клавіш, слід ознайомитися з жестами команд та введення. Ось невеликий підручник із програми « Увімкнути код» : Підручник WPF - Прив’язки команд та спеціальні команди
Задокументуючи цю відповідь для інших, оскільки існує набагато простіший спосіб зробити це, на який посилаються рідко, і зовсім не потрібно торкатися 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();
}
}
}
У мене була подібна проблема, і відповідь @ 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>
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 не потрібен.
Хоча верхні відповіді правильні, мені особисто подобається працювати з доданими властивостями, щоб рішення можна було застосувати до будь-якого 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. Він автоматично зареєструє прив'язку входу у вікні, що містить елемент.
<TextBox x:Name="SearchTextBox"
Text={Binding Path=SearchText}
local:AttachedProperties.FocusShortcutKey="Ctrl+Q"/>
Повний зразок, включаючи реалізацію FocusElementCommand, доступний у вигляді суті: https://gist.github.com/shuebner20/c6a5191be23da549d5004ee56bcc352d
Відмова від відповідальності: Ви можете користуватися цим кодом скрізь і безкоштовно. Майте на увазі, що це зразок, який не підходить для інтенсивного використання. Наприклад, немає збирання сміття видалених елементів, оскільки команда буде чітко посилатися на елемент.
Як пов’язати команду з MenuItem
:
<MenuItem Header="My command" Command="{x:Static local:MyWindow.MyCommand}"/>