Respostas:
Uma maneira é adicionar as teclas de atalho aos próprios comandos, como InputGestures
. Comandos são implementados como RoutedCommands
.
Isso permite que as teclas de atalho funcionem mesmo se não estiverem conectadas a nenhum controle. E como os itens de menu entendem os gestos do teclado, eles exibirão automaticamente sua tecla de atalho no texto dos itens de menu, se você conectar esse comando ao item de menu.
Crie um atributo estático para armazenar um comando (de preferência como uma propriedade em uma classe estática criada para comandos - mas, para um exemplo simples, basta usar um atributo estático em window.cs):
public static RoutedCommand MyCommand = new RoutedCommand();
Adicione as teclas de atalho que devem chamar o método:
MyCommand.InputGestures.Add(new KeyGesture(Key.S, ModifierKeys.Control));
Crie uma ligação de comando que aponte para o seu método para chamar na execução. Coloque-os nas ligações de comando do elemento da interface do usuário sob o qual ele deve trabalhar (por exemplo, a janela) e o método:
<Window.CommandBindings>
<CommandBinding Command="{x:Static local:MyWindow.MyCommand}" Executed="MyCommandExecuted"/>
</Window.CommandBindings>
private void MyCommandExecuted(object sender, ExecutedRoutedEventArgs e) { ... }
Executed
código do comando terminará no code-behind (da janela ou no controle do usuário), e não no modelo de visualização, em vez de usar um comando usual ( ICommand
implementação personalizada ).
Eu achei que isso era exatamente o que eu estava procurando relacionado à ligação de chaves no WPF:
<Window.InputBindings>
<KeyBinding Modifiers="Control"
Key="N"
Command="{Binding CreateCustomerCommand}" />
</Window.InputBindings>
Ver postagem no blog MVVM CommandReference and KeyBinding
Experimente este código ...
Primeiro, crie um objeto RoutedComand
RoutedCommand newCmd = new RoutedCommand();
newCmd.InputGestures.Add(new KeyGesture(Key.N, ModifierKeys.Control));
CommandBindings.Add(new CommandBinding(newCmd, btnNew_Click));
Depende de onde você deseja usá-los.
TextBoxBase
controles derivados já implementam esses atalhos. Se você quiser usar atalhos de teclado personalizados, consulte os gestos de comandos e entrada. Aqui está um pequeno tutorial do Switch on the Code : Tutorial do WPF - Ligações de comandos e comandos personalizados
Documentar essa resposta para outras pessoas, pois existe uma maneira muito mais simples de fazer isso, que raramente é referenciada e que não exige o toque no XAML.
Para vincular um atalho de teclado, no construtor Window, adicione um novo KeyBinding à coleção InputBindings. Como o comando, passe sua classe de comando arbitrária que implementa o ICommand. Para o método execute, simplesmente implemente a lógica que você precisa. No meu exemplo abaixo, minha classe WindowCommand leva um delegado que será executado sempre que chamado. Quando eu construo o novo WindowCommand para passar com minha ligação, eu simplesmente indico no meu inicializador, o método que eu quero que o WindowCommand execute.
Você pode usar esse padrão para criar seus próprios atalhos de teclado rápidos.
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)));
...
}
Crie uma classe WindowCommand simples, que leva um delegado de execução para disparar qualquer método definido nela.
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();
}
}
}
Eu tive um problema semelhante e achei a resposta da @ aliwa a solução mais útil e elegante; no entanto, eu precisava de uma combinação de teclas específica, Ctrl+ 1. Infelizmente, recebi o seguinte erro:
'1' não pode ser usado como um valor para 'Chave'. Os números não são valores de enumeração válidos.
Com um pouco mais de pesquisa, modifiquei a resposta da @ aliwa para o seguinte:
<Window.InputBindings>
<KeyBinding Gesture="Ctrl+1" Command="{Binding MyCommand}"/>
</Window.InputBindings>
Achei que isso funcionou muito bem para qualquer combinação que eu precisasse.
<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))
Não é necessário XAML.
Embora as respostas principais estejam corretas, eu pessoalmente gosto de trabalhar com propriedades anexadas para permitir que a solução seja aplicada a qualquer uma UIElement
, especialmente quando ela Window
não está ciente do elemento que deve ser focado. Na minha experiência, muitas vezes vejo uma composição de vários modelos de visualização e controles de usuário, em que a janela geralmente nada mais é que o contêiner raiz.
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));
}
}
}
Com esta propriedade anexada, você pode definir um atalho de foco para qualquer UIElement. Ele registrará automaticamente a ligação de entrada na janela que contém o elemento.
<TextBox x:Name="SearchTextBox"
Text={Binding Path=SearchText}
local:AttachedProperties.FocusShortcutKey="Ctrl+Q"/>
A amostra completa, incluindo a implementação do FocusElementCommand, está disponível como gist: https://gist.github.com/shuebner20/c6a5191be23da549d5004ee56bcc352d
Isenção de responsabilidade: Você pode usar este código em qualquer lugar e gratuitamente. Lembre-se de que esta é uma amostra que não é adequada para uso pesado. Por exemplo, não há coleta de lixo de elementos removidos porque o Comando manterá uma forte referência ao elemento.
Como associar o comando a MenuItem
:
<MenuItem Header="My command" Command="{x:Static local:MyWindow.MyCommand}"/>