Search code examples
c#wpfxamlmvvminputbinding

How to simplify InputBindings in XAML?


First, this is my code :

<Window ...>
<Window.Resources>

</Window.Resources>
<Window.InputBindings>
    <KeyBinding Key="Space" Command="{Binding KeyboardCommand}" CommandParameter="Space"/>
    <KeyBinding Key="OemPeriod" Command="{Binding KeyboardCommand}" CommandParameter="Blank"/>
    <KeyBinding Key="D0" Command="{Binding KeyboardCommand}" CommandParameter="Rest"/>
    <KeyBinding Key="D1" Command="{Binding KeyboardCommand}" CommandParameter="N1"/>
    <KeyBinding Key="D2" Command="{Binding KeyboardCommand}" CommandParameter="N2"/>
    <KeyBinding Key="D3" Command="{Binding KeyboardCommand}" CommandParameter="N3"/>
    <KeyBinding Key="D4" Command="{Binding KeyboardCommand}" CommandParameter="N4"/>
    <KeyBinding Key="D5" Command="{Binding KeyboardCommand}" CommandParameter="N5"/>
    <KeyBinding Key="D6" Command="{Binding KeyboardCommand}" CommandParameter="N6"/>
    <KeyBinding Key="D7" Command="{Binding KeyboardCommand}" CommandParameter="N7"/>

    <KeyBinding Modifiers="Control" Key="Space" Command="{Binding KeyboardCommand}" CommandParameter="Space"/>
    <KeyBinding Modifiers="Control" Key="OemPeriod" Command="{Binding KeyboardCommand}" CommandParameter="Blank"/>
    <KeyBinding Modifiers="Control" Key="D0" Command="{Binding KeyboardCommand}" CommandParameter="Rest"/>
    <KeyBinding Modifiers="Control" Key="D1" Command="{Binding KeyboardCommand}" CommandParameter="N1"/>
    <KeyBinding Modifiers="Control" Key="D2" Command="{Binding KeyboardCommand}" CommandParameter="N2"/>
    <KeyBinding Modifiers="Control" Key="D3" Command="{Binding KeyboardCommand}" CommandParameter="N3"/>
    <KeyBinding Modifiers="Control" Key="D4" Command="{Binding KeyboardCommand}" CommandParameter="N4"/>
    <KeyBinding Modifiers="Control" Key="D5" Command="{Binding KeyboardCommand}" CommandParameter="N5"/>
    <KeyBinding Modifiers="Control" Key="D6" Command="{Binding KeyboardCommand}" CommandParameter="N6"/>
    <KeyBinding Modifiers="Control" Key="D7" Command="{Binding KeyboardCommand}" CommandParameter="N7"/>

    ...
</Window.InputBindings>
<Grid>
    ...
</Grid>

There's NO ERROR on those code, so it works just fine. But, it seems that the InputBindings can get a lot of lines if my application has a lot of InputBindings.

So, is it possible to simplify/shorten them (in any way)? It is because my application will need a lot of InputBindings / KeyBinding's Modifier combination, and it feel input it one-by-one will look "not neat". M

Or maybe it is the only way to do (with MVVM)?

Please clarify anything needed :D


Just in case needed, these are the related methods in Command and ViewModel class :

public void Execute(object parameter)
{
    Notes note;
    if (Enum.TryParse(parameter.ToString(), out note))
    {
        _vm.AddOrUpdateNote(note, Keyboard.Modifiers);
    }
    else
    {
        ...
    }
}

A part of my ViewModel :

public void AddOrUpdateNote(Notes note, ModifierKeys mKeys)
{
    if (mKeys == ModifierKeys.Control)
    {
        ...
    }
    else if (mKeys == ModifierKeys.Shift)
    {
        ...
    }
    else
    {
        ...
    }
}

So, there's a minor behavior difference depending which Modifier Key is pressed. (Splitting into different methods feels awful for me)


UPDATE : I've read some explanations on InputGestures. In http://msdn.microsoft.com/en-us/library/ms752308%28v=vs.110%29.aspx it's said this.InputBindings.Add(Blabla) (from xaml.cs i guess), can it be done in the ViewModel? Or is it strictly need to be done via XAML, so, if I have a lot of key combination in my application such in the example above, it still need to be done that "long" way?

Please provide some code samples if possible, so I can understand it better. Thanks

(Not quite sure too how to ask it, so please feel free to clarify)


Solution

  • If your sole objective is to cut down on the number of manual KeyBindings, you can do something like this:

    var keys = new List<Key> { Key.Space, Key.OemPeriod, Key.D1, [...]};
    foreach(var key in keys)
    {
         this.InputBindings.Add(new KeyBinding() { Command = MyCommandClass.KeyboardCommand, CommandParameter = key});
    ]
    

    But I don't like this approach, as it requires you to implement delegation of your command yourself rather than having WPF do it. You will need to switch on the CommandParameter and modifierkey.

    The above will absolutely work, but having a single command do all the work seems counterintuitive to me. I would implement several commands (like AddNoteCommand) so that they can each hold their own Execute and CanExecute method.

    Yes, you'd have a few extra lines of code per Command, but your command implementation would not have to know HOW you accessed the command. Imagine you want to add these commands as MenuItems, or Buttons in your UI.

    There might be something I'm missing (I don't know what the commands do), but I can't really imagine a scenario where I would choose this approach.

    That doesn't necessarily make it wrong though ;)