title: How to Display Working Keyboard Shortcut for Menu Items?
body: <p>I am trying to create a localizable WPF menu bar with menu items that have keyboard shortcuts - <em>not</em> accelerator keys/mnemonics (usually shown as underlined characters that can be pressed to directly select a menu item when the menu is already open), but keyboard shortcuts (usually combinations of <kbd>Ctrl</kbd> + <kbd>another key</kbd>) that are displayed right-aligned next to the menu item header.</p>
  
  <p>I am using the MVVM pattern for my application, meaning that I avoid placing any code in code-behind wherever possible and have my view-models (that I assign to the <a href="http://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.datacontext%28v=vs.110%29.aspx" rel="noreferrer"><code>DataContext</code> properties</a>) provide implementations of the <a href="http://msdn.microsoft.com/en-us/library/system.windows.input.icommand%28v=vs.110%29.aspx" rel="noreferrer"><code>ICommand</code> interface</a> that are used by controls in my views.</p>
  
  <hr>
  
  <p>As a base for reproducing the issue, here is some minimal source code for an application as described:</p>
  
  <p><strong>Window1.xaml</strong></p>
  
  <pre><code>&lt;Window x:Class="MenuShortcutTest.Window1"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      Title="MenuShortcutTest" Height="300" Width="300"&gt;
      &lt;Menu&gt;
          &lt;MenuItem Header="{Binding MenuHeader}"&gt;
              &lt;MenuItem Header="{Binding DoSomethingHeader}" Command="{Binding DoSomething}"/&gt;
          &lt;/MenuItem&gt;
      &lt;/Menu&gt;
  &lt;/Window&gt;
  </code></pre>
  
  <p><strong>Window1.xaml.cs</strong></p>
  
  <pre><code>using System;
  using System.Windows;
  
  namespace MenuShortcutTest
  {
      public partial class Window1 : Window
      {
          public Window1()
          {
              InitializeComponent();
  
              this.DataContext = new MainViewModel();
          }
      }
  }
  </code></pre>
  
  <p><strong>MainViewModel.cs</strong></p>
  
  <pre><code>using System;
  using System.Windows;
  using System.Windows.Input;
  
  namespace MenuShortcutTest
  {
      public class MainViewModel
      {
          public string MenuHeader {
              get {
                  // in real code: load this string from localization
                  return "Menu";
              }
          }
  
          public string DoSomethingHeader {
              get {
                  // in real code: load this string from localization
                  return "Do Something";
              }
          }
  
          private class DoSomethingCommand : ICommand
          {
              public DoSomethingCommand(MainViewModel owner)
              {
                  if (owner == null) {
                      throw new ArgumentNullException("owner");
                  }
  
                  this.owner = owner;
              }
  
              private readonly MainViewModel owner;
  
              public event EventHandler CanExecuteChanged;
  
              public void Execute(object parameter)
              {
                  // in real code: do something meaningful with the view-model
                  MessageBox.Show(owner.GetType().FullName);
              }
  
              public bool CanExecute(object parameter)
              {
                  return true;
              }
          }
  
          private ICommand doSomething;
  
          public ICommand DoSomething {
              get {
                  if (doSomething == null) {
                      doSomething = new DoSomethingCommand(this);
                  }
  
                  return doSomething;
              }
          }
      }
  }
  </code></pre>
  
  <hr>
  
  <p>The <a href="http://msdn.microsoft.com/en-us/library/system.windows.controls.menuitem.aspx" rel="noreferrer">WPF <code>MenuItem</code> class</a> has an <a href="http://msdn.microsoft.com/en-us/library/system.windows.controls.menuitem.inputgesturetext.aspx" rel="noreferrer"><code>InputGestureText</code> property</a>, but as described in SO questions such as <a href="https://stackoverflow.com/questions/5329292/why-doesnt-setting-menuitem-inputgesturetext-cause-the-menuitem-to-activate-whe">this</a>, <a href="https://stackoverflow.com/questions/2994718/correct-way-to-create-a-menu-with-shortcuts-in-wpf">this</a>, <a href="https://stackoverflow.com/questions/8227588/my-key-shortcut-isnt-working">this</a> and <a href="https://stackoverflow.com/questions/4682915/defining-menuitem-shortcuts">this</a>, that is purely cosmetic and has no effect whatsoever on what shortcuts are actually processed by the application.</p>
  
  <p>SO questions like <a href="https://stackoverflow.com/questions/4682915/defining-menuitem-shortcuts">this</a> and <a href="https://stackoverflow.com/questions/2994718/correct-way-to-create-a-menu-with-shortcuts-in-wpf">this</a> point out that the command should be linked with a <a href="http://msdn.microsoft.com/en-us/library/system.windows.input.keybinding%28v=vs.110%29.aspx" rel="noreferrer"><code>KeyBinding</code></a> in the <a href="http://msdn.microsoft.com/en-us/library/system.windows.uielement.inputbindings%28v=vs.110%29.aspx" rel="noreferrer"><code>InputBindings</code></a> list of the window. While that enables the functionality, it does not automatically display the shortcut with the menu item. <strong>Window1.xaml</strong> changes as follows:</p>
  
  <pre><code>&lt;Window x:Class="MenuShortcutTest.Window1"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      Title="MenuShortcutTest" Height="300" Width="300"&gt;
      &lt;Window.InputBindings&gt;
          &lt;KeyBinding Key="D" Modifiers="Control" Command="{Binding DoSomething}"/&gt;
      &lt;/Window.InputBindings&gt;
      &lt;Menu&gt;
          &lt;MenuItem Header="{Binding MenuHeader}"&gt;
              &lt;MenuItem Header="{Binding DoSomethingHeader}" Command="{Binding DoSomething}"/&gt;
          &lt;/MenuItem&gt;
      &lt;/Menu&gt;
  &lt;/Window&gt;
  </code></pre>
  
  <p>I have tried manually setting the <code>InputGestureText</code> property in addition, making <strong>Window1.xaml</strong> look like this:</p>
  
  <pre><code>&lt;Window x:Class="MenuShortcutTest.Window1"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      Title="MenuShortcutTest" Height="300" Width="300"&gt;
      &lt;Window.InputBindings&gt;
          &lt;KeyBinding Key="D" Modifiers="Control" Command="{Binding DoSomething}"/&gt;
      &lt;/Window.InputBindings&gt;
      &lt;Menu&gt;
          &lt;MenuItem Header="{Binding MenuHeader}"&gt;
              &lt;MenuItem Header="{Binding DoSomethingHeader}" Command="{Binding DoSomething}" InputGestureText="Ctrl+D"/&gt;
          &lt;/MenuItem&gt;
      &lt;/Menu&gt;
  &lt;/Window&gt;
  </code></pre>
  
  <p>This does display the shortcut, but is not a viable solution for obvious reasons:</p>
  
  <ul>
  <li>It does not update when the actual shortcut binding changes, so even if the shortcuts are not configurable by users, this solution is a maintenance nightmare.</li>
  <li>The text needs to be localized (as e.g. the <kbd>Ctrl</kbd> key has different names in some languages), so if any of the shortcuts is ever changed, <em>all</em> translations would need to be updated individually.</li>
  </ul>
  
  <p>I have looked into creating an <a href="http://msdn.microsoft.com/en-us/library/system.windows.data.ivalueconverter%28v=vs.110%29.aspx" rel="noreferrer"><code>IValueConverter</code></a> to use for binding the <code>InputGestureText</code> property to the <a href="http://msdn.microsoft.com/en-us/library/system.windows.uielement.inputbindings%28v=vs.110%29.aspx" rel="noreferrer"><code>InputBindings</code></a> list of the window (there might be more than one <code>KeyBinding</code> in the <code>InputBindings</code> list, or none at all, so there is no specific <code>KeyBinding</code> instance that I could bind to (if <code>KeyBinding</code> even lends itself to being a binding target)). This appears to me like the most desirable solution, because it is very flexible and at the same time very clean (it does not require a plethora of declarations in various places), but on the one hand, <a href="http://msdn.microsoft.com/en-us/library/system.windows.input.inputbindingcollection%28v=vs.110%29.aspx" rel="noreferrer"><code>InputBindingCollection</code></a> does not implement <a href="http://msdn.microsoft.com/en-us/library/system.collections.specialized.inotifycollectionchanged%28v=vs.110%29.aspx" rel="noreferrer"><code>INotifyCollectionChanged</code></a>, thus the binding would not be updated when shortcuts are replaced, and on the other hand, I did not manage to provide the converter with a reference to my view-model in a tidy manner (which it would need to access the localization data). What is more, <a href="http://msdn.microsoft.com/en-us/library/system.windows.uielement.inputbindings%28v=vs.110%29.aspx" rel="noreferrer"><code>InputBindings</code></a> is not a dependency property, so I cannot bind that to a common source (such as a list of input bindings located in the view-model) that the <code>ItemGestureText</code> property could be bound to, as well.</p>
  
  <p>Now, many resources (<a href="https://stackoverflow.com/questions/4682915/defining-menuitem-shortcuts">this question</a>, <a href="https://stackoverflow.com/questions/3335378/how-to-assign-ctrl-control-plus-comma-as-the-keyboard-shortcut-to-a-wpf-menu">that question</a>, <a href="http://social.msdn.microsoft.com/Forums/vstudio/en-US/7f5228e0-3a3e-4bde-ae70-12c77972f2a0/menuitem-and-keybinding-question?forum=wpf" rel="noreferrer">this thread</a>, <a href="https://stackoverflow.com/questions/1361350/keyboard-shortcuts-in-wpf">that question</a> and <a href="http://social.msdn.microsoft.com/Forums/vstudio/en-US/c33466a8-6d4a-4327-9db1-423e216e3814/displaying-custom-commands-shortcuts-in-menu?forum=wpf" rel="noreferrer">that thread</a> point out that <a href="http://msdn.microsoft.com/en-us/library/system.windows.input.routedcommand%28v=vs.110%29.aspx" rel="noreferrer"><code>RoutedCommand</code></a> and <a href="http://msdn.microsoft.com/en-us/library/system.windows.input.routeduicommand%28v=vs.110%29.aspx" rel="noreferrer"><code>RoutedUICommand</code></a> contain a built-in <a href="http://msdn.microsoft.com/en-us/library/system.windows.input.routedcommand.inputgestures(v=vs.110).aspx" rel="noreferrer"><code>InputGestures</code> property</a> and imply that key bindings from that property are automatically displayed in menu items.</p>
  
  <p>However, using either of those <code>ICommand</code> implementations seems to open a new can of worms, as their <a href="http://msdn.microsoft.com/en-us/library/system.windows.input.routedcommand.execute%28v=vs.110%29.aspx" rel="noreferrer"><code>Execute</code></a> and <a href="http://msdn.microsoft.com/en-us/library/system.windows.input.routedcommand.canexecute%28v=vs.110%29.aspx" rel="noreferrer"><code>CanExecute</code></a> methods are not virtual and thus cannot be overridden in subclasses to fill in the desired functionality. The only way to provide that seems to be declaring a <a href="http://msdn.microsoft.com/en-us/library/system.windows.input.commandbinding%28v=vs.110%29.aspx" rel="noreferrer"><code>CommandBinding</code></a> in XAML (shown e.g. <a href="https://stackoverflow.com/questions/4682915/defining-menuitem-shortcuts">here</a> or <a href="https://stackoverflow.com/questions/5329292/why-doesnt-setting-menuitem-inputgesturetext-cause-the-menuitem-to-activate-whe">here</a>) that connects a command with an event handler - however, that event handler would then be located in the code-behind, thus violating the MVVM architecture described above.</p>
  
  <hr>
  
  <p>Trying nonetheless, this means turning most of the aforementioned structure inside-out (which also kind of implies that I need to make my mind up on how to eventually solve the issue in my current, comparably early stage of development):</p>
  
  <p><strong>Window1.xaml</strong></p>
  
  <pre><code>&lt;Window x:Class="MenuShortcutTest.Window1"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:MenuShortcutTest"
      Title="MenuShortcutTest" Height="300" Width="300"&gt;
      &lt;Window.CommandBindings&gt;
          &lt;CommandBinding Command="{x:Static local:DoSomethingCommand.Instance}" Executed="CommandBinding_Executed"/&gt;
      &lt;/Window.CommandBindings&gt;
      &lt;Menu&gt;
          &lt;MenuItem Header="{Binding MenuHeader}"&gt;
              &lt;MenuItem Header="{Binding DoSomethingHeader}" Command="{x:Static local:DoSomethingCommand.Instance}"/&gt;
          &lt;/MenuItem&gt;
      &lt;/Menu&gt;
  &lt;/Window&gt;
  </code></pre>
  
  <p><strong>Window1.xaml.cs</strong></p>
  
  <pre><code>using System;
  using System.Windows;
  
  namespace MenuShortcutTest
  {
      public partial class Window1 : Window
      {
          public Window1()
          {
              InitializeComponent();
  
              this.DataContext = new MainViewModel();
          }
  
          void CommandBinding_Executed(object sender, System.Windows.Input.ExecutedRoutedEventArgs e)
          {
              ((MainViewModel)DataContext).DoSomething();
          }
      }
  }
  </code></pre>
  
  <p><strong>MainViewModel.cs</strong></p>
  
  <pre><code>using System;
  using System.Windows;
  using System.Windows.Input;
  
  namespace MenuShortcutTest
  {
      public class MainViewModel
      {
          public string MenuHeader {
              get {
                  // in real code: load this string from localization
                  return "Menu";
              }
          }
  
          public string DoSomethingHeader {
              get {
                  // in real code: load this string from localization
                  return "Do Something";
              }
          }
  
          public void DoSomething()
          {
              // in real code: do something meaningful with the view-model
              MessageBox.Show(this.GetType().FullName);
          }
      }
  }
  </code></pre>
  
  <p><strong>DoSomethingCommand.cs</strong></p>
  
  <pre><code>using System;
  using System.Windows.Input;
  
  namespace MenuShortcutTest
  {
      public class DoSomethingCommand : RoutedCommand
      {
          public DoSomethingCommand()
          {
              this.InputGestures.Add(new KeyGesture(Key.D, ModifierKeys.Control));
          }
  
          private static Lazy&lt;DoSomethingCommand&gt; instance = new Lazy&lt;DoSomethingCommand&gt;();
  
          public static DoSomethingCommand Instance {
              get {
                  return instance.Value;
              }
          }
      }
  }
  </code></pre>
  
  <hr>
  
  <p>For the same reason (<code>RoutedCommand.Execute</code> and such being non-virtual), I do not know how to subclass <code>RoutedCommand</code> in a way to create a <code>RelayCommand</code> like the one used <a href="https://stackoverflow.com/questions/10981936/how-do-you-add-access-keys-shortcuts-to-a-wpf-contextmenu-programmatically">in an answer to this question</a> based on <code>RoutedCommand</code>, so I do not have to make the detour over the <code>InputBindings</code> of the window - while explicitly reimplementing the methods from <code>ICommand</code> in a <code>RoutedCommand</code> subclass feels like I might be breaking something.</p>
  
  <p>What is more, while the shortcut is automatically displayed with this method as configured in the <code>RoutedCommand</code>, it does not seem to get automatically localized. My understanding is that adding</p>
  
  <pre><code>System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("de-de");
  System.Threading.Thread.CurrentThread.CurrentUICulture = System.Threading.Thread.CurrentThread.CurrentCulture;
  </code></pre>
  
  <p>to the <code>MainWindow</code> constructor should make sure that localizable strings supplied by the framework should be taken from the German <code>CultureInfo</code> - however, <code>Ctrl</code> does not change to <code>Strg</code>, so unless I am mistaken about how to set the <code>CultureInfo</code> for framework-supplied strings, this method is not viable anyway if I expect the displayed shortcut to be correctly localized.</p>
  
  <p>Now, I am aware that <a href="http://msdn.microsoft.com/en-us/library/system.windows.input.keygesture%28v=vs.110%29.aspx" rel="noreferrer"><code>KeyGesture</code></a> allows me to specify a custom display string for the keyboard shortcut, but not only is the <code>RoutedCommand</code>-derived <code>DoSomethingCommand</code> class disjoint from all of my instances (from where I could get in touch with the loaded localization) due to the way <code>CommandBinding</code> has to be linked with a command in XAML, the <a href="http://msdn.microsoft.com/en-us/library/system.windows.input.keygesture.displaystring%28v=vs.110%29.aspx" rel="noreferrer">respective <code>DisplayString</code> property</a> is read-only, so there would be no way to change it when another localization is loaded at runtime.</p>
  
  <p>This leaves me with the option to manually dig through the menu tree (EDIT: for the sake of clarification, no code here because I am not asking for this and I know how to do this) and the <code>InputBindings</code> list of the window to check which commands have any <code>KeyBinding</code> instances associated with them, and which menu items are linked to any of those commands, so that I can manually set the <code>InputGestureText</code> of each of the respective menu items to reflect the first (or preferred, by whichever metric I want to use here) keyboard shortcut. And this procedure would have to be repeated every time I think the key bindings may have changed. However, this seems like an extremely tedious workaround for something that is essentially a basic feature of a menu bar GUI, so I'm convinced it cannot be the "correct" way to do this.</p>
  
  <p><strong>What is the right way to automatically display a keyboard shortcut that is configured to work for WPF <code>MenuItem</code> instances?</strong></p>
  
  <p>EDIT: All of the other questions I found dealt with how a <code>KeyBinding</code>/<code>KeyGesture</code> could be used to actually enable the functionality visually implied by <code>InputGestureText</code>, without explaining how to automatically link the two aspects in the described situation. The only somewhat promising question that I found was <a href="https://stackoverflow.com/questions/8617897/menuitem-keyboard-shortcuts-in-pure-mvvm">this</a>, but it has not received any answers in over two years.</p>