Use a virtual Keyboard on focused Textboxes and DataGridView Cells

最后都变了- 提交于 2021-02-11 07:38:21

问题


In my Form I have various Textboxes that I write into with an in Form keyboard I created using Buttons. I have this code in Form.Load, which uses an event handler to determine which Textbox has the Focus:

For Each control As Control In Me.Controls
    If control.GetType.Equals(GetType(TextBox)) Then
        Dim textBox As TextBox = control
        AddHandler textBox.Enter, Sub() FocussedTextbox = textBox
     End If
Next

Then I use this on each button to write a specific character:

Private Sub btnQ_Click(sender As Object, e As EventArgs) Handles btnQ.Click
    If btnQ.Text = "Q" Then
        FocussedTextbox.Text += "Q"
    ElseIf btnQ.Text = "q" Then
        FocussedTextbox.Text += "q"
    End If
End Sub

Up to that point I'm good and everything works as intended. The problem is I also have a DataGridView I want to write into but can't focus on it selected cells as I do on Textboxes.

I tried this:

For Each control As Control In Me.Controls
    If control.GetType.Equals(GetType(TextBox)) Then
        Dim textBox As TextBox = control
        AddHandler textBox.Enter, Sub() FocussedTextbox = textBox
    ElseIf control.GetType.Equals(GetType(DataGridViewCell)) Then
        Dim DGVC As DataGridView = control
        AddHandler DGVC.CellBeginEdit, Sub() FocussedTextbox = DGVC
    End If
Next

But it just selects my last Textbox.

I declared the variable FocussedTextbox as Control so it's not specific to Textbox but any control.

Any help will be greatly appreciated.


回答1:


To add text to the current ActiveControl using Buttons, these Button must not steal the focus from the ActiveControl (otherwise they become the ActiveControl).
This way, you can also avoid all those FocusedTextbox = textBox etc. and remove that code.

You just need Buttons that don't have the Selectable attribute set. You can use a Custom Control derived from Button and remove ControlStyles.Selectable in its constructor using the SetStyle method:

Public Class ButtonNoSel
    Inherits Button
    Public Sub New()
        SetStyle(ControlStyles.Selectable, False)
    End Sub
End Class

Replace your Buttons with this one (or, well, just set the Style if you're already using Custom Controls).


To replace the existing Buttons with this Custom Control:

  • Add a new class object to your Project, name it ButtonNoSel, copy all the code above inside the new class to replace the two lines of code you find there.
  • Build the Project. You can find the ButtonNoSel Control in your ToolBox now. Replace your Buttons with this one.
  • Or, open up the Form's Designer file and replace (CTRL+H) all System.Windows.Forms.Button() related to the Virtual KeyBoard with ButtonNoSel.
  • Remove the existing event handlers, these are not needed anymore.

Add the same Click event handler in the Constructor of the class that hosts those Buttons (a Form or whatever else you're using).
You can then remove all those event handlers, one for each control, that you have now; only one event handler is needed for all:

Public Sub New()
    InitializeComponent()

    For Each ctrl As Control In Me.Controls.OfType(Of ButtonNoSel)
        AddHandler ctrl.Click, AddressOf KeyBoardButtons_Click
    Next
End Sub

Of course, you also don't need to add event handlers to any other control, this is all that's required.

Now, you can filter the Control types you want your keyboard to work on, e.g., TextBoxBase Controls (TextBox and RichTextBox), DataGridView, NumericUpDown etc.
Or filter only special cases that need special treatment (e.g., MonthCalendar).

To add the char corresponding to the Button pressed, you can use SendKeys.Send(): it will insert the new char in the current insertion point, so you don't need any other code to store and reset the caret/cursor position as it happens if you set the Text property of a Control.

In this example, I'm checking whether the ActiveControl is a TextBoxBase Control, then just send the char that the clicked Button holds.
If it's a DataGridView, first send F2 to enter Edit Mode, then send the char.
You could also just send a char (so, no filter would be required), but in this case, you'll replace, not add to, the existing value of that Cell.

Private Sub KeyBoardButtons_Click(sender As Object, e As EventArgs)
    Dim selectedButton = DirectCast(sender, Control)
    Dim keysToSend = String.Empty

    If TypeOf ActiveControl Is TextBoxBase Then
        keysToSend = selectedButton.Text
    ElseIf TypeOf ActiveControl Is DataGridView Then
        Dim ctrl = DirectCast(ActiveControl, DataGridView)
        If TypeOf ctrl.CurrentCell IsNot DataGridViewTextBoxCell Then Return
        SendKeys.Send("{F2}")
        keysToSend = selectedButton.Text
    Else
        ' Whatever else
    End If
    If Not String.IsNullOrEmpty(keysToSend) Then
        SendKeys.Send(keysToSend)
    End If
End Sub

► Note that {F2} is sent just once: when the Cell enters Edit Mode, the ActiveControl is a DataGridViewTextBoxEditingControl, hence a TextBox Control, handled by the TextBoxBase filter.

This is how it works (using just the code posted here):



来源:https://stackoverflow.com/questions/64225955/use-a-virtual-keyboard-on-focused-textboxes-and-datagridview-cells

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!