Горячие клавиши в WPF
Я знаю об использовании _
вместо &
, но я смотрю на все сочетания клавиш типа Ctrl +.
Ctrl + Z для отмены, Ctrl + S для сохранения и т.д.
Существует ли "стандартный" способ их реализации в приложениях WPF? Или это случай сворачивать свои собственные и подключать их к какой-либо команде/контролю?
Ответы
Ответ 1
Я понимаю, что стандартным способом является создание команд, а затем добавление к ним ваших клавиш быстрого доступа в виде InputGestures.
Это позволяет сочетаниям клавиш работать, даже если они не подключены к каким-либо элементам управления. А поскольку элементы меню понимают жесты клавиатуры, они автоматически отобразят вашу комбинацию клавиш в тексте элементов меню, если вы подключите эту команду к своему элементу меню.
Создайте статический атрибут для хранения команды (предпочтительно как свойство в статическом классе, который вы создаете для команд - но для простого примера, просто используя статический атрибут в 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) { ... }
Ответ 2
Я обнаружил, что это именно то, что я искал в связи с привязкой ключей в WPF:
<Window.InputBindings>
<KeyBinding Modifiers="Control"
Key="N"
Command="{Binding CreateCustomerCommand}" />
</Window.InputBindings>
См. сообщение в блоге MVVM CommandReference и связывание ключей
Ответ 3
Попробуйте этот код...
Сначала создайте объект RoutedComand
RoutedCommand newCmd = new RoutedCommand();
newCmd.InputGestures.Add(new KeyGesture(Key.N, ModifierKeys.Control));
CommandBindings.Add(new CommandBinding(newCmd, btnNew_Click));
Ответ 4
Это зависит от того, где вы хотите их использовать.
TextBoxBase
-derived элементы управления уже реализуют эти сочетания клавиш. Если вы хотите использовать пользовательские сочетания клавиш, обратите внимание на команды и жесты ввода. Вот небольшое руководство из раздела Включение кода: Руководство WPF - Привязки команд и пользовательские команды
Ответ 5
Документирование этого ответа для других, поскольку существует гораздо более простой способ сделать это, на который редко ссылаются, и не требует вообще касаться XAML.
Чтобы связать сочетание клавиш, в конструкторе Window просто добавьте новый KeyBinding в коллекцию 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 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();
}
}
}
Ответ 6
У меня была похожая проблема, и я нашел ответ @aliwa самым полезным и элегантным решением; однако мне нужна была конкретная комбинация клавиш, Ctrl + 1. К сожалению, я получил следующую ошибку:
"1" не может использоваться в качестве значения "Ключ". Числа не являются допустимыми значениями перечисления.
После небольшого поиска я изменил ответ @aliwa следующим образом:
<Window.InputBindings>
<KeyBinding Gesture="Ctrl+1" Command="{Binding MyCommand}"/>
</Window.InputBindings>
Я нашел, что это отлично работает для любой комбинации, в которой я нуждался.
Ответ 7
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 не требуется.
Ответ 8
Хотя верхние ответы верны, мне лично нравится работать с прикрепленными свойствами, чтобы разрешить применение решения к любому 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, доступен в виде gist: https://gist.github.com/shuebner20/c6a5191be23da549d5004ee56bcc352d
Отказ от ответственности: Вы можете использовать этот код везде и бесплатно. Пожалуйста, имейте в виду, что это образец, который не подходит для интенсивного использования. Например, сборка мусора удаленных элементов отсутствует, поскольку команда будет содержать строгую ссылку на этот элемент.
Ответ 9
Как связать команду с MenuItem
:
<MenuItem Header="My command" Command="{x:Static local:MyWindow.MyCommand}"/>