Visual Studio ComboBox won't cycle through items with up/down arrows once users types - vb.net

I have a userform with a dropdown combobox that is filled with items when the form is opened. If the box has focus, the up/down arrow keys will cycle through the items (as it should), or the user can select from the drop down list and still be able to use the up/down arrows from there. If the user starts typing, the box is set to append from the list items, but that disables the up/down arrow keys from cycling through ALL the items. At that point, it only cycles through the items that start with whatever the user typed. I would like it to erase the typed data and cycle through all the combobox items (starting at the index was whatever was appended) just like it does in the VBA version.
Even if the user types something, then selects a completely different item from the dropdown, the next time up/down keys are pressed, it only goes back to whatever was typed.
I attempted to handle this in the arrow up/down keydown (or keyup) event as follows:
Private Sub SeriesBox_KeyDown(sender As Object, e As KeyEventArgs) Handles SeriesBox.KeyDown
Dim CurIndex As Integer = SeriesBox.FindStringExact(SeriesBox.Text)
Select Case e.KeyCode
Case Keys.Down
SeriesBox.Text = String.Empty
SeriesBox.SelectedIndex = CurIndex + 1
Case Keys.Up
SeriesBox.Text = String.Empty
SeriesBox.SelectedIndex = CurIndex - 1
End Select
End Sub
The arrow keys don't actually enter this sub, so I tried adding:
Protected Overrides Function ProcessCmdKey(ByRef msg As Message, ByVal keydata As Keys) As Boolean
If keydata = Keys.Right Or keydata = Keys.Left Or keydata = Keys.Up Or keydata = Keys.Down Then
OnKeyDown(New KeyEventArgs(keydata))
ProcessCmdKey = True
Else
ProcessCmdKey = MyBase.ProcessCmdKey(msg, keydata)
End If
End Function
But this didn't seem to make a difference. Is there something I am missing?

This may work:
First set you combobox's AutoCompleteMode and AutoCompleteSouce to None
Then paste this to your code:
Private Sub SeriesBox_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles SeriesBox.TextChanged
For Each it As String In SeriesBox.Items
If Not SeriesBox.Text = it Then
If it.Contains(SeriesBox.Text) Then
Dim length As Integer = SeriesBox.Text.Length
SeriesBox.Text = ""
SeriesBox.Text = it
SeriesBox.Select(length, SeriesBox.Text.Length - length)
SeriesBox.SelectedItem = SeriesBox.Text
End If
End If
Next
End Sub

Related

how to handle multiple KeyPress events

I need my win form - vb.net, to detect if Control + P is being pressed as well as Control + Shift + P as well as just the letter P being pressed.
i have ready how this should be done, and then wrote it into my application, however i can't get it to work so i assume im doing something fundamentally wrong.
my code
Private Sub Form1_KeyUp(sender As Object, e As KeyEventArgs) Handles DataGridView1.KeyUp, MyBase.KeyDown
If e.KeyCode = Keys.F9 Then
System.Diagnostics.Process.Start("calc.exe")
End If
If e.KeyCode = (Keys.P AndAlso Keys.ControlKey AndAlso Keys.ShiftKey) Then
If PrintBatchStickersToolStripMenuItem.Enabled = False Then Exit Sub
If DataGridView1.Rows.Count = 0 Then Exit Sub
Dim rowIndex As Integer = 0
rowIndex = DataGridView1.CurrentRow.Index
PrintAllMatchingProductCodeToolStripMenuItem_Click(sender, e)
ElseIf e.KeyCode = (Keys.P AndAlso Keys.ControlKey) Then
If PrintBatchStickersToolStripMenuItem.Enabled = False Then Exit Sub
If DataGridView1.Rows.Count = 0 Then Exit Sub
Dim rowIndex As Integer = 0
rowIndex = DataGridView1.CurrentRow.Index
PrintBatchQTYToolStripMenuItem_Click(sender, e)
ElseIf e.KeyCode = Keys.P Then
If PrintBatchStickersToolStripMenuItem.Enabled = False Then Exit Sub
If DataGridView1.Rows.Count = 0 Then Exit Sub
Dim rowIndex As Integer = 0
rowIndex = DataGridView1.CurrentRow.Index
PrintSingleStickerToolStripMenuItem_Click(sender, e)
End If
End Sub
if i remove the brackets i can get it to detect the P key being pressed, but never the Control and the Shift or a combination of them two.
i added this to the KeyUp event as from my testing if i did this on keydown, and a user held down the keys, the code would loop over and over printing multiple copies of the sticker. and i need the code to only execute once.
keypress from my understanding wont handle the control and shift keys from what i could understand.
am i going wrong with the keyup, because the keys could be getting released at separate times? and if i cant use keyup how to do i handle not printing multiple times on keydown?
You need to use KeyData rather than KeyCode and you need to combine your Keys values properly:
Select Case e.KeyData
Case Key.P
'P was pressed without modifiers.
Case Keys.Control Or Key.P
'Ctrl+P was pressed without other modifiers.
Case Keys.Control Or Keys.Shift Or Keys.P
'Ctrl+Shift+P was pressed without other modifiers.
End Select
It may seem odd to use Or rather than And but this is a bitwise operation, not a Boolean operation. If you understand how bitwise logic works, which you should, then it's obvious why Or is used.
As an alternative:
If e.KeyCode = Keys.P AndAlso Not e.Alt Then
If e.Control Then
If e.Shift Then
'Ctrl+Shift+P was pressed without other modifiers.
Else
'Ctrl+P was pressed without other modifiers.
End If
Else
'P was pressed without modifiers.
End If
End If

How to clear all contents of textbox when spacebar is pressed? VB.Net

I'm creating a simple typing test program.
I want the space bar to trigger checking if the typed word is correct, then clear the contents of the textbox.
What happens here is the first typed word will work and be counted when the space bar is pressed and the typed word will be cleared, but the space character still remains and so the next typed word will contain a space char and will be read wrong.
I tried interchanging where the txtInput.Clear() should be placed but results in the same problem.
Private Sub txtInput_TextChanged(sender As Object, e As KeyEventArgs) Handles txtInput.KeyDown
If e.KeyValue = Keys.Space Then
Space()
End If
End Sub
Public Function Space()
If txtInput.Text = txtWord.Text Then
ctr = CInt(txtWord.TextLength)
charTotal = charTotal + ctr
lblScore.Text = charTotal.ToString
End If
txtInput.Clear()
txtWord.Text = rdmWord()
End Function
In KewDown Event the value of TextBox isnot setted yet. So, use KeyUp Event as the code below shows
Private Sub txtInput_KeyUp(sender As Object, e As KeyEventArgs) Handles txtInput.KeyUp
If e.KeyValue = Keys.Space Then
Space()
End If
End Sub
You could also override ProcessCmdKey and trap the spacebar there:
Protected Overrides Function ProcessCmdKey(ByRef msg As Message, keyData As Keys) As Boolean
If keyData = Keys.Space Then
If Me.ActiveControl Is txtInput Then
Space()
Return True ' suppress space
End If
End If
Return MyBase.ProcessCmdKey(msg, keyData)
End Function
If you want to allow space or enter, then change to:
If keyData = Keys.Space Or keyData = Keys.Enter Then

Why DateTimePicker won't trigger keyDown and KeyPress events with the tab key?

Fellows, I am having this problem - the DateTimePicker won't trigger KeyDown and KeyPress events with the tab key (other keys are working fine, and the keyUp event as well, although it triggers after "arriving" at the DateTimePicker after pressing tab at the previous control focused). I'm using .net 4.6.1, Visual Basic and VS 2017.
What I'm trying to do -> Go to month and year directly on DateTimePicker in C# (Go to month and year directly on DateTimePicker)
Code I'm using:
Private Sub DateTimePicker1_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles DateTimePicker1.KeyDown
If e.KeyCode = Keys.Tab Then
e.Handled = True
MsgBox("TAB DOWN")
End If
End Sub
Private Sub DateTimePicker1_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles DateTimePicker1.KeyPress
e.Handled = True
MsgBox("tab press")
End Sub
Private Sub DateTimePicker1_KeyUp(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles DateTimePicker1.KeyUp
If e.KeyCode = Keys.Tab Then
MsgBox("TAB UP")
e.Handled = True
End If
End Sub
Any clues?
The Tab key is used for navigation. Moving the focus from one control to another. So your KeyDown event handler can never see it, the keystroke is intercepted and used before that. You could subscribe the PreviewKeyDown event and set the e.IsInputKey = true as a workaround, check the MSDN sample code in the linked article for code.
But it is the wrong event to use anyway, you'd still want this to work when the user changes focus with the mouse instead of the keyboard. So use the Enter event instead.
Do beware that both approaches have the same problem, the focus might already be on the month part from previous usage of the control so now your code will incorrectly move it to the year part. And you can't find out what part has the focus, that is up a creek without a good paddle. A very ugly workaround for that is to change the Format property, and back, that forces the control to re-create the control window and that always resets the focus. Use BeginInvoke() to run that code. Perhaps more constructively, consider to just not display the day if you are only interested in month+year, CustomFormat property.
Sample code that implements the focus hack:
Private Sub DateTimePicker1_Enter(sender As Object, e As EventArgs) Handles DateTimePicker1.Enter
Me.BeginInvoke(
New Action(Sub()
'' Hack to reset focus
DateTimePicker1.Format = DateTimePickerFormat.Long
DateTimePicker1.Format = DateTimePickerFormat.Short
DateTimePicker1.Focus()
SendKeys.Send("{Right}")
End Sub))
End Sub
It's not the right answer to this question, although it helps as well. If you want to just make the tab behave as the right key when inside a DateTimePicker, a good (sketchy) way to do is:
Private i = 2
Protected Overrides Function ProcessTabKey(ByVal forward As Boolean) As Boolean
Dim ctl As Control = Me.ActiveControl
If ctl IsNot Nothing AndAlso TypeOf ctl Is DateTimePicker And i <> 0 Then
SendKeys.Send("{Right}")
i -= 1
Return True
End If
i = 2
Return MyBase.ProcessTabKey(forward)
End Function
You need to override ProcessCmdKey function
Private isTab As Boolean = False
Private isShiftTab As Boolean = False
Protected Overrides Function ProcessCmdKey(ByRef msg As Message, ByVal keyData As Keys) As Boolean
If keyData = Keys.Tab Then
isTab = True
'Do something with it.
Else
isTab = False
End If
Return MyBase.ProcessCmdKey(msg, keyData)
End Function

Use PageUp PageDown on DataGridViewComboBoxColumn in vb.net

I have a DataGridView that has a few DataGridViewComboBoxColumns. When attempting to use the ComboBoxColumns they have a few user annoyances I want to resolve but don't know how.
1) PageUp and PageDown change DataGridView Rows, instead of values within the combobox when the selection window is up.
2) You have to double or triple click to get the dropdown to show. I would like it to be a single click.
The object is a standard DataGridView with no special overrides on these settings. Any help would be greatly appreciated. Thanks.
If you handel the keydown event for the combobox, you can change the selected index or text value of the combobox when the page up or down keys are pressed, like this:
Private Sub cbx_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles cbx.KeyDown
If e.KeyCode = Keys.PageDown Then
'change the selected index on the combobox +1
e.Handled = True
ElseIf e.KeyCode = Keys.PageUp Then
'Change the selected index -1
e.Handled = True
End If
End Sub

Using combobox from class

I have some questions on using of combobox.
1) I need to reference combobox from class like this:
If Me.ActiveControl.GetType Is GetType(ComboBox) And combodroppeddown = False) Then
something...
End If
From Here I need right from the AND to check if this combobox is dropped down but I don't know how.
2) My actual type of combobox is of "DropDownList" type.
Problem is that if I drop it down and type with up/down keys the value is changed according to selected row. If I then press ESC then last value stays as choosen what is not wanted.
Is here way to return original value from moment of dropping in case if I press ESC when list is dropped?
How to do that?
Here is closer look to my xCombo subclass to get help in second question...
Public Class xAutoCombo
Inherits ComboBox
Private entertext As String
Protected Overrides Sub OnKeyDown(ByVal e As KeyEventArgs)
If e.Control Then ' this dropped a list with keyboard
If e.KeyCode = Keys.Down Then
Me.DroppedDown = True
End If
End If
'' this should return value back if ESC was pressed
'' but don't work!
If Me.DroppedDown And e.KeyCode = Keys.Escape Then
Me.Text = entertext
End If
MyBase.OnKeyDown(e)
End Sub
Protected Overrides Sub OnDropDown(ByVal e As System.EventArgs)
entertext = Me.Text '' this remember text in moment of droping
MyBase.OnDropDown(e)
End Sub
EDIT:
Here I found one issue in functionality which I like to be solved.
When combo is dropped and I navigate through list by keyboard and then press with mouse to form (or outside of combo) it closes a list and set value which is last been selected.
Instead of that I would like that combo set his new value ONLY on click with mouse to list or with pressing Enter key with keyboard.
Examine the DroppedDown property, but it seemed like you have other things you wanted to do while dropped down.
Dim cbo As ComboBox
If Me.ActiveControl.GetType Is GetType(ComboBox) then
cbo=Ctype(Me.ActiveControl, ComboBox)
' make it easier to refernece
if cbo.DroppedDOwn then
....
End iF
End if
' Note:
Ctype(Me.ActiveControl, ComboBox).DroppedDown
' should work, but the above is easier to read and use since you apparently
' will have other things to do/override with it
Note also that I think one of the three combobox dropdown types does not use/support the DroppedDown property.
For the rest of your question, which I dont entirely follow, you could also store the last selected item and restore it in similar fashion. Overriding windows default behavior though, is rarely a good idea because you are creating something the user has never encountered before.
EDIT
To change Escape functionality from CLOSE DROPDOWN to ABORT CHOICE:
NOTE: I just used a std cbo, refs will need to be changed to MyBase, events to On...
Private selectedindex As Integer = -1
Private bEsc As Boolean = False
Private Sub cbo_Enter(....
' reset tracking vars...might not be needed
selectedindex = -1
bEsc = False
End Sub
Private Sub cbo_DropDown(...
' capture starting state
selectedindex = cbo.SelectedIndex
bEsc = False
End Sub
KeyDown:
If cbo.DroppedDown AndAlso e.KeyCode = Keys.Escape Then
bEsc = True
e.Handled = True
' this MUST be last!
cbo.DroppedDown = False
End If
Private Sub cbo_DropDownClosed(...
' rest cbo.selectedindex if escape was pressed
If bEsc Then
' note: SelectedIndexChanged event will fire and any code there will run
' may need to qualify with If Esc = False...
cbo.SelectedIndex = selectedindex
End If
End Sub