web-dev-qa-db-fra.com

Raccourcis clavier dans WPF

Je sais utiliser _ Au lieu de &, Mais je regarde tous les Ctrl + raccourcis de type.

Ctrl+Z pour annuler, Ctrl+S pour sauvegarder, etc.

Existe-t-il un moyen "standard" de les implémenter dans les applications WPF? Ou est-ce que c'est un cas de rouler le vôtre et de le câbler à n'importe quel commandement/contrôle?

120
Benjol

Je comprends que la méthode standard consiste à créer des commandes, puis à leur ajouter vos touches de raccourci en tant que InputGestures.

Cela permet aux touches de raccourci de fonctionner même si elles ne sont reliées à aucun contrôle. Et puisque les éléments de menu comprennent les gestes du clavier, ils afficheront automatiquement votre touche de raccourci dans le texte des éléments de menu, si vous liez cette commande à votre élément de menu.

  1. Créez un attribut statique pour contenir une commande (de préférence en tant que propriété dans une classe statique que vous créez pour des commandes - mais pour un exemple simple, utilisez simplement un attribut statique dans window.cs):

    public static RoutedCommand MyCommand = new RoutedCommand();
    
  2. Ajoutez la ou les touches de raccourci devant appeler la méthode:

    MyCommand.InputGestures.Add(new KeyGesture(Key.S, ModifierKeys.Control));
    
  3. Créez une liaison de commande qui pointe vers votre méthode à appeler à exécuter. Placez-les dans les liaisons de commande de l'élément d'interface utilisateur sous lequel il devrait fonctionner (par exemple, la fenêtre) et de la méthode:

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

J'ai trouvé que c'était exactement ce que je cherchais concernant la liaison de clé dans WPF:

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

Voir l'article de blog MVVM CommandReference and KeyBinding

87
oliwa

Essayez ce code ...

Commencez par créer un objet RoutedComand

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

Cela dépend où vous voulez les utiliser.

TextBoxBase- Les contrôles dérivés implémentent déjà ces raccourcis. Si vous souhaitez utiliser des raccourcis clavier personnalisés, vous devriez vous pencher sur les commandes et les gestes de saisie. Voici un petit tutoriel de Activer le code : Tutoriel WPF - Liaisons de commandes et commandes personnalisées

9
Anvaka

Documenter cette réponse pour les autres, car il existe un moyen beaucoup plus simple de le faire, rarement référencé, et ne nécessitant aucun contact avec le XAML.

Pour lier un raccourci clavier, dans le constructeur Windows, ajoutez simplement un nouveau KeyBinding à la collection InputBindings. En tant que commande, transmettez votre classe de commandes arbitraires qui implémente ICommand. Pour la méthode execute, implémentez simplement la logique dont vous avez besoin. Dans mon exemple ci-dessous, ma classe WindowCommand prend un délégué à exécuter chaque fois qu'elle est invoquée. Lorsque je construis la nouvelle WindowCommand pour qu'elle passe avec ma liaison, j'indique simplement à mon initializer la méthode que je veux que la WindowCommand exécute.

Vous pouvez utiliser ce modèle pour créer vos propres raccourcis clavier rapides.

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)));
   ...
}

Créez une classe WindowCommand simple qui oblige un délégué à l'exécution à déclencher n'importe quelle méthode définie sur celle-ci.

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();
        }
    }
}
4
Ayo I

J'ai eu un problème similaire et la réponse de @ aliwa a été trouvée comme étant la solution la plus utile et la plus élégante. cependant, j'avais besoin d'une combinaison de touches spécifique, Ctrl + 1. Malheureusement, j'ai eu l'erreur suivante:

'1' ne peut pas être utilisé comme valeur pour 'Key'. Les nombres ne sont pas des valeurs d'énumération valides.

Après quelques recherches, j'ai modifié la réponse de @ aliwa à ce qui suit:

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

J'ai trouvé que cela fonctionnait très bien pour pratiquement toutes les combinaisons dont j'avais besoin.

3
Nik

VB.NET:

Public Shared SaveCommand_AltS As New RoutedCommand

À l'intérieur de l'événement chargé:

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

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

Aucun XAML n'est nécessaire.

2
plaasmeisie

Bien que les réponses principales soient correctes, j'aime personnellement travailler avec des propriétés attachées pour permettre à la solution d'être appliquée à n'importe quel UIElement, en particulier lorsque le Window ne connaît pas l'élément à cibler. . D'après mon expérience, je vois souvent une composition de plusieurs modèles de vue et contrôles utilisateur, où la fenêtre n'est souvent rien de plus que le conteneur racine.

Fragment

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));
        }
    }
}

Avec cette propriété attachée, vous pouvez définir un raccourci de focus pour n’importe quel UIElement. Il enregistre automatiquement la liaison d’entrée dans la fenêtre contenant l’élément.

Utilisation (XAML)

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

Code source

L'exemple complet, y compris l'implémentation FocusElementCommand, est disponible en tant que Gist: https://Gist.github.com/shuebner20/c6a5191be23da549d5004ee56bcc352d

Avertissement: Vous pouvez utiliser ce code partout et gratuitement. N'oubliez pas qu'il s'agit d'un échantillon qui ne convient pas à un usage intensif. Par exemple, il n'y a pas de garbage collection d'éléments supprimés car la commande contiendra une référence forte à l'élément.

1
Sebastian Hübner