6

Is it possible to dynamically define KeyBindings based on a bound data source? I have a screen with a grid and I allow users to save various layouts for it. I currently bind the grids context menu to the layout names (via the ViewModel), allowing them to switch layouts via the menu.

However, I would like to associate each layout with a shortcut key. As the shortcut keys are defined by the user I can't simply add a number of <KeyBinding> elements in the window XAML. Another issue is the binding would need to supply the name of the layout as a command parameter.

Is there any way to dynamically create a series of <KeyBinding> elements from a dynamic source?

As a test I have added the bindings statically to my view XAML and they work fine, but this was only to test my concept:

<UserControl.InputBindings>
    <KeyBinding Key="F7" Command="{Binding MyCommand}" CommandParameter="My Layout Name"/>
    <KeyBinding Key="F8" Command="{Binding MyCommand}" CommandParameter="My Other Layout Name"/>
</UserControl.InputBindings>
Daniel Kelley
  • 7,579
  • 6
  • 42
  • 50

2 Answers2

2

Here's code I use to create key bindings dynamically as part of a snippet editor that allows snippets to be executed on a hotkey.

In addition to earlier examples it also demonstrates how to parse user input of key combos:

// example key combo from user input
var ksc = "Alt+Shift+M";
ksc = ksc.ToLower();

KeyBinding kb = new KeyBinding();

if (ksc.Contains("alt"))
    kb.Modifiers = ModifierKeys.Alt;
if (ksc.Contains("shift"))
    kb.Modifiers |= ModifierKeys.Shift;
if (ksc.Contains("ctrl") || ksc.Contains("ctl"))
    kb.Modifiers |= ModifierKeys.Control;

string key =
    ksc.Replace("+", "")
        .Replace("-", "")
        .Replace("_", "")
        .Replace(" ", "")
        .Replace("alt", "")
        .Replace("shift", "")
        .Replace("ctrl", "")
        .Replace("ctl", "");

key =   CultureInfo.CurrentCulture.TextInfo.ToTitleCase(key);
if (!string.IsNullOrEmpty(key))
{
    KeyConverter k = new KeyConverter();
    kb.Key = (Key)k.ConvertFromString(key);
}

// Whatever command you need to bind to
// CommandBase here is a custom class I use to create commands
// with Execute/CanExecute handlers
kb.Command = new CommandBase((s, e) => InsertSnippet(snippet),
                             (s,e) => Model.IsEditorActive);

Model.Window.InputBindings.Add(kb);
Rick Strahl
  • 17,302
  • 14
  • 89
  • 134
  • Most of that can be replaced with something like the following (don't need to manually parse all of those things): kb = new KeyBinding(theCommand, new KeyGestureConverter().ConvertFromString(ksc) as KeyGesture); – Guy Danus Dec 07 '17 at 01:15
0

there's a few ways to do that, the easiest one imo is to create a converter, which will return a key, depending on a command name (essentially it's a lookup with your layout name being a key and Key being a value). It'll get slightly more complex if you need to handle more complex guestures, gis a shout and I'll craft a sample for it:

Here's the XAML:

<Grid.InputBindings>
<KeyBinding Key="{Binding Converter={StaticResource converter}, ConverterParameter=My Other Layout Name}" Command="{Binding MyCommand}" />
</Grid.InputBindings>
  • You may get away with using the same implementation for handling complex guesteres (Ctrl + Alt +_Blah etc.), please see: http://stackoverflow.com/questions/3625859/can-i-create-a-keybinding-for-a-sequence-of-keys-in-wpf –  Feb 16 '11 at 13:06