0

In the project I am working on I have created an on screen keyboard which is meant to type into either TextBoxes or DataGridViewCells.

The way I am attempting to accomplish this is with a few methods and variables. First there is a global variable called CurrentFocus which is an object that is set to be whatever object had the most recent focus that the keypad can type into. This variable was created because there doesn't seem to be a LastFocus style method within VB.Net.

I am setting the value of CurrentFocus by adding simple event handlers to the textboxes that I will be looking to type data in the following manner:

Dim randomTextbox As New Textbox
AddHandler randomTextbox.GotFocus, AddressOf TextboxGainsFocus

Private Sub TextboxGainsFocus(sender as Textbox, e As EventArgs)
    CurrentFocus = sender
End Sub

As for typing into the textboxes themselves, each key on the keyboard calls the following method, with the parameter value being the uppercase of whatever key is being pressed (So pressing the 'B' key sends "B" as a parameter)

Private Sub KeypadPress(ByCal key As Char)
    If TypeOf CurrentFocus Is TextBox Then
        If Char.IsDigit(key) Then
            CType(CurrentFocus, Textbox).Text &= key
        Else
            If shiftActive Then
                CType(CurrentFocus, Textbox).Text &= key
            Else
                CType(CurrentFocus, Textbox).Text &= Char.ToLower(key)
            End If
        End If
    End If
End Sub

I don't exactly have a way to easily set up a shift key that you hold down, so I've set up 'Shift' to be like Caps Lock where you just toggle it on or off. That is the purpose of the shiftActive boolean value.

Now all of the above code works perfectly fine. My issue right now is I can't get it to work with DataGridViewCells. First I've tried adding a similar EventHandler to the datagrids I am using

Dim randomGrid As New DataGridView
AddHandler randomGrid.GotFocus, AddressOf GridGainsFocus

Private Sub GridGainsFocus(sender As DataGridView, e As EventArgs)
    CurrentFocus = sender.CurrentCell
End Sub

And I have tried adding an ElseIf case to the KeypadPress method that detects when the CurrentFocus is a DataGridViewCell. That works fine. My issue is that it either doesn't have the correct cell selected, or it just doesn't do anything.

For example let's say I have 3 rows and 3 columns in my DataGridView. I select Cell (2,2) and then press a key on my keypad. If I put a breakpoint in to see what the value of CurrentFocus is when the KeypadPress method fires, it shows CurrentFocus as being Cell (0,0).

This doesn't always happen though. Sometimes I do get it randomly (and it does seem random) set as the proper Cell, but trying things like

CType(CurrentFocus, DataGridViewCell).Value &= key

In my Keypress method doesn't do anything to change the value of the DataGridViewCell.

So what exactly do I need to do? Is there a way to set up each Cell to have it's own handler and have it work that way? How would I make it so I can modify the value of the Cells themselves?

Thanks for the assistance.

Skitzafreak
  • 1,797
  • 7
  • 32
  • 51
  • Is there some reason you don’t use the operating systems on-screen keyboard? `Process.Start(PathToOnScreenKeyboardExecutable)` I am guessing this would completely eliminate any of the “focus” problems you are describing, but also would enable the “Shift” and any other key combinations. All this in one line of code. I am not trying to dissuade you from writing your own on-screen keyboard (which IMHO would not be trivial) … it just seems like you are re-inventing the wheel. – JohnG Feb 10 '19 at 06:25
  • [How to create a Button that can send keys to a conrol without losing focus - Virtual Keyboard](https://stackoverflow.com/a/36773585/3110834) – Reza Aghaei Feb 10 '19 at 06:41
  • @JohnG Long story short, because my boss is telling me to reinvent the wheel here I guess. He doesn't want a separate app to be the keyboard, he wants it built into the one I am creating. – Skitzafreak Feb 11 '19 at 12:33
  • @RezaAghaei the solution in the link you posted does not work. Maybe it works differently in C# than it does in VB.Net, but even with setting the button `ControlStyles.Selectable` to False, the keyboard buttons still gain focus and won't actually work as a virtual keyboard. – Skitzafreak Feb 11 '19 at 13:05

1 Answers1

0

So I figured out how to fix my problem, and I'll go over it step by step for anyone who has this issue in the future.

First, I added an Event Handler to my DataGridView that works in a manner similar to my Event Handler for my Textboxes.

Dim exGrid As DataGridView
AddHandler exGrid.CellEnter, AddressOf GridGainsFocus

Private Sub GridGainsFocus(sender As DataGridView, e As EventArgs)
    CurrentFocus = sender.CurrentCell
End Sub

The way this works, is that DataGridViewCells cannot gain Focus. Only the DataGridView itself can gain focus. Rather the Cells themselves are set as 'Selected' when they are being 'focused'. Thus you need to use the CellEnter event which triggers whenever a user selects a Cell. Now onto my Keypress method.

Private Sub KeypadPress(ByVal key As Char)
    If TypeOf CurrentFocus Is TextBox Then
        Me.ActiveControl = CurrentFocus
        If Char.IsDigit(key) Then
            SendKeys.SendWait(key)
        Else
            If shiftActive Then
                SendKeys.SendWait(key)
            Else
                SendKeys.SendWait(Char.ToLower(key))
            End If
        End If
    ElseIf TypeOf CurrentFocus Is DataGridViewCell Then
        If CType(CurrentFocus, DataGridViewCell).ReadOnly = False THen
            If Char.IsDigit(key) Then
                If CType(CurrentFocus, DataGridViewCell).Value.Equals(0) Then
                    CType(CurrentFocus, DataGridViewCell).Value = key
                Else
                    CType(CurrentFocus, DataGridViewCell).Value &= key
                End If
            End If
        End If
    End If
End Sub

So I'll go over this from the top down. First, you'll notice I modified the code for processing the key presses when trying to enter data into a TextBox. This is because for my TextBoxes I have them set up to have AutoComplete data to help with searching through data. My first setup presented in my original question, did not allow for the AutoComplete data to be used, because no actual key presses were being triggered.

So with the changes I have made the code now does the followings:

  1. When a button is pressed, if the CurrentFocus object is of type TextBox, then it changes the current focus to that object.
  2. Triggers a SenKey Event. This will trigger the TextBox AutoComplete.

Now for the DataGridViewCells. When I set the CurrentFocus object to a DataGridViewCell with my GridGainsFocus method, the object stores a perfect reference to that cell. So all I need to do is modify the value of that Cell.

Now for the purposes of my program, I only want the user putting digit values into the cells, so that's why I have the IsDigit if statement. And the specific If value.Equals(0) is setup to that when there is a default value of 0 in the cell, clicking the '5' key won't have the text input set as '05', but rather, '5'.

Skitzafreak
  • 1,797
  • 7
  • 32
  • 51