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 или клавишу пробела или клавиши со стрелками вверх или вниз, появится системное меню "Восстановить", "Переместить", ..., "Закрыть".
Позже Редактировать: я обнаружил две довольно странные вещи -
Если я закрою Form2 без использования мыши (т.е. нажмите кнопку "ОК" и нажмите "Ввод"), проблема не произойдет. Это происходит только в том случае, если я нажимаю кнопку ОК мышью.
Если я вызываю форму 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