keyboard shortcut in UWP - c#

I have a KeyDown event defined in usercontrol. At the moment it works when you press Enter. I want it to also handle the ctrl + v key combination so that the copied text is pasted and some action has been performed.
Explanation: my KeyDown event handler receives a pressed key, if it's Enter, it gets the current focus in this control (for example, focus on some textBox), checks if there are any data in the TextBox "X", and if so, the other TextBox is autocomplete. And I need that when you insert text in the TextBox "X", autocomplete the rest of the TextBox. How to force the program and execute the insertion and execute my autocomplete code?
private async void OnKeyDown(object sender, KeyRoutedEventArgs e)
{
if (e.Key != VirtualKey.Enter) return;
var focusedElement = FocusManager.GetFocusedElement();
if (focusedElement == LocationName || focusedElement == AddressTextBox ||
focusedElement == Latitude || focusedElement == Longitude)
{
e.Handled = true;
}
if (IsAddressTextValid)
{
var mapLocation = await FindFirstMapLocationAsync(AddressTextBox.Text);
if (mapLocation != null)
{
LatitudeText = mapLocation.Point.Position.Latitude.ToString();
LongitudeText = mapLocation.Point.Position.Longitude.ToString();
}
}
}

To handle Ctrl+V, actually Justin has a post which can helps.
Window.Current.CoreWindow.KeyDown += (s, e) =>
{
var ctrl = Window.Current.CoreWindow.GetKeyState(VirtualKey.Control);
if (ctrl.HasFlag(CoreVirtualKeyStates.Down) && e.VirtualKey == VirtualKey.V)
{
// do your stuff
Debug.WriteLine("ctrl+V has been triggered");
}
if(e.VirtualKey==VirtualKey.Enter)
{
Debug.WriteLine("Enter triggered");
}
};
But for how to force update other textboxs, not so sure about your logic. Change the text not work for you?

Related

WPF TextBox - How to trap and deal with Backspace and Delete events

I am trying to warn the user when they select and delete text in a wpf textbox.
I am able to trap the delete event using the previewkeydown event, but its is canceling out the delete event. Even when you press ok in the code below - deletion does not happen. I am missing something ...
private void TextBox_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
if (e.Key == System.Windows.Input.Key.Delete)
{
var textbox = (TextBox)sender;
if (textbox.SelectionLength > 1)
{
var result = MessageBox.Show("Delete selected?", "MyApp", MessageBoxButton.OKCancel);
if (result == MessageBoxResult.Cancel)
{
e.Handled = true;
}
}
}
}
This does not seem to be the proper usage of the PreviewKeyDown event handler. That handler seems to be meant to redirect non-standard input key events to do custom behavior. The delete key is not considered non-standard/special.
You've got the right idea with your current code otherwise, but now you just need to actually delete the text in the textbox.
private void TextBox_KeyDownHandler(object sender, KeyEventArgs e)
{
switch(e.KeyCode)
{
case Keys.Delete:
if (sender is TextBox tb)
{
if(tb.SelectionLength > 1 && MessageBox.Show("Delete?", "MyApp", MessageBoxButton.OKCancel) == MessageBoxResult.OK)
{
tb.SelectedText = "";
}
}
e.Handled = true;
break;
}
}
Lastly, make sure you're actually subscribing your handlers
public MainWindow()
{
InitializeComponent();
MyTextBox.KeyDown += new KeyEventHandler(TextBox_KeyDownHandler);
}

WPF: Change Button Text when SHIFT is pressed

I would like to change the text (Content property) of a button when the SHIFT key is pressed. In that cases the button shall execute a different command. That is a common UI behaviour e. g. in Photoshop.
Any idea how to do this.
Many thanks in advance
Add the KeyDown or PreviewKeyDown event to your Button element.
<Button Width="300" Height="50" Name="btnFunction" KeyDown="btnFunctionKeyDown" Content="Function1"/>
And the C# Code:
private void btnFunctionKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.LeftShift || e.Key == Key.RightShift)
{
btnFunction.Content = "Function2";
}
}
Have a look on this Article for more information:
https://learn.microsoft.com/de-de/dotnet/api/system.windows.input.keyboard.keydown?view=netcore-3.1
Here my solution (event is handled at the Window) - many thanks for your input - if there is a better solution kindly comment...
internal void HandlePreviewKeyDown(KeyEventArgs e)
{
IInputElement focusedControl = FocusManager.GetFocusedElement(_window);
if (( (Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift) && !(focusedControl?.GetType() == typeof(TextBox)))
{
// set button text
e.Handled = true;
}
}
internal void HandlePreviewKeyUp(KeyEventArgs e)
{
IInputElement focusedControl = FocusManager.GetFocusedElement(_window);
if ( (e.Key == Key.LeftShift) || (e.Key == Key.RightShift) && !(focusedControl?.GetType() == typeof(TextBox)))
{
// re-set button text
e.Handled = true;
}
}

How to avoid newline when user presses CTRL+ENTER keys in a UWP TextBox with AcceptsReturn = "True"

I'm working on a text editing UwP Desktop application that needs to add a line when the user presses ENTER, and perform another procedure when the user presses CTRL + ENTER. The problem is to delete the new line that is also created in the second case. How to prevent this from happening?
KeyEventHandler keyeventHandler = new KeyEventHandler(rtbText_KeyDown);
rtbText.AddHandler(TextBox.KeyDownEvent, keyeventHandler, true);
private static bool IsCtrlKeyPressed()
{
var ctrlState = CoreWindow.GetForCurrentThread().GetKeyState(VirtualKey.Control);
return (ctrlState & CoreVirtualKeyStates.Down) == CoreVirtualKeyStates.Down;
}
private void rtbText_KeyDown(object sender, KeyRoutedEventArgs e)
{
if (IsCtrlKeyPressed())
{
switch (e.Key)
{
case VirtualKey.Enter:
NviNew_Tapped(nviNew, null);
e.Handled = true;
break;
}
}
}
You can use PreviewKeyDown Event as keydown event will not fire for system handled keys
private void TextBox_PreviewKeyDown(object sender, KeyRoutedEventArgs e)
{
if (Window.Current.CoreWindow.GetKeyState(VirtualKey.Control).HasFlag(CoreVirtualKeyStates.Down)&& e.Key == Windows.System.VirtualKey.Enter)
{
e.Handled = false;
}
}
As #Vignesh said, you can use PreviewKeyDown Event instead of keydown event and set the event as "handled" like e.Handled = true to prevent adding the new line.
KeyEventHandler keyeventHandler = new KeyEventHandler(rtbText_KeyDown);
rtbText.AddHandler(TextBox.PreviewKeyDownEvent, keyeventHandler, true);
Or based on this document, you can change how your TextBox reacts to key input by overriding Control.OnKeyDown. First, declare a custom class inherits from TextBox and override OnKeyDown event. Then you can continue to use keydown event to do something.
public class MyTextBox : TextBox
{
protected override void OnKeyDown(KeyRoutedEventArgs e)
{
if (Window.Current.CoreWindow.GetKeyState(VirtualKey.Control).HasFlag(CoreVirtualKeyStates.Down) && e.Key == VirtualKey.Enter)
{
e.Handled = true;
}
else
{
base.OnKeyDown(e);
}
}
}
.xaml:
<local:MyTextBox Width="400" AcceptsReturn="True" x:Name="rtbText"></local:MyTextBox>

How can I handle a customizable hotkey setting?

I'm trying to let my app's users an option to set a keyboard hotkey for for some feature.
Right now I'm using a TextBox with the KeyDown event as follows:
Key Hotkey;
private void SetHotKey(object sender, KeyEventArgs e)
{
(sender as TextBox).Text = e.Key.ToString();
Hotkey = e.Key;
e.Handled = true;
}
The problem with this approach is I can't set complex shortcuts, like [Ctrl]+[F4]. Is there some 3rd-party control that helps with that? Or a better-suited event to subscribe to on a textbox?
UPDATE: I've changed my code but it seems I'm still doing something wrong.
Key Hotkey;
bool lControl = false;
bool lAlt = false;
bool lShift = false;
private void SetHotKey(object sender, KeyEventArgs e)
{
var k = e.Key;
if (e.IsDown)
{
var tb = sender as TextBox;
tb.Text = "";
lControl = Keyboard.IsKeyDown(Key.LeftCtrl);
lAlt = Keyboard.IsKeyDown(Key.LeftAlt);
lShift = Keyboard.IsKeyDown(Key.LeftShift);
if (lControl) tb.Text += "Ctrl+";
if (lAlt) tb.Text += "Alt+";
if (lShift) tb.Text += "Shift+";
tb.Text = e.Key.ToString();
Hotkey = e.Key;
}
e.Handled = true;
}
How can I make it work and look cleaner as well?
To get you started in the right direction.
First you will need the real key behind the System/ImeProcessed/DeadCharProcessed key. This can be done with extension method for easier access.
public static Key RealKey(this KeyEventArgs e)
{
switch (e.Key)
{
case Key.System:
return e.SystemKey;
case Key.ImeProcessed:
return e.ImeProcessedKey;
case Key.DeadCharProcessed:
return e.DeadCharProcessedKey;
default:
return e.Key;
}
}
And then you should format your modifiers to the shortcut, not just the Key which was pressed. You can use Keyboard.ModifierKeys to get flags and for easier formatting, gather those in a list. And also you should block just a modifier key (Ctrl, Alt and Shift) from updating the hotkey.
private void SetHotKey(object sender, KeyEventArgs e)
{
var nonShortcuttableKeys = new[] { Key.LeftAlt, Key.RightAlt, Key.LeftCtrl, Key.RightCtrl, Key.LeftShift, Key.RightShift };
var actualKey = e.RealKey();
if (e.IsDown && !nonShortcuttableKeys.Contains(actualKey))
{
var tb = sender as TextBox;
var modifiers = new List<ModifierKeys>();
if (Keyboard.Modifiers.HasFlag(ModifierKeys.Control))
{
modifiers.Add(ModifierKeys.Control);
}
if (Keyboard.Modifiers.HasFlag(ModifierKeys.Alt))
{
modifiers.Add(ModifierKeys.Alt);
}
if (Keyboard.Modifiers.HasFlag(ModifierKeys.Shift))
{
modifiers.Add(ModifierKeys.Shift);
}
tb.Text = modifiers.Count == 0
? string.Format("{0}", actualKey)
: string.Format("{0} + {1}", string.Join(" + ", modifiers), actualKey);
Hotkey = actualKey;
}
e.Handled = true;
}
WinForms
You can check the KeyEventArgs.Modifiers if the Ctrl is pressed or not.
https://msdn.microsoft.com/en-us/library/system.windows.forms.keyeventargs.modifiers(v=vs.110).aspx
WPF
you can use this little snippet to check if the Control key is pressed:
Keyboard.IsKeyDown(Key.LeftCtrl)
If you want to use the MVVM pattern you can use the KeyBindings of the textbox (or any other control)
Create Key binding in WPF

WPF TextBox select all on Tab focus

I'm trying to select all the text when the focus is done with the Tab key. But I'm not able to find the right solution. Now I'm using the GotFocusEvent but now when i click with the mouse it raises the event.
The code that I'm using now is:
EventManager.RegisterClassHandler(typeof(System.Windows.Controls.TextBox), System.Windows.Controls.TextBox.GotKeyboardFocusEvent, new RoutedEventHandler(SelectAllText));
void SelectAllText(object sender, RoutedEventArgs e)
{
var textBox = sender as System.Windows.Controls.TextBox;
if (textBox != null)
if (!textBox.IsReadOnly)
textBox.SelectAll();
}
Referencing this answer
Textbox SelectAll on tab but not mouse click
What you have can be modified to...
EventManager.RegisterClassHandler(typeof(System.Windows.Controls.TextBox), System.Windows.Controls.TextBox.GotKeyboardFocusEvent, new KeyboardFocusChangedEventHandler(OnGotKeyboardFocus));
void OnGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
var textBox = sender as System.Windows.Controls.TextBox;
if (textBox != null && !textBox.IsReadOnly && e.KeyboardDevice.IsKeyDown(Key.Tab))
textBox.SelectAll();
}
You should also take notice of the details about clearing the selection on LostKeyboardFocus
Use MouseButtonState as below:
void SelectAllText(object sender, RoutedEventArgs e)
{
if (Mouse.LeftButton == MouseButtonState.Released)
{
var textBox = sender as System.Windows.Controls.TextBox;
if (textBox != null)
if (!textBox.IsReadOnly)
textBox.SelectAll();
}
}

Categories