开发者

How to make WPF MenuBar visibile when ALT-key is pressed?

开发者 https://www.devze.com 2023-03-20 12:29 出处:网络
Today I got some new restrictions on my WPF user interface that should eliminate the permanent visibility of the MenuBar.

Today I got some new restrictions on my WPF user interface that should eliminate the permanent visibility of the MenuBar.

I thought of imitating the user interface of Windows Live Messenger. That application displays the MenuBar only if the ALT-key is pressed. And hides it again when the focus on the M开发者_运维技巧enuBar is lost.

Currently I don't have a clue how to build such a thing in WPF... is something like this possible?

Thanks in advance.


You can write a key down event on main window..

KeyDown="Window_KeyDown"

and in the code behind file..

 private void Window_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.LeftAlt || e.Key == Key.RightAlt)
            {
                myMenu.Visibility = Visibility.Visible;
            }
        }

if you want to achive this with MVVM or using bindings... you can use input key bindings

 <Window.InputBindings>
        <KeyBinding Key="LeftAlt" Command="{Binding ShowMenuCommand}"/>
        <KeyBinding Key="RightAlt" Command="{Binding ShowMenuCommand}"/>
    </Window.InputBindings>


I think that the correct implementation is with KeyUp. This is the behaviour of IE8, Vista, Windows7 and other recent MS products:

private void MainWindow_KeyUp(Object sender, KeyEventArgs e)
    {
        if (e.Key == Key.System)
        {
            if (mainMenu.Visibility == Visibility.Collapsed)
                mainMenu.Visibility = Visibility.Visible;
            else
                mainMenu.Visibility = Visibility.Collapsed;
        }
    }


Try the following solution - a better and more compact solution in WPF. This also works if your control has not the focus or if you programatically enter the menu mode via InputManager.Current.PushMenuMode(menuSite); (see the end of the post).

Add the following code to your window or user control which contains your menu myMenu - for example at the end of your constructor:

this.myMenu.Height = 0; // Initially hide the menu
InputManager.Current.EnterMenuMode += this.InputManager_MenuModeToggled;
InputManager.Current.LeaveMenuMode += this.InputManager_MenuModeToggled;

Then implement the event handler:

private void InputManager_MenuModeToggled(object sender, EventArgs e)
{
    if (!InputManager.Current.IsInMenuMode)
        this.myMenu.Height = 0; // 0 to hide the menu
    else
        this.myMenu.Height = double.NaN; // NaN to reset the height (auto height)
}

Consider the following notes:

  • Set Height=0 instead of Visiblity to Collapsed/Hidden, because if the menu is invisible then the menu mode may not will be entered when Alt key will be pressed.
  • The menu must contains at least ony item, otherwise the menu mode may not will be entered when Alt key will be pressed.
  • In my opinion this solution also applies to MVVM applications, because its UI logic and not View Model logic.

Tested with target framework .NET Framework 4.5 within a WPF app on a Windows 10 machine.

Added:

If you want to enter the menu mode programmatically you can call the menu mode via: InputManager.Current.PushMenuMode(menuSite); However I had the issue that if I call the method PushMenuMode that after then the menu mode never will be leaved. So I fixed this with following solution:

PresentationSource source = PresentationSource.FromVisual(this);
InputManager.Current.PushMenuMode(menuSite: source);
this.Menu.Focus();

RoutedEventHandler lostFocus = null;
lostFocus = (s, args) =>
{
    InputManager.Current.PopMenuMode(menuSite: source);
    this.Menu.LostFocus -= lostFocus;
};
this.Menu.LostFocus += lostFocus;


This is what I understood:

private void form_KeyDown(object sender, 
    System.Windows.Forms.KeyEventArgs e)
{
    if(e.KeyCode == Keys.Alt && /*menu is not displayed*/) 
    {
        // display menu
    } 
}

private void form_KeyUp(object sender,
    System.Windows.Forms.MouseEventArgs e)
{
    if (/*check if mouse is NOT over menu using e.X and e.Y*/)
    {
        // hide menu
    }
}

If you need something different play a little with keyboard and mouse events.


You can use the KeyDown (or Preview version if you prefer) and then check for the System key like this:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        this.KeyDown += new KeyEventHandler(MainWindow_KeyDown);
    }

    void MainWindow_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.System && (Keyboard.Modifiers & ModifierKeys.Alt) == ModifierKeys.Alt)
        {
            // ALT key pressed!
        }
    }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消