Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MenuItem HotKey only works after the menu item has been displayed at least once. #2441

Open
Michron opened this issue Apr 10, 2019 · 10 comments
Assignees
Labels

Comments

@Michron
Copy link
Contributor

Michron commented Apr 10, 2019

It looks like this is the same issue which was fixed in #290.
If the HotKey property of a MenuItem is set, it will not work until the user has opened the menu which contains that MenuItem.

To reproduce the bug simply add the following changes to the Menu sample in the ControlCatalog.
In MenuItemViewModel.cs

    public class MenuItemViewModel
    {
        public string Header { get; set; }
        public ICommand Command { get; set; }
        public object CommandParameter { get; set; }
        public IList<MenuItemViewModel> Items { get; set; }
        // Add the Gesture property.
        public KeyGesture Gesture { get; set; }
    }

In MenuPage.xaml:

                <TextBlock Classes="h3" Margin="4 8">Dyanamically generated</TextBlock>
                <Menu Items="{Binding MenuItems}">
                    <Menu.Styles>
                        <Style Selector="MenuItem">
                            <Setter Property="Header" Value="{Binding Header}"/>
                            <Setter Property="Items" Value="{Binding Items}"/>
                            <Setter Property="Command" Value="{Binding Command}"/>
                            <Setter Property="CommandParameter" Value="{Binding CommandParameter}"/>
                            <!-- Add a binding for the HotKey property -->
                            <Setter Property="HotKey" Value="{Binding Gesture}"/>
                        </Style>
                    </Menu.Styles>
                </Menu>

In MenuPageViewModel.cs

                    Items = new[]
                    {
                        new MenuItemViewModel { Header = "_Open...", Command = OpenCommand },
                        // Assign a gesture to the Save command.
                        new MenuItemViewModel
                        {
                            Header = "Save",
                            Command = SaveCommand,
                            Gesture = new Avalonia.Input.KeyGesture(Avalonia.Input.Key.S, Avalonia.Input.InputModifiers.Control)
                        },
                        new MenuItemViewModel { Header = "-" },
                        // The rest of the items....

With these changes, run the ControlCatalog.Desktop project, and go to the Menu page. Press Ctrl+S and notice that nothing will be printed in the output. Open the menu which contains the Save command, and press Ctrl+S again. This time it will print Save in the output.

@Gillibald
Copy link
Contributor

I don't think that these hotkeys should work when the menu isn't open (focused). What you want are global hotkeys(global commands).

@Michron
Copy link
Contributor Author

Michron commented Apr 10, 2019

If that would be the desired behavior, I would expect that the hotkeys would stop working if the menu is closed again. But they keep working even when the menu is closed again.

@Gillibald
Copy link
Contributor

Gillibald commented Apr 10, 2019

I think unless you change focus the menu still listens to input gestures. There are plans for a global menu. That should probably always listen to input gestures.

@Michron
Copy link
Contributor Author

Michron commented Apr 10, 2019

I've ran another test to see what happens if the focus is changed. After opening the menu once it doesn't matter what is focused, the hotkey still works. Even after switching to different pages and while typing inside a TextBox. My guess is that it only stops working if nothing is focused at all, but I didn't find a way to test that in the Control Gallery.

@grokys grokys added the bug label Apr 11, 2019
@grokys grokys self-assigned this Apr 11, 2019
@grokys grokys added this to To do in @grokys todos via automation Apr 11, 2019
@Michron
Copy link
Contributor Author

Michron commented Apr 12, 2019

Additionally I've found that if you press the Save command in the menu, and then press Ctrl+S it also doesn't execute the command. It looks like the key up and down event is not consumed by anything despite the MenuItem being focused.

@grokys
Copy link
Member

grokys commented Apr 12, 2019

This appears to happen because when using bindings to create the MenuItems, the items are not materialized until the Popup is opened.

I notice that WPF does not have HotKey binding for menu items and you seem to need to do this manually in the containing Window - I think WPF has the same behavior as us here, so this might be the reason for their lack of hotkey handling.

I'll need to have a bit more of a think about potential fixes to this.

@grokys grokys added this to the 0.9 milestone Jun 25, 2019
@grokys grokys added this to To do in 0.9 Release Jul 27, 2019
@grokys
Copy link
Member

grokys commented Jul 27, 2019

@kekekeks is currently refactoring Popups to always dispose of their content when a popup is closed. This is only going to make this worse.

I think the only solution is to remove MenuItem.HotKey and add InputBindings as in WPF.

@grokys grokys removed this from the 0.9 milestone Sep 9, 2019
@grokys grokys removed this from To do in 0.9 Release Sep 9, 2019
@grokys grokys added this to the 0.10 milestone Sep 9, 2019
@robloo
Copy link
Contributor

robloo commented Sep 14, 2019

Instead of InputBindings in might be good to look at the 'updated' concept of KeyboardAccelerator from UWP.

https://docs.microsoft.com/en-us/windows/uwp/design/input/keyboard-accelerators
https://docs.microsoft.com/en-us/windows/uwp/design/input/keyboard-interactions

Oh, and then there is gestures for special touch input :)

@Raymonf
Copy link

Raymonf commented Nov 24, 2022

A workaround is to use KeyBindings on the window, if anyone finds this thread in the future:

<Window.KeyBindings>
    <KeyBinding Gesture="Ctrl+O" Command="{Binding OpenCommand}" />
</Window.KeyBindings>

@seleborg
Copy link

seleborg commented Jun 6, 2024

I use the following method, which also seems to work, and which doesn't require duplicating the keyboard shortcut descriptions:

In MainWindow.xaml:

    <Menu DockPanel.Dock="Top" Name="MainMenu">
      <MenuItem Header="_File">
        <MenuItem Header="_Open..."
                  InputGesture="Ctrl+O"
                  Name="OpenMenuItem"
                  Command="{Binding OpenCommand}"/>
      </MenuItem>
    </Menu>

In MainWindow.xaml.cs:

public partial class MainWindow : Window {
  public MainWindow() {
    InitializeComponent();
  }

  protected override void OnLoaded(RoutedEventArgs _) {
    // At this point, all bindings are resolved, including menu items' .Command properties.
    if (DataContext is MainWindowViewModel vm) {
      RegisterHotKeys(MainMenu);
    }
  }

  void RegisterHotKeys(Control control) {
    if (control is MenuItem item) {
      if (item.InputGesture != null && item.Command != null) {
        KeyBindings.Add(new KeyBinding() {
          Gesture = item.InputGesture,
          Command = item.Command
        });
      }
    }

    foreach (Control child in control.GetLogicalChildren()) {
      RegisterHotKeys(child);
    }
  }
}

This solution assumes that the DataContext doesn't change, otherwise you'd have to unregister and re-register the hotkeys. For a main window, this should work, though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

7 participants