web-dev-qa-db-fra.com

Définition des raccourcis MenuItem

J'ai besoin d'un moyen simple de définir un raccourci pour les éléments de menu.

Mais cela ne fonctionne pas avec un raccourci, juste avec un clic:

<MenuItem Header="Editar">
    <MenuItem Header="Procurar" Name="MenuProcurar"
              InputGestureText="Ctrl+F"
              Click="MenuProcurar_Click">
        <MenuItem.ToolTip>
            <ToolTip>
                Procurar
            </ToolTip>
        </MenuItem.ToolTip>
    </MenuItem>
</MenuItem>

J'utilise WPF 4.0

46

Vous devez utiliser KeyBindings (et CommandBindings si vous (ré) utilisez RoutedCommands = tels que ceux trouvés dans la classe ApplicationCommands ) pour cela dans les contrôles où les raccourcis devraient fonctionner.

par exemple.

<Window.CommandBindings>
        <CommandBinding Command="New" Executed="CommandBinding_Executed" />
</Window.CommandBindings>
<Window.InputBindings>
        <KeyBinding Key="N" Modifiers="Control" Command="New"/>
</Window.InputBindings>

Pour RoutedCommands personnalisé:

static class CustomCommands
{
    public static RoutedCommand DoStuff = new RoutedCommand();
}

usage:

<Window
    ...
    xmlns:local="clr-namespace:MyNamespace">
        <Window.CommandBindings>
                <CommandBinding Command="local:CustomCommands.DoStuff" Executed="DoStuff_Executed" />
        </Window.CommandBindings>
        <Window.InputBindings>
                <KeyBinding Key="D" Modifiers="Control" Command="local:CustomCommands.DoStuff"/>
        </Window.InputBindings>
    ...
</Window>

(Il est souvent plus pratique d'implémenter l'interface ICommand plutôt que d'utiliser RoutedCommands. Vous pouvez avoir un constructeur qui prend les délégués pour Execute et CanExecute pour créer facilement des commandes qui font différentes choses, ces implémentations sont souvent appelées DelegateCommand ou RelayCommand. De cette façon, vous n'avez pas besoin de CommandBindings.)

58
H.B.

H.B. avait raison ... Je voulais juste ajouter plus de précisions.

Supprimez l'événement Click de votre MenuItem et associez-le à la place à un Command.

1 - Ajoutez/créez vos commandes:

<Window.CommandBindings>
     <CommandBinding Command="Open" Executed="OpenCommandBinding_Executed"/>
     <CommandBinding Command="SaveAs" Executed="SaveAsCommandBinding_Executed"/>
</Window.CommandBindings>

Les commandes font référence au code suivant:

private void OpenCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
    Open();//Implementation of open file
}
private void SaveAsCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
    SaveAs();//Implementation of saveAs
}

2 - Associez les commandes aux touches souhaitées:

<Window.InputBindings>
    <KeyBinding Key="O" Modifiers="Control" Command="Open"/>
    <KeyBinding Key="S" Modifiers="Control" Command="SaveAs"/>
</Window.InputBindings>

3 - Enfin, affectez les commandes avec votre élément de menu (InputGestureText n'est qu'un texte de décoration):

<Menu Name="menu1">
    <MenuItem Header="_File">
        <MenuItem Name="menuOpen" Header="_Open..." Command="Open" InputGestureText="Ctrl+O"/>
        <MenuItem Name="menuSaveAs" Header="_Save as..." Command="SaveAs" InputGestureText="Ctrl+S"/>
    </MenuItem>
</Menu>

De cette façon, plusieurs entrées peuvent être associées à la même commande.

57
Guish

À mon humble avis, il est beaucoup plus facile d'utiliser simplement _ à l'en-tête. Cela créera automatiquement la touche d'accès rapide souhaitée.

Par exemple:

<MenuItem Header="_Editar">
<MenuItem Header="_Procurar" Name="MenuProcurar"
          InputGestureText="Ctrl+F"
          Click="MenuProcurar_Click">
    <MenuItem.ToolTip>
        <ToolTip>
            Procurar
        </ToolTip>
    </MenuItem.ToolTip>
</MenuItem>
</MenuItem>
11

Vous pouvez également déclarer RoutedUICommand en XAML:

<Window.Resources>
    <RoutedUICommand x:Key="BuildCmd" Text="Build">
        <RoutedUICommand.InputGestures>
            <KeyGesture>CTRL+SHIFT+B</KeyGesture>
        </RoutedUICommand.InputGestures>
    </RoutedUICommand>      
</Window.Resources>

Faire la reliure

<Window.CommandBindings>
    <CommandBinding Command="{StaticResource BuildCmd}" Executed="BuildCmdExecuted"/>
</Window.CommandBindings>

Et dans MenuItem

<MenuItem Command="{StaticResource BuildCmd}"/>

Une autre solution est discutée ici .

8
Eliko

Je suis trop biaisé par Windows.Forms & gulp VB 6, donc je sorte de d'accord avec Jonathan et Jase qu'il doit y avoir une méthode plus simple/procédurale pour câbler statiquement les gestionnaires d'événements qui ne sont pas nécessairement CommandBindings. Et il y en a, je pense.

Un bon tutoriel pour l'utilisation de gestionnaires non -CommandBinding comme celui-ci, mais en mettant l'accent sur les boutons, peut être trouvé dans ce blog MSDN , je crois. Je distillerai et viserai MenuItems ...

Création de l'ICommand

Créez d'abord une classe implémentant ICommand. Vous pouvez le mettre n'importe où, bien sûr, même dans votre fichier MainWindow.xaml.cs si vous le souhaitez, pour garder votre code de démonstration incroyablement simple. Vous voudrez probablement rendre CanExecute plus compliqué lorsque vous souhaitez désactiver/activer/désactiver les éléments de menu plus tard, mais pour l'instant, nous aurons toujours toujours nos éléments de menu activés.

public class HelloWorldCommand : ICommand
{
    public void Execute(object parameter)
    {
        MessageBox.Show(@"""Hello, world!"" from " 
            + (parameter ?? "somewhere secret").ToString());
    }

    public bool CanExecute(object parameter)
    {
        return true;
    }

    public event EventHandler CanExecuteChanged;
} 

Comme le tutoriel le souligne, vous pouvez déjà appeler cette commande depuis n'importe où, avec du code comme ...

var hwc = new HelloWorldCommand();
if (hwc.CanExecute(this))
    hwc.Execute(this);

Déclarer votre commande dans la fenêtre

Ajoutons donc une sorte de "déclaration" pour le HelloWorldCommand à notre fenêtre afin de pouvoir l'utiliser plus tard. À l'intérieur de vos balises Window, enregistrez la commande en tant que ressource:

<Window.Resources>
    <local:HelloWorldCommand x:Key="hwc"/>
</Window.Resources>

Nous avons maintenant un raccourci soigné pour créer un lien vers cette commande "localement nommée", "hwc", Bien que vous puissiez évidemment utiliser n'importe quelle chaîne de votre choix. Nous l'utiliserons beaucoup dans notre xaml.

Câblage (et réutilisation!) De la commande

Ajoutons nos MenuItems à notre xaml. J'ai remplacé le stock Grid par un DockPanel parce que c'est le moyen le plus simple (pour moi) d'avoir des widgets équidistants qui remplissent le Window, bien que je sois parti tout le reste de mon interface utilisateur.

Notez les Command="{StaticResource hwc}" S saupoudrés dans chaque déclaration MenuItem. La clé est le hwc là-dedans - rappelez-vous que c'est notre raccourci pour le HelloWorldCommand que nous avons configuré au Window niveau. Et, bien sûr, StaticResource dit simplement de rechercher les ressources de Window. Nous ne lions rien; nous utilisons simplement notre raccourci.

<DockPanel LastChildFill="True">
    <Menu DockPanel.Dock="Top">
        <MenuItem Header="_File">
            <MenuItem 
                Header="_Open" 
                Command="{StaticResource hwc}" 
            >
                <MenuItem.CommandParameter>
                    <!-- so you could make this object as complex as you wanted, 
                        like, say, your entire Window. See magic incantation, below. -->
                    <Binding RelativeSource="{RelativeSource FindAncestor, AncestorType=Window}" />
                </MenuItem.CommandParameter>

            </MenuItem>

            <MenuItem 
                Header="_Close" 
                Command="{StaticResource hwc}" 
                CommandParameter="Close"
                InputGestureText="Ctrl+G" />

            <MenuItem 
                Header="_Save" 
                Command="{StaticResource hwc}" 
                CommandParameter="Save" />

            <Separator />

            <MenuItem 
                Header="_Quit" 
                Command="{StaticResource hwc}" 
                CommandParameter="Quit" />
        </MenuItem>
</DockPanel>

CommandParameters pour distinguer les sources d'événements

Notez que nous utilisons la même commande pour tout! Mais comment savoir quel widget a déclenché l'événement? Pour cela, vous devez utiliser la CommandParameter - rappelez-vous la signature de notre méthode Execute: Execute(object parameter). Ce paramètre CommandParameter est ce que nous pouvons utiliser pour savoir comment gérer l'événement. Essayez d'exécuter ceci et notez que MessageBox utilisera tout ce qui se trouve dans CommandParameter pour vous informer de la source de l'événement. Nous faisons tout manuellement, mais ce n'est pas trop mal.

Notez également que vous pouvez rendre ces objets aussi compliqués que vous le souhaitez. Vous pouvez utiliser une propriété de la balise MenuItem pour définir le paramètre, ou utiliser des balises <MenuItem.CommandParameter> "Réelles", comme dans l'élément de menu Ouvrir, ci-dessus, pour définir quelque chose de complexe. Dans ce cas, nous passons l'objet parent entier Window, ce qui était le plus simple (mais pas la plus propre) façon de jeter notre contexte VB6-ish dans le code du gestionnaire d'événements.

Ajout de raccourcis clavier à MenuItems (alias "Répondre à l'OP")

Et maintenant, nous pouvons enfin répondre à la question d'origine! Connectons enfin un raccourci clavier pour l'élément de menu Close. Vous remarquerez que nous avons déjà déclaré un InputGestureText. En soi, InputGestureText n'est que cosmétique . Si nous étions trop pointilleux, nous pourrions affirmer que le mécanisme de création du raccourci clavier n'a aucune relation directe et inhérente avec le MenuItem!

Nous devons plutôt (ou en plus) enregistrer un écouteur pour Ctrl-G au niveau Window pour attraper la frappe. Donc, au niveau supérieur de vos balises Windows, insérez ceci (pris essentiellement d'ici ):

<Window.InputBindings>
    <KeyBinding Modifiers="Control"
                Key="G"
                Command="{StaticResource hwc}" 
                CommandParameter="window input binding"
    />
</Window.InputBindings>

Notez que vous pouvez mettre des balises CommandParameter dans vos KeyBinding en les déplaçant d'un élément XML à fermeture automatique vers de "vraies" balises KeyBinding.

Et nous avons terminé. Exécutez votre application et appuyez sur Ctrl-G. Whaddup.

Assez simple, une fois que vous avez les joueurs droits, et beaucoup moins de reliure magique que la plupart des introductions aux commandes et MenuItems, je pense.


Astuce possible:

Le tout CommandBinding m'a un peu dérouté. C'est juste pour des types de commandes spécifiques, je crois. Autrement dit, vous ne pouvez pas simplement câbler tout Command que vous aimez. Des trucs comme ce qui se vante ici (dans ce qui est un tutoriel d'introduction décent!) ...

Cela peut ne pas être complètement évident, mais en utilisant des commandes, nous venons d'obtenir tout un tas de choses gratuitement: raccourcis clavier, texte et InputGestureText sur les éléments et WPF active/désactive automatiquement les éléments en fonction du contrôle actif et de son état. Dans ce cas, Couper et Copier sont désactivés car aucun texte n'est sélectionné, mais Coller est activé, car mon presse-papiers n'est pas vide!

... est un peu magique et pas nécessairement bon, et peut être déroutant lorsque vous êtes nouveau dans les menus WPF.

7
ruffin