Why doesn't setting MenuItem.InputGestureText cause the MenuItem to activate when I perform the input gesture?

后端 未结 3 1229
清酒与你
清酒与你 2021-01-18 14:22

I want to implement Keyboard shortcuts for a MenuItem. I have used the code below:



        
相关标签:
3条回答
  • 2021-01-18 15:01

    The best way to do this is to make a Command, and associate the InputGesture with that command:

    public static class Commands
    {
        public static readonly RoutedCommand CreateNew = new RoutedCommand("New", typeof(Commands));
    
        static Commands()
        {
            SomeCommand.InputGestures.Add(new KeyGesture(Key.N, ModifierKeys.Control));
        }
    }
    
    ...
    
    // Wherever you want to create the MenuItem. "local" should be the namespace that
    // you delcared "Commands" in.
    <MenuItem Header="_New" Command="{x:Static local:Commands.CreateNew}">
    
    ...
    
    // Wherever you want to process the command. I am assuming you want to do it in your 
    // main window, but you can do it anywhere in the route between your main window and 
    // the menu item.
    <Window.CommandBindings>
        <CommandBinding Command="{x:Static local:Commands.CreateNew}"> Executed="CreateNew_Executed" />
    </Window.CommandBindings>
    
    ...
    
    // In the code behind for your main window (or whichever file you put the above XAML in)
    private void CreateNew(object sender, ExecutedRoutedEventArgs e)
    {
        ...
    }
    

    If you really just want a "New" command, you can skip creating the RoutedCommand and InputGesture, because that command is already created for you:

    <MenuItem Header="_New" Command="New">
    
    ...
    
    <Window.CommandBindings>
        <CommandBinding Command="New" Executed="New_Executed" />
    </Window.CommandBindings>
    
    ...
    
    private void New_Executed(object sender, ExecutedRoutedEventArgs e)
    {
        ...
    }
    
    0 讨论(0)
  • 2021-01-18 15:02

    It is quite explicit in the documentation for the property:

    This property does not associate the input gesture with the menu item; it simply adds text to the menu item. The application must handle the user's input to carry out the action. For information on how to associate a command with a menu item, see Command.

    0 讨论(0)
  • 2021-01-18 15:19

    One solution that doesn't involve commands and bindings is to override the owning Window's OnKeyDown method and search a menu item that has a KeyGesture that matches the keyboard event.

    Here is the code for the Window's OnKeyDown override:

    protected override void OnKeyDown(KeyEventArgs e)
    {
        base.OnKeyDown(e);
    
        // here I suppose the window's menu is named "MainMenu"
        MainMenu.RaiseMenuItemClickOnKeyGesture(e);
    }
    

    And here is the utility code that matches a menu item with the keyboard event:

        public static void RaiseMenuItemClickOnKeyGesture(this ItemsControl control, KeyEventArgs args) => RaiseMenuItemClickOnKeyGesture(control, args, true);
        public static void RaiseMenuItemClickOnKeyGesture(this ItemsControl control, KeyEventArgs args, bool throwOnError)
        {
            if (args == null)
                throw new ArgumentNullException(nameof(args));
    
            if (control == null)
                return;
    
            var kgc = new KeyGestureConverter();
            foreach (var item in control.Items.OfType<MenuItem>())
            {
                if (!string.IsNullOrWhiteSpace(item.InputGestureText))
                {
                    KeyGesture gesture = null;
                    if (throwOnError)
                    {
                        gesture = kgc.ConvertFrom(item.InputGestureText) as KeyGesture;
                    }
                    else
                    {
                        try
                        {
                            gesture = kgc.ConvertFrom(item.InputGestureText) as KeyGesture;
                        }
                        catch
                        {
                        }
                    }
    
                    if (gesture != null && gesture.Matches(null, args))
                    {
                        item.RaiseEvent(new RoutedEventArgs(MenuItem.ClickEvent));
                        args.Handled = true;
                        return;
                    }
                }
    
                RaiseMenuItemClickOnKeyGesture(item, args, throwOnError);
                if (args.Handled)
                    return;
            }
        }
    
    0 讨论(0)
提交回复
热议问题