Multi-line textbox and KeyPress event unusual behavior

keb1965

Well-known member
Joined
Feb 9, 2009
Messages
103
Programming Experience
10+
I have several multi-line textboxes that I want to lose focus (i.e. when the user presses the right arrow key) but the control wil not relinquish the focus.

Simply put, I first verify if the selection start is at the end of the text, if it is, and the user presses the arrow key, it should move to the next textbox.

some debug.print code placed in strategic locations indicates that the target textbox gets focus and immediately loses it and the source textbox gains focus once again. Essentially not allowing the textbox to lose focus.

VB.NET:
Select Case
Case Keys.Right
tbRight.Focus()
Case Keys.Left
tbLeft.Focus
End Select

It should be simple ... I don't understand the problem. After changing the source textbox multi-line property to false, it behaves as expected. Is this a "feature" .. surely I don't have to resort to "SendKeys"
 
Assuming that you want to follow the Tab order, this is what your code should look like:
VB.NET:
Private Sub TextBoxes_KeyDown(ByVal sender As Object, _
                              ByVal e As System.Windows.Forms.KeyEventArgs) Handles TextBox1.KeyDown, _
                                                                                    TextBox2.KeyDown
    Dim field As TextBox = DirectCast(sender, TextBox)

    Select Case e.KeyCode
        Case Keys.Left
            If field.SelectionStart = 0 Then
                'Select the previous control.
                Me.SelectNextControl(field, False, True, True, True)
            End If
        Case Keys.Right
            If field.SelectionStart = field.TextLength Then
                'Select the next control.
                Me.SelectNextControl(field, True, True, True, True)
            End If
    End Select
End Sub
 
Unfortunately, that is part of the problem. I need to move among textboxes in all 4 directions, up, down, left and right. For now, I can simply use sendkeys to move to the correct location by stacking +{tab} or {tab} as needed, but I loath the thought of using sendkeys.

I thought for a while there was something seriously wrong with the code until I realized it was the contol that was preventing the focus from changing.
 
The principle remains the same but you have to do a little more work. You might change the details a bit but this worked for me:
VB.NET:
Public Class Form1

    Private textBoxCoordinates As New Dictionary(Of TextBox, Point)

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Me.textBoxCoordinates.Add(Me.TextBox1, New Point(0, 0))
        Me.textBoxCoordinates.Add(Me.TextBox2, New Point(1, 0))
        Me.textBoxCoordinates.Add(Me.TextBox3, New Point(0, 1))
        Me.textBoxCoordinates.Add(Me.TextBox4, New Point(1, 1))
    End Sub

    Private Sub TextBoxes_KeyDown(ByVal sender As Object, _
                                  ByVal e As System.Windows.Forms.KeyEventArgs) Handles TextBox1.KeyDown, _
                                                                                        TextBox2.KeyDown, _
                                                                                        TextBox3.KeyDown, _
                                                                                        TextBox4.KeyDown
        Dim current As TextBox = DirectCast(sender, TextBox)

        If current.SelectionLength = 0 Then
            Select Case e.KeyData
                Case Keys.Left
                    If current.SelectionStart = 0 Then
                        Me.SelectNextTextBox(current, ArrowDirection.Left)
                        e.SuppressKeyPress = True
                    End If
                Case Keys.Right
                    If current.SelectionStart = current.TextLength Then
                        Me.SelectNextTextBox(current, ArrowDirection.Right)
                        e.SuppressKeyPress = True
                    End If
                Case Keys.Up
                    Dim lineIndex As Integer = current.GetLineFromCharIndex(current.SelectionStart)

                    If lineIndex = 0 Then
                        Me.SelectNextTextBox(current, ArrowDirection.Up)
                        e.SuppressKeyPress = True
                    End If
                Case Keys.Down
                    Dim lineIndex As Integer = current.GetLineFromCharIndex(current.SelectionStart)

                    If lineIndex = current.Lines.GetUpperBound(0) Then
                        Me.SelectNextTextBox(current, ArrowDirection.Down)
                        e.SuppressKeyPress = True
                    End If
            End Select
        End If
    End Sub

    Private Sub SelectNextTextBox(ByVal current As TextBox, ByVal direction As ArrowDirection)
        Dim coordinates As Point = Me.textBoxCoordinates(current)

        Select Case direction
            Case ArrowDirection.Left
                coordinates.Offset(-1, 0)
            Case ArrowDirection.Right
                coordinates.Offset(1, 0)
            Case ArrowDirection.Up
                coordinates.Offset(0, -1)
            Case ArrowDirection.Down
                coordinates.Offset(0, 1)
        End Select

        If coordinates.X < 0 Then
            coordinates.X = 1
        ElseIf coordinates.X > 1 Then
            coordinates.X = 0
        ElseIf coordinates.Y < 0 Then
            coordinates.Y = 1
        ElseIf coordinates.Y > 1 Then
            coordinates.Y = 0
        End If

        For Each entry As KeyValuePair(Of TextBox, Point) In Me.textBoxCoordinates
            If entry.Value = coordinates Then
                entry.Key.Select()
            End If
        Next
    End Sub

End Class
Note the setting of e.SuppressKeyPress, which fixes your original issue of the focus shifting right back again.
 
Back
Top