WPF how to manage ENTER hit on TextBox for messaging purpose

2.7k views Asked by At

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 :

  1. Using CTR or SHIFT, I can create a new line in my TextBox :) ;
  2. I cannot paste a multiline text from the Clipboard: only the first line will be pasted, nothing else :( ;
  3. 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) ;
  4. 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 !

1

There are 1 answers

7
Jens On

The Result of the Solution is this:

Normal
Normal

After one SHIFT + ENTER
enter image description here

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