LeftAlt Keybinding in WPF - c#

I'm trying to bind Left ALT key with a command to toggle visibility of a menu in WPF.
But it doesn't work.. Command is not firing..
<Window.InputBindings>
<KeyBinding
Key="LeftAlt"
Command="{Binding Path=MenuVisibilitySetCommand}"/>
</Window.InputBindings>
I've noticed that other special Keys ( such as Alt, Ctrl etc..) also not working here..
How to do KeyBinding for Special Key in WPF ?

For LeftALt to work like this, you also need to set Modifiers property to Alt.
<KeyBinding Key="LeftAlt" Modifiers="Alt" Command="{Binding Path=MenuVisibilitySetCommand}"/>

These special Keys are called Modifier keys and this should make it clear why it is not working. A modifier Key is to "modify" the behavior of a given key, Like Shift + L makes an uppercase "L" where only the L key makes a lowercase "l". Using Modifierkeys for actual logic can be problematic and irritating, because the user is not accustomed to see real actions happening when pressing these kind of buttons. But i agree there are places where this makes sense e.g. highlighting MenuItems when hitting ALT key.
But to your actual problem: You could use codebehind and the OnKeyDown/OnKeyUp or the Preview events to implement this behavior.
protected override void OnKeyDown(KeyEventArgs e)
{
if(e.SystemKey == Key.LeftAlt)
{
myMenu.Visibility = Visibility.Visible;
// e.Handled = true; You need to evaluate if you really want to mark this key as handled!
}
base.OnKeyDown(e);
}
Of course cou could also fire your command in this code.

Related

Is there an alternative to WPF's "KeyBinding" in UWP?

In my WPF app I am using what's written below to bind a key press of the F10 key to running a method in my script named 'btn_font_click'. However obviously UWP does not support direct keybindings like this in XAML since it's universal and not designed for Windows.
Is there any way that I can get this same effect in a UWP application?
<Window.Resources>
<RoutedUICommand x:Key="cmd1"></RoutedUICommand>
</Window.Resources>
<Window.CommandBindings>
<CommandBinding Command="{StaticResource cmd1}"
Executed="btn_font_Click">
</CommandBinding>
</Window.CommandBindings>
<Window.InputBindings>
<KeyBinding Key="F10" Command="{StaticResource cmd1}"></KeyBinding>
</Window.InputBindings>
I'm using for inputting data from an RFID reader. Currently when the RFID card is scanned it presses F10, types out its data and then presses enter.
My idea is F10 sets the keyboards focus to a textbox, the script then waits for an enter press while the RFID types out its data and it then takes what's in the text box and splits it into an array for usage within the app.
If there's a better or more direct way for getting the data from within the RFID card to my array I'm open for other potential solutions.
Edit: After looking into this for a while I've found that a 'Keyboard Accelerator' would be best for this programs current functionality as I would like the RFID card to still work while the app isn't in focus. Could I get some pointers as of how to set up a Keyboard Accelerator linking an F10 key press to running my method?
If you want to set up this kind of application-wide keyboard shortcut mechanism, activators are definitely one way to go about doing it.
There is a documentation on keyboard accelerators available and this functionality is available since the Fall Creators Update. Each UIElement has a KeyboardAccelerators collection, which allows you to define keyboard accelerators which interact with it. In case of buttons and menu items invoking the specified shortcut automatically invokes the control, but to make your TextBox focused, you have to specify this behavior yourself using the Invoked event:
<TextBox>
<TextBox.KeyboardAccelerators>
<KeyboardAccelerator Modifiers="None"
Key="F10" Invoked="KeyboardAccelerator_OnInvoked" />
</TextBox.KeyboardAccelerators>
</TextBox>
And in the event handler the TextBox is then focused:
private void KeyboardAccelerator_OnInvoked(
KeyboardAccelerator sender,
KeyboardAcceleratorInvokedEventArgs args )
{
(args.Element as Control).Focus(FocusState.Keyboard);
}
The KeyboardAcceleratorInvokedEventArgs.Element property contains a reference to our TextBox, I cast it to Control, as this is the parent of TextBox that declares the Focus method and you can potentially reuse this method on any focusable control.

Detect question mark independent from keyboard

The goal is simple: When the user enters chars in a textbox, I want to detect if this char is the question mark key (?).
I don't care what to use (text changed, key down etc...)
One thing to mention: I am working on a german keyboard layout and therefore I need a solution independent from the keyboard (for example: e.Key = Keys.OemQuestion isn't working, it fires when I press the plus (+) key)
Edit: I tried Convert.toString((char)e.Key) which returned \u0095 and e.Key.ToString() which returned OemOpenBrackets
I chose the solution from #HansPassant and managed to do it with the TextInput event.
First in the constructor:
InitializeComponent();
CommandTextBox.AddHandler(TextBox.TextInputEvent, new TextCompositionEventHandler(CommandTextBox_TextInput), true);
You need this code to actually fire the event
in TextInput
if(e.Text == "?")
{
//Do something
}
NOTE:
This does not capture space, control, shift etc.

WPF KeyBinding swallowing keys, preventing TextBox use

Problem Overview:
Any KeyBinding's defined at a level higher than a TextBox (with no modifier keys assigned), prevents the user from typing those keys inside the TextBox.
Minimal XAML Hierarchy:
<Window>
<UserControl>
<Border>
<UserControl>
<TextBox>
Minimal Command/KeyBinding:
<UserControl.Resources>
<RoutedUICommand x:Key="Commands.SomeCommand" />
</UserControl.Resources>
<UserControl.InputBindings>
<KeyBinding Key="A" Command="{StaticResource Commands.SomeCommand}" />
</UserControl.InputBindings>
<UserControl.CommandBindings>
<CommandBinding Command="{StaticResource Commands.SomeCommand}" Executed="..." />
</UserControl.CommandBindings>
The Command and KeyBinding, are defined at the first UserControl level. So in this example, in the textbox, the user can type freely until they press the A key, and then it just does not insert the letter into the textbox. I can clearly see that the TextBox.KeyDown and TextBox.PreviewKeyDown are firing when you press the A key (and Handled = false) , but the letter will not get added to the text of the textbox and TextBox.PreviewTextInput does not fire.
I'm looking for any suggestions that may indicate what is swallowing the keypress and stopping it from getting processed by the TextBox, or anything related to how I can debug this issue.
EDIT: Thanks to Snoop, I was able to clearly see the problem.
TextBox.PreviewKeyDown tunnels down and fires through the visual tree, starting at the Window, and ending at the TextBox
TextBox.KeyDown bubbles back up starting at the TextBox and heading towards the window
TextBox.KeyDown gets Handled set to true by the first UserControl that has the KeyBinding set.
TextBox.PreviewTextInput never fires, nor does the textbox process the input, because the KeyDown event was set as handled.
This still leaves the problem, how do you prevent the UserControl from handling the input if a textbox has focus? Within the Command execution, I can check if a textbox has keyboard focus, but by this time it's too late.
TextInput and PreviewTextInput only fires when the Text actually changes / might change.
As you updated your question to reflect, the Command intercepts the event and the (Preview)TextInput events are never raised.
The nicest solution would be to add a modifier key to your KeyBinding, but I suspect that is not your preferred way to go.
Another option would be to e.Handle the PreviewKeyDown event on the TextBox and raise the TextComposition events yourself, using something like:
target.RaiseEvent(new TextCompositionEventArgs(InputManager.Current.PrimaryKeyboardDevice,
new TextComposition(InputManager.Current, target, "A"))
{
RoutedEvent = TextCompositionManager.TextInputEvent
});
(Alternatively, insert into textBox.Text at the correct CaretIndex)
Truth be told, it would still be a hack.
I have the same problem.
I took a look to documentation for key bindind, and there is described, that the key on which you bind shouldn't be just key, but key gesture, so it shall be
Modifier key + normal key
Numeric keypad key
Functional key.
Of course, it works with just A, but it's bad practice overall. You should consider to implement some of the posibilities mentioned behind. More at https://msdn.microsoft.com/cs-cz/library/system.windows.input.keybinding(v=vs.110).aspx
I had used the TextComposition RaiseEvent approach for years, however this seems to break typing for non-latin keyboard layouts (eg. cyrillic).
The proper way to do this is to derive from InputBinding and return false in the Matches? check if the event originated from a text-box.
/// <summary>
/// This gesture doesn't handle keys originating in a text control. This allows key bindings without modifier keys
/// that don't break normal typing. A standard KeyGesture doesn't have such logic; this allows the parent of a
/// text box to handle such bare keypresses before the textbox gets to see it as normal text input, thus breaking
/// normal typing.
/// </summary>
public class BareKeyGesture : InputGesture
{
public Key Key { get; set; }
public override bool Matches(object targetElement, InputEventArgs inputEventArgs)
{
var keyEventArgs = inputEventArgs as KeyEventArgs;
if (keyEventArgs == null)
return false;
if (inputEventArgs.OriginalSource is TextBoxBase)
return false;
return (int)Key == (int)keyEventArgs.Key && Keyboard.Modifiers == ModifierKeys.None;
}
}
/// <summary>
/// This only exists because the InputBinding constructor is protected, but since we have to have it anyway
/// we also use this opportunity to simplify adding a BareKeyGesture to it.
/// </summary>
public class BareKeyBinding : InputBinding
{
private BareKeyGesture _gesture = new();
public BareKeyBinding()
{
Gesture = _gesture;
}
public Key Key
{
get => _gesture.Key;
set { _gesture.Key = value; }
}
}
And now that you have an InputGesture which will ignore events originating from textboxes, you can use it in XAML like normal:
<UserControl.InputBindings>
<nsp:BareKeyBinding
Key="D"
Command="{StaticResource Commands.YourCommand}"
CommandParameter="None" />
</UserControl.InputBindings>
As long as you use KeyBinding this not going to work without major hacks. A solution I implemented for this is:
Use the KeyDown event to capture those keys being pressed (instead of KeyBindings). This will be on your code-behind and from there you'll need to switch on the pressed Key to call the required command (SomeCommand in your case).
Now you have a different problem. The TextBox is getting the input but your key-bound commands are also firing. On the code behind, check the type of keyEventArgs.InputSource and ignore the key stroke if it's a TextBox.
It should look like this:
private void OnKeyDown(object sender, KeyEventArgs e)
{
ICommand command = null;
switch (e.Key)
{
case Key.A:
command = Commands.SomeCommand;
break;
case Key.B:
command = Commands.SomeOtherCommand;
break;
}
bool isSourceATextBox = e.InputSource.GetType() == typeof(TextBox);
if (command != null && !isSourceATextBox)
{
command.Execute(parameter:null);
}
}

Keybinding with more than one Key programmatically [duplicate]

I have a KeyBinding with the Key set to D1 which is the 1 key. This isn't the same as NumPad1 key.
Is there a way to have something like:
Key="D1 && NumPad1"
So that pressing either D1 or NumPad1 would execute the command?
I've added a second KeyBinding one for each key D1 & NumPad1, but that seems like there should be a better way.
Yes you can - comma delimited :-)
I am not certain if in the question you want to use two KeyBindings to signify that user would have to push the key twice. But that's what I was looking for. If that's the reason then this post will work.
For example, I wanted to use + to go forward, and ++ to double-go-forward, and - to go-back, -- to go double back in my app:
<KeyBinding Key="OemMinus" Modifiers="Control" Command="{Binding GoBack}"/>
<KeyBinding Key="OemMinus,OemMinus" Modifiers="Control" Command="{Binding GoBack2X}"/>
The reason I figured it out, was that I know that in VisualStudio you have a ton of commands that have double key, like commenting, or collapsing regions. And you know that VS2010's written in WPF. So I looked on the VS menu, and there are ton of commands comma separated:
View > Solution Navigator Cntr + W, F.
I tried it and it worked!
No, you can't do that.

KeyBinding with no modifiers (in UserControl)

I want to execute a command when a key pressed(without modifiers). So, I tried below code:
<UserControl.InputBindings>
<KeyBinding Key="A" Command="{Binding ACommand}" />
</UserControl.InputBindings>
but, KeyBinding supports not a key but key and modifier.
Now I consider using Behavior and treat KeyDown event. But this is too complex.
Someone knows an easier solution?
Add:
Above code is work well in Window.
I find solution in UserControl. (Using .NET Framework 4)
I do not quite get what your problem is. The code you wrote should work, there is no need to specify modifiers.
I suppose the problem might be your binding or the control you set the key binding on cannot be focused so it won't trigger.
Microsoft doesn't support binding to a normal key that you might press while typing in a text box - unless it has a modifier. You can bind to function keys (like F1) and a few others without a modifier.
See: http://msdn.microsoft.com/en-us/library/system.windows.input.keygesture(v=vs.110).aspx
I've come across a blog that says he was able to get around this problem by creating his own KeyGesture class by inheriting from InputGesture and implementing the Matches function. http://dikhi.wordpress.com/2008/06/27/keygesture-doesnt-work-with-alpha-numeric-key/
I figured a way out to set a InputBinding by using only a single Key like "Key.A"
boolean noMod = ModifierKeys == ModifierKeys.None;
KeyBinding inputBinding = new KeyBinding(this, Keys, noMod ? ModifierKeys.Alt : ModifierKeys));
if (noMod)
{
inputBinding.ClearValue(KeyBinding.ModifiersProperty);
}
That worked for me fine.

Categories

Resources