I have a TextBox (multiline) and if I press Ctrl+Enter it just makes a new line. But I would also like to do this on Shift+Enter.
I tried:
messageTextBox_KeyDown(null, new KeyEventArgs(Keys.Control | Keys.Enter));
But this is not working.
I think that I can do this:
int lastSelectionStart = messageTextBox.SelectionStart;
messageTextBox.Text = messageTextBox.Text.Insert(messageTextBox.SelectionStart, Environment.NewLine);
messageTextBox.SelectionStart = lastSelectionStart;
But I don't like this.
How can I make it so that Shift+Enter will be the same as Ctrl+Enter?
My current code:
KeyDownEvent
if (e.KeyCode == Keys.Enter)
{
e.Handled = true;
if (e.Shift)
{
}
else if (!e.Control)
{
sendButton_Click(null, null);
}
}
In KeyPress event:
if (e.KeyChar == (char)13)
{
e.Handled = true;
return;
}
This is because I want to use the Enter key alone as Send button.
Sounds to me like the real problem you are fighting is the form's AcceptButton property. You cannot fix this with the KeyDown event handler, the keystroke is processed before it ever gets to the event.
This can be fixed by overriding the form's ProcessCmdKey() method but the cleanest way is to just create your own TextBox derived control. You can override its IsInputKey() method to tell Winforms that you want to see the Ctrl+Enter key. Add a new class to your project and paste the code shown below. Compile. Drop the new control from the top of the toolbox. Note how you can alter the class to your convenience to make it more adept at being a chat input box.
using System;
using System.Windows.Forms;
class ChatBox : TextBox {
public ChatBox() {
this.Multiline = true;
}
protected override bool IsInputKey(Keys keyData) {
if (keyData == (Keys.Shift | Keys.Enter)) return true;
return base.IsInputKey(keyData);
}
protected override void OnKeyDown(KeyEventArgs e) {
if (e.KeyData == (Keys.Shift | Keys.Enter)) {
int pos = this.SelectionStart;
this.SelectedText = Environment.NewLine;
this.SelectionStart = pos;
e.Handled = e.SuppressKeyPress = true;
return;
}
base.OnKeyDown(e);
}
}
Related
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);
}
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>
I have this class inherited by RichTextBox. I overrided void OnKeyDown to check for incoming Tabs, because I don't want them.
Using breakpoints, I see that the overrided void is called, but it doesn't do its job.
Here is the code:
class ProgrammingTextBox : RichTextBox
{
protected override void OnKeyDown(KeyEventArgs e)
{
if (e.KeyCode == Keys.Tab)
{
// Tab was pressed, replace it with space
e.SuppressKeyPress = true; // Don't press Tab
for (int i = 0; i < 4; i++)
{
base.OnKeyDown(new KeyEventArgs(Keys.Space); // Repeat space 4 times
}
}
else base.OnKeyDown(e);
}
}
The wanted output should be text with 4 spaces but results as a Tab, like the OnKeyDown call from the for loop wasn't called.
Any idea what should I do?
base.OnKeyDown(new KeyEventArgs(Keys.Space);
OnKeyDown() on OnKeyPress() only generates notifications, their job is not to modify the Text property. That's up to you, assign the SelectedText property. Like this:
class ProgrammingTextBox : RichTextBox {
protected override bool IsInputKey(Keys keyData) {
if (keyData == Keys.Tab) return true;
return base.IsInputKey(keyData);
}
protected override void OnKeyDown(KeyEventArgs e) {
if (e.KeyCode == Keys.Tab) {
const string tabtospaces = " ";
var hassel = this.SelectionLength > 0;
this.SelectedText = tabtospaces;
if (!hassel) this.SelectionStart += tabtospaces.Length;
e.SuppressKeyPress = true;
}
else base.OnKeyDown(e);
}
}
When working with Tab (which is not an ordinary key - it can, say, be preprocessed and move focus control) you have to override a different method, ProcessCmdKey:
https://msdn.microsoft.com/en-us/library/system.windows.forms.control.processcmdkey(v=vs.110).aspx
Something like this
protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
if (keyData == Keys.Tab) {
//TODO: Your code here
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
see also
https://msdn.microsoft.com/en-us/library/system.windows.forms.textboxbase.acceptstab.aspx
The problem
I'm trying to get a text field to process Tab and Escape to handle a user password field. I currently have an event firing on PreviewKeyDown to allow me to catch Escape and Tab on the KeyDown event and then a KeyDown event to process it as follows:
private void passwordText_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Tab)
{
bool success = this.SelectNextControl(ActiveControl, true, false, true, true);
e.Handled = true;
e.SuppressKeyPress = true;
}
else if (e.KeyCode == Keys.Escape)
{
keepPassword = false;
bool success = this.SelectNextControl(ActiveControl, true, false, true, true);
e.Handled = true;
e.SuppressKeyPress = true;
}
else
{
e.Handled = false;
base.OnKeyDown(e);
}
}
private void passwordText_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
if (e.KeyCode == Keys.Tab || e.KeyCode == Keys.Escape)
{
e.IsInputKey = true;
}
}
The problem I'm running into is that the SelectNextControl command returns true, but the ActiveControl does not change. It's still on the passwordText control.
Further Insight
It's calling the Leave override, and then the Enter override. If I remove Leave from the events, it correctly selects the next control. I'm posting the code from Leave here while I puzzle things through:
private void passwordText_Leave(object sender, EventArgs e)
{
if (passwordText.ReadOnly == false)
{
if (keepPassword) // This is used to handle the case of using ESC to cancel the password entry.
{
// Change user password accordingly.
password = GlobalDataStore.HashPassword(passwordText.Text);
}
else
{
keepPassword = true;
}
if (String.IsNullOrWhiteSpace(passwordText.Text))
{
passwordText.Text = "";
}
else
{
passwordText.Text = "(Hashed Password)";
}
passwordText.UseSystemPasswordChar = false;
passwordText.ReadOnly = true;
}
}
Current Workaround
I moved the guts of the Leave Event into a separate function, ProcessPasswordTextLeave(). Inside the KeyDown event, before I do the select, I remove the Leave Event, do the Select, run the ProcessPasswordTextLeave() function, then add the Leave Event again. Messy, but it works for now. I would prefer something more elegant. I'd also like to know why processing it as a Leave event restore focus to it.
I have this requirement that the users need to use the keyboard numpad keys to control specific button assigned to it and perform each function.
Example:
if Numpad key 0 is press then Button0 will be triggered.
Or
if(Numpad0 is pressed)
{
//do stuff
if (inputStatus)
{
txtInput.Text += btn0.Text;
}
else
{
txtInput.Text = btn0.Text;
inputStatus = true;
}
}
else if(Numpad1 is pressed)
{
//do stuff
}
In my form i have a split container then all Buttons are located on a group box.
Set KeyPreview to true and handle KeyDown:
private void Form_KeyDown(object sender, KeyDownEventArgs e) {
if(e.KeyCode >= Keys.NumPad0 && e.KeyCode <= Keys.NumPad9)
((Button) this["Button" + (e.KeyCode - Keys.NumPad0).ToString()]).PerformClick();
}
I haven't tested it, but that's about how I would do it.
Add a window handler for the keydown event:
private void Window_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys./*numpad keys*/)
{
// do something such as call the click handler for your button!
e.Handled = true;
}
}
Or you can do it for the Form instead! You didn't specify, but the logic is the same.
And don't forget to turn KeyPreview on. Use Keys.NumPad0, Keys.NumPad1, etc for the number pad keys. See MSDN for the Keys Enumeration.
If you want to prevent the keys default action being performed set e.Handled = true as shown above.
Set the Form's KeyPreview to true and handle the Form.KeyDown event.
private void Form_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.NumPad0)
{
Button0.PerformClick()
e.Handled = true;
}
else if (e.KeyCode == Keys.NumPad1)
{...}
...
}
By using ProcessCmdkey Solves the Problem:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.Numpad0)
{
Numpad0.PerformClick();
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
Thanks