WPF how to manage ENTER hit on TextBox for messaging purpose - c#

Take a simple messaging program, such as Steam friend conversation.
When you hit ENTER, the message is sent, and the message field is emptied.
When you enter CTRL/SHIFT + ENTER a newline is created. If your cursor is not at the end of the input text, then all the text appearing after your cursor will be sent to a newline.
Well, how do you accomplish such a feat ?
Furthermore, I'd like to know how to have the aforementioned features and also how to still be able to paste a multiline text into the message field.
For now, this is my code. It's something but does not get all the job done :
private bool ctrlOrShift = false;
private void MessageField_KeyDown( object sender, KeyEventArgs e )
{
if( e.Key == Key.LeftCtrl || e.Key == Key.LeftShift )
{
ctrlOrShift = true;
}
else if( e.Key == Key.Enter && ctrlOrShift != true && !MessageField.AcceptsReturn )
{
AsyncSendMessage();
}
else if( e.Key == Key.Enter && ctrlOrShift != true && MessageField.AcceptsReturn )
{
MessageField.AcceptsReturn = false;
}
else if( e.Key == Key.Enter && ctrlOrShift == true )
{
ctrlOrShift = false;
MessageField.AcceptsReturn = true;
MessageField.Text += System.Environment.NewLine;
MessageField.Select( MessageField.Text.Length, 0 );
MessageField.AcceptsReturn = false;
}
else
{
ctrlOrShift = false; // Canceled because follow-up key wat not ENTER !
}
}
The following scenarios occur :
Using CTR or SHIFT, I can create a new line in my TextBox :) ;
I cannot paste a multiline text from the Clipboard: only the first line will be pasted, nothing else :( ;
If I use CTRL + V to paste content, the MessageField_KeyDown event takes the CTRL hit is taken into account, therefore, if I press ENTER, message is not sent but a newline is created instead :/ (in a case where you would paste a content and send it right away) ;
If my cursor position is before the end of the input text, CTR/SHIT + ENTER will create a newline at the end of the text regardless of the cursor position :/
So, how can I tweak this code ? Thanks for the help !

The Result of the Solution is this:
Normal
After one SHIFT + ENTER
When you push ENTER it looks like in Normal only without text in the box
As mentioned in the comments you could use the AcceptsReturn and TextWrapping properties for a multiline textbox (like in steam).
Use Height = Auto for a better looking one (otherwise you only have one line and all other lines disappear)
XAML
for Textbox:
<TextBox HorizontalAlignment="Left" Height="Auto" Margin="10,10,0,0"
TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top"
Width="497" AcceptsReturn="True"
KeyDown="TextBoxKeyDown" PreviewKeyDown="TextBoxPreviewKeyDown"/>
Event Handler:
This is not that easy as i thought first :'D But i figured it out.
When you use the AcceptsReturn Property the Enter Key is Handeled by the AcceptsReturn. So if you push enter you will see a new line instead of a Send() if you programm is like this:
private void TextBoxKeyDown(object sender, KeyEventArgs e)
{
var textbox = sender as TextBox;
// This will never happen because the Enter Key is handeled before
// That means TextBoxKeyDown is not triggered for the Enter key
if (e.Key == Key.Enter &&
!(Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) &&
!(Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.LeftShift)))
{
// Send(textBox.Text)
textbox.Text = "";
}
}
So you need to implement the PreviewKeyDown eventhandler. Because in the PreviewKeyDown event handler the Event is routed through the (Parent)Elements.
Look at this Answer
Also note the e.Handled = true line. Otherwise the Enter is routed through the method to the AcceptsReturn and you will have 2 lines after the enter, but the Textbox is empty.
With this method the KeyDown Method is no longer needed!
private void TextBoxPreviewKeyDown(object sender, KeyEventArgs e)
{
// Enter key is routed and the PreviewKeyDown is also fired with the
// Enter key
var textbox = sender as TextBox;
// You don't want to clear the box when CTRL and/or SHIFT is down
if (e.Key == Key.Enter &&
!(Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) &&
!(Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift)))
{
textbox.Text = "";
e.Handled = true;
}
}
The pros of the Multiline Textbox is that you can copy and paste
+ you have no problems with CTRL pushed or not.
What do you think about it?
Hope it helps

Related

Forms, basic calculator key triggering problem

private void UserInputText_KeyDown(object sender, KeyEventArgs e)
{
if ((e.KeyCode == Keys.D4 && e.Modifiers == Keys.Shift) || (e.KeyCode == Keys.Add))
{
if (String.IsNullOrEmpty(UserInputText.Text))
{
MessageBox.Show("Bir sayı giriniz.");
UserInputText.Clear();
return;
}
if (double.TryParse(UserInputText.Text, out sayı1))
{
CalculationResultText.Text = sayı1 + " + ";
islem = "+";
UserInputText.Clear();
}
else
{
MessageBox.Show("Sadece sayı değeri girebilirsiniz.");
UserInputText.Clear();
}
}
}
I am coding a basic forms calculator. I am trying to trigger addition function and clear the textbox when textbox is focused and user presses "+" key. "if (String.IsNullOrEmpty(UserInputText.Text)) and else conditions work well. But if no Message boxes shows up as in the
if (double.TryParse(UserInputText.Text, out sayı1)) condition, the "+" character remains in the textbox as in the image. Thanks for help.
If I understand correctly, you want to first check the character that was typed in and if it's incorrect then you want to prevent this character from appearing?
If so, then you need to set e.Handled = true property when you want to prevent it.
This call tells the GUI element (your TextBox) that "I did all the checks for this event (i.e. KeyDown event), and I don't want you to contribute in handling of this event (i.e. normally the TextBox would try to add this character to its Text property, but you prevent it)".
Check out documentation on KeyEventArgs.Handled.
KeyPress event enables you to prevent any further changes in the TextBox.
You can do that thanks to Handled property of KeyPressEventArgs
private void UserInputText_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == '+')
{
UserInputText.Clear();
e.Handled = true;
}
}

How to move to next textbox form a multiline textbox

I have this procedure wich moves the cursor to the next textbox up/down within non multiline textbox.
When using key down from multiline textbox, cursor moves to the next textbox but does not focus in the next textbox when pressing key up idem. With key enter it moves from multiline to the next textbox and focuses it.
What can be the reason ?
I have 8 textboxes which are groupped with tag properties from 0 to 7. TxtboxNbrLimit is set to 8
private void textBox_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter || e.KeyCode == Keys.Down)
{
if (KeyIndex < TxtboxNbrLimit)
++KeyIndex;
if (KeyIndex == TxtboxNbrLimit)
{
SaveBtn.Select();
return;
}
if (_textBox[KeyIndex].Text != "")
ChangeDone = true;
_textBox[KeyIndex].SelectionStart = 0;
_textBox[KeyIndex].SelectionLength = _textBox[KeyIndex].Text.Length;
_textBox[KeyIndex].Select();
_textBox[KeyIndex].Focus();
}
else
{
if (e.KeyCode == Keys.Up)
{
if (KeyIndex > 0)
--KeyIndex;
_textBox[KeyIndex].SelectionStart = 0;
_textBox[KeyIndex].SelectionLength = _textBox[KeyIndex].Text.Length;
_textBox[KeyIndex].Select();
_textBox[KeyIndex].Focus();
}
}
}
Try to move your logic to key up event instead of key down. That will work fine, TESTED.
Maybe multiline TextBox has some kind of event handler internally to handle up/down keyboard key pressed event, to move cursor between text lines. So your code work will be overridden by that internal behavior.
And in case you put it in key up event, the opposite happened. Your code logic will override effect of TextBox's internal behavior. So if the TextBox contains multiline text, the cursor will move to next/previous TextBox instead of moving between text lines inside the multiline TextBox.

How to change the focus inside a form and make the new control deal with the key pressed?

I have a form with a search box and a datagridview with the results.
What I need is the search box to always get the focus whenever I press a char or number key, and then process the key. So, for instance, if my focus is on the datagrid, and I press a char, it'll go to the search box. (Additionally, whenever the Up or Down arrows are pressed in the form, the focus will go to the datagrid, but I got no problem with that.)
Now, the code below will work as a charm for chars. When I get to the numbers, though, I can't do it the same way (as my e.KeyCode.ToString() will not give me the number, but a "d0" or "numpad0").
private void Form_KeyDown(object sender, KeyEventArgs e)
{
if (!this.tbxSearch.Focused)
{
if ((e.KeyCode >= Keys.A) && (e.KeyCode <= Keys.Z))
{
this.tbxSearch.Focus();
this.tbxSearch.Text = (e.Shift) ? e.KeyCode.ToString() : e.KeyCode.ToString().ToLower();
this.tbxSearch.SelectionStart = this.tbxSearch.Text.Length;
}
}
}
Of course, I might do it just about the same way, and simply get the last char in the "e.KeyCode.ToString()", but it doesn't seem alright to me. I mean, there must be a simpler way of just changing the focus and then making the control deal with the key pressed.
I've tried making it in the PreviewKeyDown event, but it won't be triggered by the form (even with the KeyPreview property set to true):
private void Form_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
if ((e.KeyCode == Keys.Down) || (e.KeyCode == Keys.Up))
this.dgvResults.Focus();
else
this.tbxSearch.Focus();
}
So I was left wondering: how can I change the focus on a form and let the new control deal with the key?
You can check if a key is a digit like this:
private Keys[] numericKeys =
{
Keys.D1,
Keys.D2,
Keys.D3,
Keys.D4,
Keys.D5,
Keys.D6,
Keys.D7,
Keys.D8,
Keys.D9,
Keys.D0,
Keys.NumPad0,
Keys.NumPad1,
Keys.NumPad2,
Keys.NumPad3,
Keys.NumPad4,
Keys.NumPad5,
Keys.NumPad6,
Keys.NumPad7,
Keys.NumPad8,
Keys.NumPad9
};
...
bool isDigit = numericKeys.Contains(e.KeyCode);
or like this:
bool isDigit = Char.IsDigit((char)e.KeyCode);
or:
bool isLetterOrDigit = char.IsDigit((char)e.KeyCode);

Textbox and messagebox

I have 2 input box on my form. If user enter data he can press enter to see if they are correct or in the other case messagebox will appear with error. Now i have small problem. When messagebox appears and user presses enter, msgbox disappear and immediately appear another one. I wanted to disappear, and let user change their data. How can i fix that?
I tried to fix that in that way: i added invisible textbox, when user press enter this textbox gains focus, if there is error msgbox appears and in the end sender gains focus.
code:
private void login(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
focus.Focus();
if (password.Password == "" || account.Text == "")
{
MessageBoxResult result = MessageBox.Show("Fill login and password.");
}
if(sender.GetType() == account.GetType())
((TextBox)sender).Focus();
else
((PasswordBox)sender).Focus();
}
}
Try setting e.Handled = true; to prevent propagating of the key press to your text box.
try this:
if (e.Key == Key.Enter && !string.IsNullOrWhiteSpace(txtPass.Text))
{
if (1 + 1 != 3)
{
MessageBox.Show("Wrong!!!");
txtPass.Clear();
txtPass.Focus();
}
}

Allow only " Shift + _ " from ignored chars

I am using this code to block some keys in text box.
private void tb_MyTextBox_KeyDown(object sender, KeyEventArgs e)
{
// Handle Shift case
if (Keyboard.Modifiers == ModifierKeys.Shift)
e.Handled = true;
// Handle all other cases
if (!e.Handled && (e.Key < Key.D0 || e.Key > Key.Z))
{
if (e.Key < Key.NumPad0 || e.Key > Key.NumPad9)
{
if (e.Key != Key.Back)
e.Handled = true;
}
}
}
This code blocks all the keys except A to Z and 0 to 9. But I also want to allow _ which you get by Shift + _ .
How to do this for only Shift + _ ?????
(All the code is on KeyDown event of Siverlight)
I don't like the idea of checking the KeyPress args, since there are LOTS of cases it doesn't account for (such as alternate keyboard layouts, CAPS LOCK being on, or pasting text from the clipboard).
I see two ways of doing this properly:
Create a behaviour that you attach to the TextBox. The behaviour would keep track of the current text, and subscribe to the TextChanged event. Whenever the event fires, the behaviour would ensure the text is valid, and if not, just set the text back to the last valid value it saw.
Create a subclass of TextBox, in which you override the OnTextInput() method. Here you can do whatever checks you want, and if you don't like the text that was input (e.Text), just set e.Handled = true and the input will be ignored.
You can do it like that:
if ((e.Modifiers == Keys.Shift) && (e.KeyCode == Keys.OemMinus))
{
// Do Something
}

Categories

Resources