How to filter my combobox - vb.net

I have managed to filter my combobox so it filters and displays the correct records ie when A is typed all A records show, B is typed all B records show and so on. However it would it be possible to have a message box to display when no records is found in the combobox?
The coding i have so far is :-
Private Sub cmblogged_KeyPress(sender As Object, e As KeyPressEventArgs) Handles cmblogged.KeyPress
If Char.IsControl(e.KeyChar) Then Return
With Me.cmblogged
Dim ToFind As String = .Text.Substring(0, .SelectionStart) & e.KeyChar
Dim Index As Integer = .FindStringExact(ToFind)
If Index = -1 Then Index = .FindString(ToFind)
If Index = -1 Then Return
.SelectedIndex = Index
.SelectionStart = ToFind.Length
.SelectionLength = .Text.Length - .SelectionStart
e.Handled = True
End With
End Sub

Achieving what you want with your code is straightforward, just convert If Index = -1 Then Return into:
If Index = -1 Then
MessageBox.Show("Not Found.")
Return
End If
In any case, note that there is an in-built functionality in ComboBox performing the same action which your code does right now: AutoCompleteMode different than None and AutoCompleteSource set to ListItems. Logically, you can evolve your code to perform much more complex actions (what I guess that is the case), but I preferred to highlight this issue just in case.

Related

How to find a toolstripitem based on its name being a variable and then change the checked value of it

I have a ContextMenuStrip called: DGVContextStrip its displayed when the user right clicks on my datagridview.
That MenuStrip contains an item called AddUpgradeTagToolStripMenuItem
which contains sub items(dropdownitems), these sub items are all named with a number in their name.
eg: Add1ToolStripMenuItem, Add2ToolStripMenuItem, Add3ToolStripMenuItem.... and so on until Add25ToolStripMenuItem.
When a user right clicks, on the Datagridview, I want to check if a cell contains the number "1" then if it does make Add1ToolStripItem.checked = true
I figured I would loop through the numbers 1 to 25, and in each loop check if the cell contains 1 and if true, change the checked value of the menu item. something like...
For i = 1 to 25
If DataGridView1.SelectedRows(0).Cells("Text_Field").Value.ToString.Contains(i) then
CType("Add" & i & "ToolStripMenuItem", ToolStripMenuItem).Checked = True
Next
but this doesn't work, iv seen examples online that use the control.find method but i couldn't get that to work for my use.
for example
Dim ControlName As String = "Add" & i & "ToolStripMenuItem"
CType(Me.Controls.Find(ControlName, True), ToolStripMenuItem).Checked = True
any ideas how I get this to work? I realise I could have used 25 if then else statements but I kind of wanted to keep the code far neater.
The ToolStripItem is not a control to search for one in a Control.ControlCollection. You need to search a ToolStripItemCollection where it belongs.
Just like the Control.ControlCollection.Find method, the ToolStripItemCollection.Find method can perform a deep search for an item.
Examples for your case:
Dim itemName As String = $"Add{i}ToolStripMenuItem"
Dim tsmi = yourContextMenuStrip.Items.
Find(itemName, True).
OfType(Of ToolStripMenuItem).
FirstOrDefault()
If tsmi IsNot Nothing Then
tsmi.Checked = True
End If
Alternatively, if you already know that the target item is one of the AddUpgradeTagToolStripMenuItem drop down items, then you can do:
Dim itemName As String = $"Add{i}ToolStripMenuItem"
Dim tsmi = DirectCast(AddUpgradeTagToolStripMenuItem, ToolStripMenuItem).
DropDownItems.OfType(Of ToolStripMenuItem).
FirstOrDefault(Function(x) x.Name.Equals(itemName, StringComparison.OrdinalIgnoreCase))
If tsmi IsNot Nothing Then
tsmi.Checked = True
End If
In case you need to check only one item from the collection:
Dim itemName As String = $"Add{i}ToolStripMenuItem"
For Each tsmi In DirectCast(AddUpgradeTagToolStripMenuItem, ToolStripMenuItem).
DropDownItems.OfType(Of ToolStripMenuItem)
If tsmi.Name.Equals(itemName, StringComparison.OrdinalIgnoreCase) Then
tsmi.Checked = True
Else
tsmi.Checked = False
End If
Next

DataGridView live search data

I am trying to add a search function to a DataGridView in vb.net using this code
For i As Integer = 0 To ContactsList.RowCount - 1
For j As Integer = 0 To ContactsList.ColumnCount - 1
If ContactsList.Rows(i).Cells(j).Value.ToString.ToLower.Trim = ContactsListSearch.Text.ToLower.Trim Then
MsgBox("Item found " + i.ToString)
ContactsList.Rows(i).Visible = True
Else
ContactsList.Rows(i).Visible = False
End If
Next
Next
I'm seeing the MsgBox show when the value matches, but the rows are not showing, it just hides all rows
Another possible option is to load data into a DataTable, create a BindingSource, set the BindingSource DataSource property to the DataTable. Set the DataGridView DataSource property to the BindingSource.
The following example works against a column in the DataTable. If the user clears the TextBox the filter is removed while if there is text filter with trim.
Private Sub SearchButton_Click(sender As Object, e As EventArgs) _
Handles SearchButton.Click
If String.IsNullOrWhiteSpace(SearchTextBox.Text) Then
bindingSource.Filter = ""
Else
Dim currentRowCount = bindingSource.Count
bindingSource.Filter = $"TRIM(LastName) = '{SearchTextBox.Text}'"
MessageBox.Show($"Before: {currentRowCount} Now: {bindingSource.Count}")
End If
End Sub
Edit If the column name might be variable consider loading a ComboBox with column names then adjust code as follows.
bindingSource.Filter = $"TRIM({FilterComboBox.Text}) = '{SearchTextBox.Text}'"
In most cases working against a data source is better than working against cells values as per the above recommendation.
I added 2 Exits in the IF statement when the value matches as it's searching each column as well, so it was causing them to be hidden as it loops columns too
For i As Integer = 0 To ContactsList.RowCount - 1
For j As Integer = 0 To ContactsList.ColumnCount - 1
If ContactsList.Rows(i).Cells(j).Value.ToString.ToLower.Trim = ContactsListSearch.Text.ToLower.Trim Then
MsgBox("Item found " + i.ToString)
ContactsList.Rows(i).Visible = True
Else
ContactsList.Rows(i).Visible = False
End If
Next
Next

Sorting datagridview items 9,000 to 10,000

I'm trying to sort a datagridview but from 9,000 to 10,000, something doesn't work. The 10,000 is placed before the 9,000. Here's my code and a screenshot of my program
DataGridView1.Sort(DataGridView1.Columns(0), System.ComponentModel.ListSortDirection.Ascending)
Try using Linq's OrderBy clause. It allows you to split the string and sort by the numbers.
Dim dList As List(Of Datagridviewrow) = datagridview1.Rows.Cast(of DataGridViewRow).ToList()
dList = dList.OrderBy(Function(q) Integer.Parse(q.Cells(0).Value.ToString().Split("-").Last)).ToList()
DataGridView1.DataSource = dList.Select(function(x) x.DataBoundItem).ToList()
There are few ways for custom sorting in the DataGridView Control
Usually the easiest and most general is to handle the DataGridView.SortCompare event:
Private Sub DataGridView1_SortCompare(sender As Object, e As DataGridViewSortCompareEventArgs) Handles DataGridView1.SortCompare
If e.Column.Index <> 0 Then Return ' custom sort only for the first column
e.SortResult = Len(e.CellValue1).CompareTo(Len(e.CellValue2)) ' compare by string length
e.Handled = e.SortResult <> 0 ' to use the default comparison if same length
End Sub
Another option is to pass IComparer to the DataGridView.Sort method (.Create needs .NET 4.5):
DataGridView1.Sort(Comparer(Of DataGridViewRow).Create(
Function(r1, r2)
Dim o1 = r1.Cells(0).Value, o2 = r2.Cells(0).Value
Dim i = Len(o1).CompareTo(Len(o2))
If i = 0 Then i = o1.ToString.CompareTo(o2)
Return i
End Function))

Search listview for multiple results

I have accomplished to search my list view item, but unfortunately it shows the first result only and nothing beyond that
This is my code
Private Sub ULButton1_Click(sender As Object, e As EventArgs) Handles ULButton1.Click
If ComboBox2.Text = "" Then
MessageBox.Show("Please select an office")
Else
Dim itm As ListViewItem
itm = Me.ListView2.FindItemWithText(TextBox1.Text)
If Not itm Is Nothing Then
ListView2.SelectedItems.Clear()
ListView3.Clear()
ListView3.View = View.Details
ListView3.FullRowSelect = True
ListView3.GridLines = True
ListView3.Sorting = SortOrder.Ascending
ListView3.Columns.Add("Username", CInt(ListView1.Width / 2))
ListView3.Columns.Add("Name", CInt(ListView1.Width / 2))
Me.ListView2.Items.Item(itm.Index).Selected = True
For Each itm2 As ListViewItem In Me.ListView2.SelectedItems
Me.ListView3.Items.Add(ListView2.Items(itm2.Index).Clone())
Next
Else
MessageBox.Show("Not Found", "")
End If
itm = Nothing
End If
End Sub
When I enter a string in the textbox, this code will show results of listview item in another listview, is there a way I can modify this to show multiple related items to the string I enter in the textbox?
Thank you
FindItemWithText finds only the first matching item.
You would need to use another form or that function that takes the starting index and keep finding next item in a loop.
Also, this fragment looks strange:
Me.ListView2.Items.Item(itm.Index).Selected = True
For Each itm2 As ListViewItem In Me.ListView2.SelectedItems
Me.ListView3.Items.Add(ListView2.Items(itm2.Index).Clone())
Next
You iterate over selected items, but you just selected one! An you already know it's index...

Building a collection of buttons and sorting by text

I have a collection of buttons on a panel, I want to be able to build a collection of those buttons and then sort the buttons by the text on the button. However, I am stuck. This is what I have so far, but I can't figure out how to sort.
Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
Dim btn1 As Control
Dim btnArray(0 To 3) As Button
btnArray(0) = btnAll
btnArray(1) = btnWine
btnArray(2) = btnBeer
btnArray(3) = btnNonAlcoholic
For Each btn1 In btnArray
Next
End Sub
You can use a simple manual bubble sort:
Dim Changed as Boolean = False
Do
Changed = False
For i = 0 to btnArray.Count - 2
If btnArray(i).Text > btnArray(i+1).Text Then '< > work for strings as well and they check 'position' in the alphabet. So "A" < "B" and so on
'If order is wrong, switch the two buttons
Dim temp as Button = btnArray(i+1)
btnArray(i + 1) = btnArray(i)
btnArray(i) = temp
Changed = True
End If
Next
'Do this until no more switches are necessary
Loop Until Changed = False
This will order your buttons and is reasonably fast for low numbers of buttons. You could use a list and a custom IComparer object as well and simply call List.Sort with the custom comparer.
See here for example implementations of this approach for a similar problem: http://msdn.microsoft.com/en-us/library/cfttsh47%28v=vs.110%29.aspx
Using LINQ:
btnArray = btnArray.OrderBy(Function(btn) btn.Text).ToArray