简体   繁体   中英

vb.net Can't set focus to windows form textbox

I've tried every suggestion I could think of or could find online to solve this problem, without success.

I use ShowDialog to display a form. The first time the form is displayed, it works OK - the first textbox has a blinking cursor and is ready for input. The form is closed by one of two buttons or the ControlBox "X". Every time the form is displayed after the first time, the cursor is in the textbox, but is frozen. Pressing almost any key will unfreeze the cursor, but the Enter key, spacebar, and up and down arrows all bring up the form's context menu ("Restore", "Move", ... , "X Close") instead. Removing the ControlBox solves the problem (Setting "ControlBox" to False in Properties window), but I don't want to do that. Possibly the ControlBox has the focus???

Initially, if the form was closed using a button, that button had focus the next time the form was opened . I added the line Me.ActiveControl = TextBox1 to the form's Load event. This prevented the buttons from having focus. I also tried adding Me.Show before Me.ActiveControl = TextBox1 , but it had no effect. I tried setting the active control in the form's Activated and Shown event handlers, but it made no difference. I also tried TextBox1.Select() and TextBox1.Focus() without success.

Here is a simple program that demonstrates the problem. There are two Windows forms. In the design window, I added a DataGridView (with one column) and a Button to Form1. Here is the code for Form1:

Public Class Form1
    Private Sub Button1_Click(ByVal sender As System.Object, _
        ByVal e As _System.EventArgs) Handles Button1.Click
        Dim result As DialogResult
        Dim TForm As Form2
        TForm = New Form2
        result = TForm.ShowDialog
    End Sub

    Private Sub DataGridView1_EditingControlShowing _
    (ByVal sender As Object, ByVal e As _
    System.Windows.Forms.DataGridViewEditingControlShowingEventArgs) _
    Handles DataGridView1.EditingControlShowing

        If TypeOf e.Control Is TextBox Then
            RemoveHandler DirectCast(e.Control, TextBox).KeyDown, AddressOf CellKeyDown
            AddHandler DirectCast(e.Control, TextBox).KeyDown, AddressOf CellKeyDown
        End If
    End Sub

    Private Sub CellKeyDown(ByVal sender As Object, ByVal e As KeyEventArgs)
        Select Case e.KeyCode
            Case Keys.F10
                With DataGridView1
                    .EndEdit()
                    Dim result As DialogResult
                    Dim TestForm2 As Form2
                    TestForm2 = New Form2
                    result = TestForm2.ShowDialog
                    TestForm2 = Nothing
                    .BeginEdit(False)
                    Me.ActiveControl = .EditingControl ' This makes the cursor visible
                End With
            Case Keys.F11
                With DataGridView1
                     .EndEdit()
                    Dim result As DialogResult
                    result = Form2.ShowDialog
                    .BeginEdit(False)
                    Me.ActiveControl = .EditingControl
                End With
        End Select
    End Sub

End Class

For Form2, I added 2 textboxes and an "OK" button in the design window. The button is not set as the form's Accept or Cancel button. Here's the code:

Public Class Form2
    Private Sub btnOK_Click(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles btnOK.Click
        Me.Close()
    End Sub

    Private Sub Form2_Load(ByVal sender As Object, _
    ByVal e As System.EventArgs) Handles Me.Load
        Me.ActiveControl = Me.TextBox1
    End Sub
End Class

If you press the button on Form1, it always brings up Form2 with the cursor blinking in TextBox1. In Form2, press the "OK" button or the ControlBox "X" to close it. No problem there.

The problem happens if you go into a cell in the DataGridView, enter edit mode, and press F10 (or F11). The first time it brings up Form2 correctly, but if you close Form2, then press F10 again (while editing DataGridView1), Form2 is displayed with the cursor frozen. At this point, if you press Enter or the spacebar or the up or down arrow keys, the "Restore", "Move", ... , "Close" system menu pops up.

Later Edit: I discovered two pretty strange things -

  1. If I close Form2 without using the mouse (ie Tab to the OK button and press Enter) the problem doesn't happen. It only happens if I click on the OK button with the mouse.

  2. If I bring up Form2 by pressing Button1 instead of pressing F10 and then press and release the Alt key, the cursor freezes and the same four keys bring up the system menu. It turns out this works in other programs (I'm using XP), not just mine, provided there is no menustrip on the form. I'm guessing this is an accessibility feature. So now my question is: Why is this program acting as if the Alt key was pressed and is there a way to prevent or correct it?

What I didn't know is that The F10 key (like the Alt key) changes the focus of a form to the menu (if there is one) or the Title Bar icon (if there is one). I added a menustrip with the standard items to Form2 just to verify that this is the case. What I still don't understand is why pressing F10 on Form1 has this effect on Form2. In any event, adding the following code to Form1 solves the problem. In my actual program, I plan to add this code to my own class derived from DataGridView. In that case it won't be necessary to make sure that the form's ActiveControl is the datagridview (which I did do in the following code).

Basically, I just moved the code for processing F10 from the CellKeyDown sub to ProcessCmdKey, and added Return True to cancel the normal processing of the key. ProcessCmdKey intercepts the F10 key first, so the other subs (DataGridView1_EditingControlShowing and CellKeyDown) are not needed.

Protected Overrides Function ProcessCmdKey(ByRef msg As System.Windows.Forms.Message, ByVal keyData As System.Windows.Forms.Keys) As Boolean
    If TypeOf Me.ActiveControl Is DataGridViewTextBoxEditingControl Then
        If keyData = Keys.F10 Then
            DataGridView1.EndEdit()
            Dim TestForm2 As Form2
            TestForm2 = New Form2
            Dim result As DialogResult
            result = TestForm2.ShowDialog
            TestForm2.Dispose()
            TestForm2 = Nothing
            DataGridView1.BeginEdit(False)
            Me.ActiveControl = DataGridView1.EditingControl
            Return True
        End If
    End If
    Return MyBase.ProcessCmdKey(msg, keyData)
End Function

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM