Listbox Multiple KeyPress - vb.net

How can I achieve the search functionality that works with multiple keys in CheckedListBox and ListBox?
Example: I have the following items in the list:
1000
1500
1520
2010
5001
5102
When I press the key 1, instantly search the first hit that match with the first char that starts with '1'.
But, If I want locate the item "5102", the list only will can search the 5, and then, I need go manually to identify the wanted item.

Answering to my own question. This it's a clean solution that doesn't need too much work (All the code can handle in the KeyDown event):
Sub DropDownListBox_KeyDown(ByVal sender As Object, ByVal e As KeyEventArgs)
If Char.IsLetterOrDigit(Chr(e.KeyValue)) Then
e.SuppressKeyPress = True
If TryCast(sender.tag, Timer) Is Nothing Then
Dim vTimer As New Timer
vTimer.Interval = 1000
vTimer.Tag = ""
sender.Tag = vTimer
AddHandler vTimer.Tick,
Sub(Timer As Object, eventsArgs As System.EventArgs)
Timer.Tag = ""
If Not TryCast(sender, CheckedListBox).Visible Then
Timer.dispose() : Timer = Nothing
End If
End Sub
Else
sender.Tag.Stop() : sender.Tag.Start()
sender.Tag.Tag &= Chr(e.KeyValue)
Dim vIndex As Integer = TryCast(sender, CheckedListBox).FindString(sender.Tag.Tag)
If vIndex <> -1 Then TryCast(sender, CheckedListBox).SelectedItem = TryCast(sender, CheckedListBox).Items(vIndex)
End If
End If
End Sub
Basically I use the TAG object to keep a Timer running every 1 sec; then, if the user typing several chars, the process will find exactly the wanted text.
Any comment or feedback will be welcome.

Public Class Form1
Dim Type As String
Private Sub ListBox1_KeyPress(sender As Object, e As KeyPressEventArgs) Handles ListBox1.KeyPress
If Asc(e.KeyChar) <> 8 Then
If Asc(e.KeyChar) < 65 Or Asc(e.KeyChar) > 122 Then
e.Handled = True
' Clear String at Escape key press & Reset Listbox location
If Asc(e.KeyChar) = 27 Then
Type = ""
ListBox1.SelectedIndex = -1
ListBox1.SelectedItem = ListBox1.SelectedIndex
End If
End If
If Asc(e.KeyChar) = 27 Then
' Do not add escape key char to string at key press
Else
' add char one by one after key press
Type &= e.KeyChar
Dim TL As Integer = Type.Length
Dim i As Integer = 0
For i = 0 To ListBox1.Items.Count - 1
' match key press in total items in listbox
'MsgBox(Format$(Mid$(ListBox1.Items(i), 1, TL)))
If Format$(Mid$(ListBox1.Items(i), 1, TL)) = Type Then
ListBox1.SelectedIndex = i
End If
Next
End If
End If
End Sub
End Class

Related

Changing typing behavior of ListBox

When typing into a listbox the listbox scrolls to the next item with first letter matching the input character. I want to disable/change this behavior.
I implemented a handler for the keypress event and implemented my new behavior, but I don't see any way to remove the old behavior.
How can I disable the default behavior?
Here is the event handler for the keypress event:
Private Sub FooListBox_KeyPress(sender As Object, e As KeyPressEventArgs) Handles FooListBox.KeyPress
If SearchResetTimer.Enabled Then
SearchResetTimer.Stop()
SearchTimer.Stop()
Else
BeginUpdate()
SearchedString = ""
End If
SearchedString = SearchedString & e.KeyChar
SearchResetTimer.Start()
SearchTimer.Start()
End Sub
Private Function SearchFor(listbox As ListBox, target As String) As Integer
For i As Integer = listbox.SelectedIndex To listbox.Items.Count - 1
If listbox.Items(i).ToString().ToLower().StartsWith(target) Then
Return i
End If
Next
For i As Integer = 0 To listbox.SelectedIndex - 1
If listbox.Items(i).ToString().ToLower().StartsWith(target) Then
Return i
End If
Next
Return -1
End Function
Private Sub SearchTimer_Tick(sender As Object, e As EventArgs) Handles SearchTimer.Tick
SearchTimer.Stop()
Dim Found As Integer = SearchFor(FooListBox, SearchedString)
If Found <> -1 Then
FooListBox.SelectedIndex = Found
End If
EndUpdate()
End Sub
Private Sub SearchResetTimer_Tick(sender As Object, e As EventArgs) Handles SearchResetTimer.Tick
SearchResetTimer.Stop()
End Sub
Quick overview: there are two timers, searchTimer that when ticked searches for the string and updates the control, searchResetTimer which resets the searched string and marks the beginning of a new user input.
Note that I am not releasing this code under CC, it is for illustration purposes only

Visual Basic- Loop to make listbox update as checkbox is checked

I'm having trouble having the listbox update as the checkbox is checked. I have a total of 8 "test_location" check boxes and I want the listbox to add items to "Steps_Queue_List" and store "1" in the "Test_Locations" array when the location is checked. Also want to clear the list when the checkbox is unchecked. This works so far but I would much prefer to learn how to make a loop for this:
Private Sub Location_CheckBox_1_CheckedChanged(sender As Object, e As EventArgs) Handles Location_CheckBox_1.CheckedChanged
If Location_CheckBox_1.Checked Then
Test_Locations(0) = 1
Steps_Queue_List.Items.Add("test for location" & 1, 1)
ElseIf Location_CheckBox_1.Checked = False Then
Test_Locations(0) = 0
Steps_Queue_List.Items.RemoveAt(0)
End If
End Sub
Private Sub Location_CheckBox_2_CheckedChanged(sender As Object, e As EventArgs) Handles Location_CheckBox_2.CheckedChanged
If Location_CheckBox_2.Checked Then
Test_Locations(1) = 1
Steps_Queue_List.Items.Add("test for location" & 2, 2)
ElseIf Location_CheckBox_2.Checked = False Then
Test_Locations(1) = 0
Steps_Queue_List.Items.RemoveAt(0)
End If
End Sub
Private Sub Location_CheckBox_3_CheckedChanged(sender As Object, e As EventArgs) Handles Location_CheckBox_3.CheckedChanged
If Location_CheckBox_3.Checked Then
Test_Locations(2) = 1
Steps_Queue_List.Items.Add("test for location" & 3, 3)
ElseIf Location_CheckBox_3.Checked = False Then
Test_Locations(2) = 0
Steps_Queue_List.Items.RemoveAt(0)
End If
End Sub
Thanks in advance.
You don't need a loop but you can just handle everything in a single method.
Set the property Tag of your Checkboxes to a progressive value starting from 1 to 8 matching the text value you want to be displayed in the listboxes.
Then setup an event handler that manages all the CheckBoxChanged events for all the CheckBox.
In this event handler retrieve the tag and use it to address the array index and the listbox to update
' Handle all Checkbox changed with the same handler
Private Sub OnCheckBoxChanged(sender As Object, e As EventArgs)
Handles Location_CheckBox_1.CheckedChanged,Location_CheckBox_2.CheckedChanged,
Location_CheckBox_3.CheckedChanged,Location_CheckBox_4.CheckedChanged,
Location_CheckBox_5.CheckedChanged,Location_CheckBox_6.CheckedChanged,
Location_CheckBox_7.CheckedChanged,Location_CheckBox_8.CheckedChanged
' Discover which checkbox has been clicked
Dim chk = DirectCast(sender, CheckBox)
' Now read the value of the Tag property of that checkbox
Dim idx = Convert.ToInt32(chk.Tag)
If chk.Checked Then
Test_Locations(idx - 1) = 1
Steps_Queue_List.Items.Add("test for location" & idx, idx)
Else
Test_Locations(idx - 1) = 0
Steps_Queue_List.Items.RemoveAt(0)
End If
End Sub

How To Clear CheckedListBox From Previous Selection - VB.NET

Okay so I have a checkedlistbox that when a user selects a item it will print out that item into word. That works perfect. However, I want to give the user the option to not select anything at all, but when the user does not select an item in the checkboxlist, it still prints out the previous selected item into MS word.
Below is my code:
Private Sub ExportContactOkButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ExportContactOkButton.Click
Dim i As Integer
Dim array_Counter_Contacts As Integer
Dim array_size_Contacts As Integer
array_Counter_Contacts = 0
For i = 0 To ExportContactCheckedListBox.Items.Count() - 1
If ExportContactCheckedListBox.GetItemCheckState(i) = CheckState.Checked Then
array_size_Contacts = UBound(SelectedContacts)
ReDim Preserve SelectedContacts(array_size_Contacts + 1)
SelectedContacts(array_Counter_Contacts) = ExportContactCheckedListBox.Items(i)
If Search.debugging = True Then
MsgBox(ExportContactCheckedListBox.Items(i))
End If
array_Counter_Contacts += 1
ExportContactCheckedListBox.Items(i) = ExportContactCheckedListBox.Items(i).ToString.Replace("'", "''")
If array_Counter_Contacts = 1 Then
ContactNames = "" & ExportContactCheckedListBox.Items(i) & ""
Else
ContactNames = String.Concat(ContactNames & "', '" & ExportContactCheckedListBox.Items(i) & "")
End If
End If
Next
If Search.debugging = True Then
MsgBox(ContactNames)
End If
sConnection.Close()
Dispose()
Me.Close()
End Sub
I have tried remove, clear, and I even tried this
Dim i As Integer
For i = 0 To ExportContactCheckedListBox.CheckedIndices.Count - 1
ExportContactCheckedListBox.SetItemChecked(ExportContactCheckedListBox.CheckedIndices(0), False)
Next i
But nothing is working. Can anyone help me? All I want is to be able to have the checkedlistbox forget or clear the checked item after the "OK" button is pressed and the text has already been printed into word.
Use a List(Of String) to store the selection and, of course remember, to reinitialize the list when you hit the ExportContactOkButton
' Declared at the form level....
Dim SelectedContacts as List(Of String)
.....
Private Sub ExportContactOkButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ExportContactOkButton.Click
Dim i As Integer
SelectedContacts = new List(Of String)()
For i = 0 To ExportContactCheckedListBox.Items.Count() - 1
If ExportContactCheckedListBox.GetItemCheckState(i) = CheckState.Checked Then
SelectedContacts.Add(ExportContactCheckedListBox.Items(i))
.....
End If
Next
End Sub
In this way, every time you hit the ExportContactOKButton you reinitialize your list of contacts, loop through the checked items, add the checked one to your list.
A List(Of String) is better because you don't need to know in advance how many items your user selects in the CheckedListBox and continuosly resize the array. You simply add new items to it. And you could always use it like an array
Dim Dim array_Counter_Contacts = SelectedContacts.Count
For i = 0 to array_Counter
Console.WriteLine(SelectedContacts(i))
Next

Moving through datagridview rows on keypress

I'm trying to go through datagridview rows where the cell value starts with the same keychar the user pressed. Code bellow works, but It wont move selection to next row starting with same letter when I press same letter second, third time...
Private Sub dataGridView1_KeyPress(sender As Object, e As KeyPressEventArgs) Handles dgw.KeyPress
If [Char].IsLetter(e.KeyChar) Then
For i As Integer = 0 To (dgw.Rows.Count) - 1
If dgw.Rows(i).Cells(1).Value.ToString().StartsWith(e.KeyChar.ToString(), True, CultureInfo.InvariantCulture) Then
If lastKey = e.KeyChar And lastIndex < i Then
Continue For
End If
lastKey = e.KeyChar
lastIndex = i
dgw.Rows(i).Cells(1).Selected = True
Return
End If
Next
End If
End Sub
Seems like a flaw in the logic. You press key, save index and break. Then you press the same key. And if lastIndex is lesser than i you continue. Which means it will only select the first row it finds with a lesser value than the last one. Change to lastindex > i and you should be fine.
You can with the code you have written never get anything else than the first line matching the key. After that it doesn't matter how many times you press.
I know that is too old this post... anyway I've found a workaround for this and maybe it will be useful for someone.
public lastkey as string
Private Sub dataGridView1_KeyPress(sender As Object, e As KeyPressEventArgs) Handles dgw.KeyPress
Dim input = StrConv(e.keychar.toString()
lastkey += input
Dim found as Boolean
if StrConv(dgw.currentCell.Value.toString.Substring(0,1), VbStrConv.UpperCase) = input then
dim curIndex = dgw.currentRow.Index
if curIndex < dgw.rows.count - 1 then
dgw.ClearSelection()
curIndex += 1
dgw.currentCell = dgw.rows(curIndex).Cells(0)
dgw.rows(curIndex).selected = true
end if
else
dgv_jumpRecord(lastkey,found)
if not found then
lastkey = input
dgv_jumpRecord(lastkey,found)
end if
End if
End Sub
Public Sub dgv_jumpRecord(byVal lastkey as String, ByRef found as boolean)
For i As Integer = 0 To (dgw.Rows.Count) - 1
dim rowText = dgw.Rows(i).Cells(1).Value.ToString
If StrConv(rowText.ToString(),VbStrConv.UpperCase).StartsWith(lastkey) Then
dgw.ClearSelection()
dgw.CurrentCell = dgw.rows(i).Cells(0)
dgw.rows(i).selected = true
found = true
Exit Sub
End If
Next
found = false
End Sub

limit the range of characters the user can put into a textbox vb.net

I have a textbox in a vb form and I want to limit the range of characters that the user can put into the textbox to:" abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890^-*().". The textbox is to insert SI Units into a database so i need consistent syntax. If the user types an invalid character into the textbox I would like the textbox to refuse to insert it, or remove it straight away, leaving the cursor in the same position within the textbox. I would also like the textbox to replace "/" with "^(-" and place the cursor before this.
I have found some code elsewhere which I have edited to do this but the code is bad, it activates on text changed within the textbox. This causes the code to fail, when the user inputs a disallowed value the code it activates itself when it tries to changes the text within the textbox.
Here is my code, the textbox starts with the contents "enter SI Units" from the form designer.
Private Sub TxtQuantityTextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles txtSIUnit.TextChanged
If txtSIUnit.Text = "Enter SI Units" Then
Exit Sub
End If
Dim charactersAllowed As String = " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890^-*()."
Dim Text As String = txtSIUnit.Text
Dim Letter As String
Dim SelectionIndex As Integer = txtSIUnit.SelectionStart
Dim Change As Integer
Letter = txtSIUnit.Text.Substring(SelectionIndex - 1, 1)
If Letter = "/" Then
Text = Text.Replace(Letter, "^(-")
SelectionIndex = SelectionIndex - 1
End If
Letter = txtSIUnit.Text.Substring(SelectionIndex - 1, 1)
If charactersAllowed.Contains(Letter) = False Then
Text = Text.Replace(Letter, String.Empty)
Change = 1
End If
txtSIUnit.Text = Text
txtSIUnit.Select(SelectionIndex - Change, 0)
If txtQuantity.Text <> "Enter Quantity" Then
If cmbStateRateSumRatio.SelectedIndex <> -1 Then
bttAddQUAtoDatabase.Enabled = True
End If
End If
End Sub`
Thanks for you help.
Use the KeyPress event. Set e.Handled to true if you don't like the character. It's a one-liner:
Private Const AllowedChars = " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890^-*()."
Private Sub TextBox1_KeyPress(ByVal sender As Object, ByVal e As PressEventArgs) Handles TextBox1.KeyPress
If e.KeyChar >= " "c AndAlso Not AllowedChars.Contains(e.KeyChar) Then e.Handled = True
End Sub
In the textbox's KeyDown event, check e.KeyCode. This lets you prevent certain characters from being handled. There's an example on the KeyDown documentation.