Is it possible to have 2 or more KeyGestures for a single RoutedUICommand?
For example: User wants to be able to press Space or Alt+P to play a video.
Currently, if I set both KeyGestures to a RoutedUICommand, it will expect both to be pressed to execute.
private static RoutedUICommand _play = new RoutedUICommand("Play", "Play", typeof(Commands),
new InputGestureCollection
{
new KeyGesture(Key.P, ModifierKeys.Alt, "Alt + P"),
new KeyGesture(Key.Space, ModifierKeys.None, "Space")
});
So, can I set multiple KeyGestures to a single RoutedUICommand? If so, how?
Yes you can add multiple keyBindings for same Command like below,
<UserControl.InputBindings>
<KeyBinding Modifiers="Alt" Key="P" Command="{Binding PlayCommand}" />
<KeyBinding Key="Space" Command="{Binding PlayCommand}" />
</UserControl.InputBindings>
Related
I want to obtain the barcode returned by a barcode reader without the need for the focus to be in a textbox, which only needs to be open one view.
For now what I'm doing is this in my Vista
<UserControl x:Class="Capa_Presentacion_WPF.Views.AutoServicio.AutoServicio"
xmlns:local="clr-namespace:Capa_Presentacion_WPF.Views.AutoServicio"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:local11="clr-namespace:Capa_Entidades.Models;assembly=Capa_Entidades"
mc:Ignorable="d"
d:DesignHeight="768" d:DesignWidth="1130" Background="Lavender"
Loaded="UserControl_Loaded"
KeyDown="UserControl_KeyDown">
<UserControl.InputBindings>
<KeyBinding Command="{Binding Path=EnterCommand}" Key="Enter"/>
<KeyBinding Command="{Binding Path=KeyF1Command}" Key="F1" />
<KeyBinding Command="{Binding Path=KeyF2Command}" Key="F2" />
<KeyBinding Command="{Binding Path=KeyF3Command}" Key="F3" />
<KeyBinding Command="{Binding Path=KeyF4Command}" Key="F4" />
<KeyBinding Command="{Binding Path=KeyF12Command}" Key="F12" />
</UserControl.InputBindings>
</UserControl>
The first ** <KeyBinding ** refers to me when it detects the "enter", since the codes that are read with the reader come with an enter to the last one. I was thinking of using that, but the problem there is how do I get the code before the "enter"?
The other thing that this is is that I program in a textbox, but that's what I don't want, I just want to get the code and to execute a function when reading the barcode, without having to be in a textbox or any other control.
Currently I associate it to my textbox as follows:
<TextBox Background="White" Margin="0,0,10,10" Name="textBoxBuscador"
Text="{Binding Buscador, UpdateSourceTrigger=PropertyChanged}" MaxLines="1" Focusable="True">
<TextBox.InputBindings>
<KeyBinding Command="{Binding Path=BindKeyCommand}" Key="Enter" />
<KeyBinding Command="{Binding Path=KeyF1Command}" Key="F1" />
<KeyBinding Command="{Binding Path=KeyF2Command}" Key="F2" />
<KeyBinding Command="{Binding Path=KeyF3Command}" Key="F3" />
<KeyBinding Command="{Binding Path=KeyF4Command}" Key="F4" />
<KeyBinding Command="{Binding Path=KeyF12Command}" Key="F12" />
</TextBox.InputBindings>
<TextBox.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding SomeTextIsFocused,
Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Value="True">
<Setter Property="FocusManager.FocusedElement"
Value="{Binding RelativeSource={RelativeSource Self}}" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
<i:Interaction.Behaviors>
<local11:FocusChangedBehavior IsFocused="{Binding SomeTextIsFocused}" />
</i:Interaction.Behaviors>
</TextBox>
I bind a string object called Buscador, and inside the <Binding it is calling a command when pressing the "enter" key that is in my viewmodel
This is my ViewModel:
private void Enter()
{
try
{
int c = this.DataPlatosBusqueda.Where(p => p.cbarplato.Contains(Buscador.ToUpper())).Count();
if (c > 0)
{
var id = this.DataPlatosBusqueda.Where(p => p.cbarplato.Contains(Buscador.ToUpper())).FirstOrDefault().idplato.ToString();
if (id != null)
{
PasarPlatos(id);
SomeTextIsFocused = true;
}
this.Buscador = "";
SomeTextIsFocused = true;
}
this.Buscador = "";
SomeTextIsFocused = true;
}
catch (Exception ex)
{
globales.Mensaje("Error:", "Opcion Enter: " + ex.Message.ToString(), 3);
}
}
Broadly speaking, barcode readers fall into two groups.
There are those that are intended for remote stocktaking and the like. These have internal memory and often store data internally for later download. They can often send the data via wi fi to a url. Essentially posting got one of these. Got one of these... as you scan.
The other category is purely an input device like a keyboard. And like a keyboard, you need something to take that input. The simplest approach is a textbox but you can also handle key input at say a window level if that has focus.
A window level key handler would look something like:
private void Window_KeyHandler(object sender, KeyEventArgs e)
{
var keypressed = e.Key;
// do something with keypressed
}
And you can hook it in a window:
this.PreviewKeyDown += new KeyEventHandler(Window_KeyHandler);
There is also a previewtextinput event.
https://learn.microsoft.com/en-us/dotnet/api/system.windows.uielement.previewtextinput?view=netcore-3.1
There are a number of potential issues you could hit with this implementation. One of which being mis reads where it doesn't read the data right and drops a number, reads it as a different one or some such.
Which is why it is usual to simply have a textbox and take the input there.
If the scanner you have is a regular cheap to mid range one then I recommend you reconsider your approach.
This is how apps I've worked on do this and it's useful even when someone is scanning many items very quickly as they come off a conveyor.
If this is an expensive scanner than you could well have the option to post your data direct to a url. You could build a simple web api site and take input there. Your view and wpf app would then be more about seeing what had been input.
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?
How I solved it
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.
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.
I am new to WPF and I see the best pattern call MVVM. I have try to deep in it and I see that the command can only execute on a button or menuitem, etc. But I have a doubt how to execute the ViewModel command when I'm focusing on a textbox and hit the enter key when I finish my editing.
I have google this but I got nothing from all that answer. So hope all of you help me. How to execute command when hit the enter key in textbox?
In my opinion the easiest way is to use a KeyBinding, which allows you to bind a KeyGesture to an ICommand implementation.
In your case, you can write in your XAML something like this:
<TextBox AcceptsReturn="False">
<TextBox.InputBindings>
<KeyBinding Key="Enter" Command="{Binding YourCommand}" />
</TextBox.InputBindings>
</TextBox>
So when your TextBox is focused and you press Enter, YourCommand will be executed.
I hope it can help you.
You can achieve your requirement using behaviors in WPF.
In XAML,
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
<TextBox Text="MyText">
<i:Interaction.Behaviors>
<i:BehaviorCollection>
<EventToCommand EventName="TextChanged" Command="{Binding ViewModelCommand}">
**// You can provide other events to be triggered in the EventName property based on your requirement like "Focused" or "UnFocused".Focused event will be fired if you enter into edit mode and UnFocused event will be triggered if you press enter key.**
<i:BehaviorCollection>
</i:Interaction.Behaviors>
</TextBox>
In ViewModel.cs,
Public class ViewModel
{
private Command viewCommand;
public ViewModel()
{
viewCommand = new Command(CommandMethod);
}
public Command ViewModelCommand
{
get { return viewCommand }
set { viewCommand = value}
}
private void CommandMethod()
{
//This method will hit if you modify enter/delete text in the TextBox
}
}
I have not done WPF development before.
I am creating a calculator. I want the "one" button to be bound to the keyboard key "1".
So the click function of my button must execute when the keyboard key "1" is pressed.
Please advise on how to do this>
use this:
http://msdn.microsoft.com/en-us/library/system.windows.input.keygesture.aspx
<Window.InputBindings>
<KeyBinding Command="{Binding MyCommand}"
Gesture="CTRL+R" />
</Window.InputBindings>
I want to set two shortkeys for two buttons with one shortkey name.
How can i detect which control is focused in MVVM ?
You can simply add the hotkey to whatever scope is logical for it to exist in. There are many ways to handle hotkeys to WPF, however your basic markup should look something like this:
<Window>
<StackPanel>
<local:MyUserControlA>
<local:MyUserControlA.InputBindings>
<KeyBinding Key="Enter" Command="{Binding SaveACommand}" />
</local:MyUserControlA.InputBindings>
</local:MyUserControlA>
<local:MyUserControlB>
<local:MyUserControlB.InputBindings>
<KeyBinding Key="Enter" Command="{Binding SaveBCommand}" />
</local:MyUserControlB.InputBindings>
</local:MyUserControlB>
</StackPanel>
</Window>
This will run SaveACommand if UserControlA has keyboard focus, or SaveBCommand if UserControlB has keyboard focus.