Question

I am developing a WPF UI application .

I have a menu on top of the screen, which has File, Help menuitems.

In file -> Backend features (shortcut key is ctrl + B), Exit (Ctrl + x) sub menu items.

when clicked on any sub menu item, the corresponding window opens.

So, with out using mouse, by pressing ctrl + B or Ctrl + x, how can the window be opened??

Also, how can I display a small line below the "F" in the File so that when user presses Alt + F, the File menu should be visible.

I am working on WPF using C#.

Was it helpful?

Solution

You'll want to investigate ICommand, RoutedUICommand, InputGestureCollection, and CommandManager. It a little more upfront infrastructure work, but the WPF Command pattern allows you to share a command across main menu, context menu's, button clicks, etc. With your actions written as Commands, all the places in your application that use the Command will enable/disable consistently and it add one more layer of indirection to reduce code repetition.

The following example is in VB.Net (sorry, but hopefully it should be easy to translate).

Implement each of your required actions as a class that implements ICommand:

Public Class OpenWindowCommand
  Implements ICommand

  Public Function CanExecute(parameter as Object) As Boolean Implements System.Windows.Input.ICommand.CanExecute
    'enter code that determines whether this command should be enabled or not
    'if you are listening to some backend logic that changes this state, you can
    'raise a CanExecuteChanged event
  End Function

  Public Sub Execute(parameter as Object) Implements System.Windows.Input.ICommand.Execute
     'code that you want to run for the action
  End Sub
 End Class

Create a class that stores shared instances of each of your Commands.

Public Class MyCommands
  Private Shared ReadyOnly openWindowCmd As ICommand = New OpenWindowCommand()
  Private Shared _openWindow as RoutedUICommand

  Shared Sub New()
    'static constructor
    Dim shortcut = New KeyGesture(Key.W, ModifierKeys.Control)
    RegisterCommand(_openWindow, "OpenWindow", "Open...", shortcut, AddressOf ExecuteOpenWindow, AddressOf CanExecuteOpenWindow)
    'add more commands as needed
  End Sub

  Private Shared Sub RegisterCommand(ByRef command as RoutedUICommand, ByVal name as String, ByVal text as String, ByVal gesture as KeyGesture, ByVal executeHandler as ExecutedRoutedEventHandler, ByVal canExecuteHandler as CanExecuteRoutedEventHandler)
    Dim inputs = New InputGestureCollection()
    If gesture IsNot Nothing Then inputs.Add(gesture)
    command = New RoutedUICommand(text, name, GetType(MyCommands), inputs)
    Dim binding = New CommandBinding(command, executeHandler, canExecuteHandler)
    Application.Current.MainWindow.CommandBindings.Add(binding)
    CommandManager.RegisterClassCommandBinding(GetType(Window),binding)
  End Sub

  Public Shared ReadOnly Property OpenWindow() as RoutedUICommand
    Get
      Return _openWindow
    End Get
  End Property
  Public Shared Sub ExecuteOpenWindow(sender as Object, e as ExecutedRoutedEventArgs)
    openCmd.Execute(e.Parameter)
  End Sub
  Public Shared Sub CanExecuteSave(sender as Object, e as CanExecuteRoutedEventArgs)
    e.CanExecute = openCmd.CanExecute(e.Parameter)
    e.Handled = True
  End Sub

End Class

Now in your XAML for your menu you can bind to this command:

<Window.Resources>
  <local:MyCommands x:Key="commands"/>
</Window.Resources>
...
<MenuItem Name="mnuOpenWindow" Command="{Binding Path=OpenWindow}"/>

This is a bit more than the minimal requirement to use Commands, but in a reasonably large application I've found this additional infrastructure pretty useful. Once the Commands are written and registered, binding to them in any XAML document is trivial and by exposing Shared Properties for each action through the MyCommands class you can access the commands purely in code if needed.

OTHER TIPS

To add the small line that represents the menu item's accelerator, use an underscore in the XAML:

<MenuItem Header="_File">
    <MenuItem Header="_Backend Features" />
    <MenuItem Header="E_xit" />
</MenuItem>

As for the shortcut keys, first off I would recommend not using Ctrl + X for Exit, since that is generally used for Cut. Normally exit doesn't have a shortcut key, but Pressing Alt + F4 to close the main window will have the same affect.

Regarding your actual question, you have a couple of options, but for both you need to be using Commands to implement handle your MenuItems rather than the Click event.

The first option is to set an InputBinding for each shortcut key. It would be done something like this on your main window:

For the Command attribute, you'd need to specify an expression that represents the command for that shortcut (you'd use the same Command when defining the MenuItem, too). If you have a Commands class, you could do something like the following:

static class Commands
{
    public static ICommand BackendFeaturesCommand = ...;
}

And then in XAML:

<KeyBinding Key="B" Modifiers="Control"
    Command="{x:Static Commands.BackendFeaturesCommand}" />

The other option is to define your command as a RoutedUICommand, and specify an InputGesture for it. This will take care of wiring up the shortcut key for you.

You might have a look at the ShortCutKey sample of the WPF Application Framework (WAF). It is quite simple to understand.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top