Reputation: 542
I'm developing a feature where a user can press 1 trough 9 or 'a' through 'z' that executes a command in a list. I built support for the numbers, but I don't really like the way I made it.
<Grid.InputBindings>
<KeyBinding Command="{Binding ShortcutCharacterCommand}" Key="D0" CommandParameter="0" />
<KeyBinding Command="{Binding ShortcutCharacterCommand}" Key="D1" CommandParameter="1" />
<KeyBinding Command="{Binding ShortcutCharacterCommand}" Key="D2" CommandParameter="2" />
<KeyBinding Command="{Binding ShortcutCharacterCommand}" Key="D3" CommandParameter="3" />
<KeyBinding Command="{Binding ShortcutCharacterCommand}" Key="D4" CommandParameter="4" />
<KeyBinding Command="{Binding ShortcutCharacterCommand}" Key="D5" CommandParameter="5" />
<KeyBinding Command="{Binding ShortcutCharacterCommand}" Key="D6" CommandParameter="6" />
<KeyBinding Command="{Binding ShortcutCharacterCommand}" Key="D7" CommandParameter="7" />
<KeyBinding Command="{Binding ShortcutCharacterCommand}" Key="D8" CommandParameter="8" />
<KeyBinding Command="{Binding ShortcutCharacterCommand}" Key="D9" CommandParameter="9" />
</Grid.InputBindings>
If I implement the remaining characters in the same manner, I'll have a huge list of bindings. Not only to support the letters, but also the numpad. I'd rather test for ranges of characters like I did with a Winform control in another part of our application with the code:
if (e.KeyValue >= '1' && e.KeyValue <= '9' ||
e.KeyValue >= 'A' && e.KeyValue <= 'Z')
{
FavoriteShortcutKeyPressedCallBack.Raise(e.KeyValue);
}
I really think it is possible but I can't seem to work out a solution or find one on the internet that adheres to the MVVM pattern.
So basically my question is, how can this be done in WPF/MVVM in a more generic, elegant manner?
I took the suggestion from the answer of mm8 to use EventToCommandBinding. This resulted in the following code in the XAML:
<i:Interaction.Behaviors>
<behaviors:EventToCommandBehavior Event="PreviewTextInput"
Command="{Binding TextInputCommand}"
PassArguments="True" />
</i:Interaction.Behaviors>
The ViewModel has a TextInputCommand that reads the text from the EventArgs and selects the corresponding item.
public RelayCommand<TextCompositionEventArgs> TextInputCommand { get; set; }
private void HandleTextInputCommand(TextCompositionEventArgs args)
{
SelectItemBoundToShortcut(args.Text);
}
At first I used the KeyDown event as user1672994 suggested in the comments. But found out that I had to account for different keyboard layouts and check separately for the numpad characters. Using the PreviewTextInput event just sends the typed text, which is exactly what I need.
Upvotes: 0
Views: 191
Reputation: 169200
You could handle the PreviewKeyDown
event. Either in the code-behind of the view, from where you then invoke the command of the view model:
private void Grid_PreviewKeyDown(object sender, KeyEventArgs e)
{
var viewModel = DataContext as YourViewModel;
if (viewModel != null)
{
switch (e.Key)
{
case Key.D0:
viewModel.ShortcutCharacterCommand.Execute("0");
break;
case Key.D1:
viewModel.ShortcutCharacterCommand.Execute("1");
break;
//...
}
}
}
Or by using an interaction trigger as explained here:
MVVM Passing EventArgs As Command Parameter
You may also wrap the functionality defined in the event handler in an attached behaviour.
Upvotes: 2