vb.net Не могу установить фокус на текстовое поле формы Windows

Я попробовал все предложения, которые мог придумать или найти в Интернете, чтобы решить эту проблему, но безуспешно.

Я использую ShowDialog для отображения формы. Когда форма отображается в первый раз, она работает нормально - первое текстовое поле имеет мигающий курсор и готово для ввода. Форма закрывается с помощью одной из двух кнопок или элемента управления "X". Каждый раз, когда форма отображается после первого раза, курсор находится в текстовом поле, но останавливается. Нажатие почти любой клавиши размораживает курсор, но вместо этого все клавиши Enter, пробел и стрелки вверх и вниз вызывают контекстное меню формы ("Восстановить", "Переместить", ..., "Закрыть X"). Удаление ControlBox решает проблему (установив "ControlBox" в False в окне "Свойства"), но я не хочу этого делать. Возможно, ControlBox имеет фокус???

Первоначально, если форма была закрыта с помощью кнопки, эта кнопка имела фокус при следующем открытии формы. Я добавил строку Me.ActiveControl = TextBox1 на событие загрузки формы. Это предотвратило фокусировку кнопок. Я также попытался добавить Me.Show до Me.ActiveControl = TextBox1, но это не имело никакого эффекта. Я попытался установить активный элемент управления в обработчиках событий Activated и Shown, но это не имело значения. Я тоже пробовал TextBox1.Select() а также TextBox1.Focus() безуспешно.

Вот простая программа, которая демонстрирует проблему. Есть две формы Windows. В окне дизайна я добавил DataGridView (с одним столбцом) и кнопку для формы Form1. Вот код для формы 1:

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

Для Form2 я добавил 2 текстовых поля и кнопку "ОК" в окне дизайна. Кнопка не является кнопкой "Принять" или "Отменить". Вот код:

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

Если вы нажмете кнопку на Form1, она всегда вызывает Form2 с курсором, мигающим в TextBox1. В Form2 нажмите кнопку "ОК" или ControlBox "X", чтобы закрыть его. Нет проблем там.

Проблема возникает, если вы войдете в ячейку в DataGridView, войдете в режим редактирования и нажмете F10 (или F11). Первый раз, когда он правильно вызывает Form2, но если вы закроете Form2, а затем снова нажмете F10 (при редактировании DataGridView1), Form2 отобразится с замороженным курсором. В этот момент, если вы нажмете Enter или клавишу пробела или клавиши со стрелками вверх или вниз, появится системное меню "Восстановить", "Переместить", ..., "Закрыть".

Позже Редактировать: я обнаружил две довольно странные вещи -

  1. Если я закрою Form2 без использования мыши (т.е. нажмите кнопку "ОК" и нажмите "Ввод"), проблема не произойдет. Это происходит только в том случае, если я нажимаю кнопку ОК мышью.

  2. Если я вызываю форму Form2, нажимая кнопку Button1 вместо нажатия клавиши F10, а затем нажимая и отпуская клавишу Alt, курсор останавливается, и те же четыре клавиши вызывают системное меню. Оказывается, это работает в других программах (я использую XP), а не только в моей, при условии, что на форме нет меню. Я предполагаю, что это особенность доступности. Итак, теперь мой вопрос: почему эта программа действует так, как будто нажата клавиша Alt, и есть ли способ предотвратить или исправить ее?

1 ответ

Решение

Чего я не знал, так это того, что клавиша F10 (например, клавиша Alt) меняет фокус формы на меню (если оно есть) или значок строки заголовка (если он есть). Я добавил Menustrip со стандартными элементами в Form2, чтобы убедиться, что это так. Что я до сих пор не понимаю, так это то, почему нажатие клавиши F10 в форме Form1 влияет на форму Form2. В любом случае добавление следующего кода в Form1 решает проблему. В моей настоящей программе я планирую добавить этот код в свой собственный класс, производный от DataGridView. В этом случае нет необходимости проверять, что ActiveControl формы является сетью просмотра данных (что я и сделал в следующем коде).

По сути, я просто переместил код для обработки F10 из подпрограммы CellKeyDown в ProcessCmdKey и добавил Return True отменить нормальную обработку ключа. ProcessCmdKey сначала перехватывает клавишу F10, поэтому другие подпрограммы (DataGridView1_EditingControlShowing и CellKeyDown) не нужны.

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
Другие вопросы по тегам