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

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

Related

Is there a way to identify which dropdown boxes aren't empty when hitting 'search' on a VBA GUI?

I'm working on an application in VBA that takes in information from an excel sheet, populates a dropdown combobox, then based on the selected information from the dropbox, retrieves the full information for matching values. There are 6 dropboxes and I'm looking for a way to find out which dropboxes have a value (not empty) without rewriting dozens of if statements with the same code but different conditions (i.e combo 1 and 3 have values, so the program will only look for the records based on those two selected fields)
I know this can be achieved with re-writing if statements, but I'm hoping there's an easier way that doesn't take hours?
Private Sub Search_Page1_Click()
Dim year As String
Dim location As String
Dim snap As String
Dim city As String
Dim group As String
Dim endyear As String
year = Multipage1.Cmb_Year.Value
location = Multipage1.Cmb_Location.Value
snap = Multipage1.Cmb_Snapshot.Value
city = Multipage1.Cmb_City.Value
group = Multipage1.Cmb_Group.Value
endyear = Multipage1.Cmb_LeaseEnd.Value
If year = Empty And location = Empty And snap = Empty And city = Empty
And group = Empty And endyear = Empty Then
MsgBox ("Please fill in at least one field")
End If
End Sub
If you can work with a Collection of ComboBox controls, then whip up a custom function like and call it like:
Dim populatedBoxes as New Collection
Set populatedBoxes = GetPopulatedThings(Multipage1, "ComboBox")
Dim cb as MSForms.ComboBox
For Each cb in populatedBoxes
MsgBox cb.Value
Next
In your code, you could replace:
If year = Empty And location = Empty And snap = Empty And city = Empty And group = Empty And endyear = Empty Then
With this:
Set populatedBoxes = GetPopulatedThings(Multipage1, "ComboBox")
If populatedBoxes.Count = 0 Then Exit Sub
Here's the function:
Private Function GetPopulatedThings(container As Object, Optional ctrlType As String = "ComboBox") As Collection
Dim c As New Collection
Dim ctrl As MSForms.Control
For Each ctrl In container.Controls
If TypeName(ctrl) = ctrlType Then
Select Case ctrlType
Case "ComboBox"
If ctrl.ListIndex > -1 Then
c.Add ctrl
End If
Case Else
' TBD
' Additional cases will require separate logic...
End Select
End If
Next
Set GetPopulatedThings = c
End Function

VB.NET How to add Event Handler to ComboBoxColumn located in programmatically created controls?

I've got part of my code that creates a tab in a tabcontrol, and then fills it with a datagridview which contains a couple columns that are DataGridViewComboBoxColumn.
It looks like this:
Private Sub NewTabPage()
Dim TabPageCount As Integer = RacerOrderTAB.TabPages.Count
RacerOrderTAB.TabPages.Add(TeamNames(TabPageCount)) 'teamnames() is an array of team names
Dim CurrentTabPage = RacerOrderTAB.TabPages(TabPageCount)
Dim GridToAdd As New DataGridView
GridToAdd.Size = CurrentTabPage.Size
GridToAdd.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill
GridToAdd.Location = New Point(CurrentTabPage.Location.X, CurrentTabPage.Location.Y)
GridToAdd.Columns.Add("ShiftCOL", "Shift Name")
GridToAdd.Name = "grid_" & CurrentTabPage.Text
For y As Integer = 1 To ShiftSetup.racerspershift 'add extra column for each racer in shift
Dim cmb As New DataGridViewComboBoxColumn
cmb.HeaderText = "Racer" & y
cmb.Name = "Racer_" & y
cmb.MaxDropDownItems = AmountOfRacers
cmb.DisplayStyle = DataGridViewComboBoxDisplayStyle.DropDownButton
GridToAdd.Columns.Add(cmb)
Next
RacerOrderTAB.TabPages(TabPageCount).Controls.Add(GridToAdd)
End Sub
But I've been having difficulty in adding an eventhandler for the comboboxes. What I want to happen is that when a combobox is clicked and opened, I populate it with the items I want.
I managed to vaguely get it working by adding:
AddHandler GridToAdd.EditingControlShowing, AddressOf <sub name>
but then have been unable to figure out which combobox was clicked, and how to populate it. It's also been requiring like four clicks before the drop list will appear. I'm only slightly very confused.
Thanks for any advice; these DataGridViewComboBoxColumns [deep breath] have been confusing me a lot!
It may be a little hacky but it should do what you are asking… hopefully. I created two List(Of String) variables. AllRacers contains all the racers… i.e. all the names we want to appear in a combo box such that there is no other combo box on that row that has an item selected. These names are what all combo boxes on all rows would initially contain in the selectable items list.
The other List(Of String) UsedRacers contains a list of all the “comboboxes” on the current row that have selected items. Each time a cell value is changed and it is one of the “combobox” column cells, then UsedRacers is cleared/updated to reflect the added/changed selected item on the current row.
When a “comboBox” cell value is changed, SetUsedRacersForRow is called…
Private Sub SetUsedRacersForRow(rowIndex As Int16)
UsedRacers.Clear()
Dim curValue = ""
For i = 1 To racersPerShift
If (Not (dgvRacers.Rows(rowIndex).Cells(i).Value Is Nothing)) Then
curValue = dgvRacers.Rows(rowIndex).Cells(i).Value.ToString()
If (Not (String.IsNullOrEmpty(curValue))) Then
UsedRacers.Add(curValue)
End If
End If
Next
End Sub
The code above loops through all the “combobox” cells in the given row and if a “combobox” cell has something selected, the selected value is added to the UsedRacers list.
Now that the selected items for all the “comboboxes” in that row are in the UsedRacers list, we can now loop through each “combobox” cell in that row and set the proper list of names. To help, a method is created that returns a DataGridViewComboBoxCell such that the names in the current UsedRacers list will NOT be in the DataGridViewComboBoxCell’s list of selectable names.
The only issue here would be with cells that currently have an item selected. Each “combobox” cell with an item selected will uniquely need to have its selected item in its list of items. To remedy this, a check is needed to see if the “combobox” cell contains a value. If the “combobox” cell DOES contain a selected value, then this value is also contained in the UsedRacers list. Since THIS cell is the cell that is in the UseRacers list… then we need to ADD this value to this cells items list. Otherwise, we would not be able to display the unique selection.
To keep the UsedRacers list consistent, we need to add this item directly to the individual “combobox” cell and not remove or alter the UsedRacers list as this will be used for the other “combobox” cells. In other words… whatever value is selected in a combo box, we need to make sure it is one of the items in the “combobox’s” list of selectable items. I hope that makes sense.
This can all be done in the DataGridViews CellChanged event.
Private Sub dgvRacers_CellValueChanged(sender As Object, e As DataGridViewCellEventArgs) Handles dgvRacers.CellValueChanged
If (e.ColumnIndex >= 1 And e.ColumnIndex <= racersPerShift) Then
SetUsedRacersForRow(e.RowIndex)
For i = 1 To racersPerShift
Dim newCell As DataGridViewComboBoxCell = GetCurrentComboBoxCell()
If (Not (dgvRacers.Rows(e.RowIndex).Cells(i).Value Is Nothing)) Then
Dim curValue = dgvRacers.Rows(e.RowIndex).Cells(i).Value.ToString()
newCell.Items.Add(curValue)
newCell.Value = curValue
End If
dgvRacers.Rows(e.RowIndex).Cells(i) = newCell
Next
End If
End Sub
In the code above, a method GetCurrentComboBoxCell (below) returns a DataGridViewComboBoxCell such that the items in the combo boxes list of items does not contain any items that are in the UsedRacers list. Because of this, a check is needed (above) to see if the cell already contains a value. NOTE: the DataGridViewComboBoxCell returned will always contain a “blank” empty item. This is necessary to allow the user to “De-Select” any currently selected value and then make the “De-Selected” item available to the other combo box cells.
Public Function GetCurrentComboBoxCell() As DataGridViewComboBoxCell
Dim newComboCell = New DataGridViewComboBoxCell()
newComboCell.DisplayStyle = DataGridViewComboBoxDisplayStyle.DropDownButton
newComboCell.FlatStyle = FlatStyle.Flat
newComboCell.Items.Add("")
For Each curRacer In AllRacers
If (Not UsedRacers.Contains(curRacer)) Then
newComboCell.Items.Add(curRacer)
End If
Next
Return newComboCell
End Function
Finally, putting all this together…
Dim racersInShift = 3
Dim AllRacers As List(Of String) = New List(Of String) From {"John", "Bobby", "Trent", "Josh", "Chapman", "Henry", "George", "Marvin"}
'Dim racersPerShift As Int16 = AllRacers.Count '<-- should be MAX value
Dim racersPerShift As Int16 = 4
Dim UsedRacers = New List(Of String)
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
BuildGrid()
End Sub
Private Sub BuildGrid()
dgvRacers.Size = New Size(800, 200)
dgvRacers.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill
'dgvRacers.Location = New Point(50, 200)
dgvRacers.Columns.Add("ShiftCOL", "Shift Name")
dgvRacers.Name = "RacersDGV"
dgvRacers.EditMode = DataGridViewEditMode.EditOnEnter
dgvRacers.AllowUserToAddRows = False
AddRacerColumns()
AddRacerRows()
End Sub
Private Sub AddRacerColumns()
Dim newColumn As DataGridViewComboBoxColumn
For i As Integer = 1 To racersPerShift
newColumn = GetNewComboBoxColumn("Racer" & i, "Racer " & i)
dgvRacers.Columns.Add(newColumn)
Next
End Sub
Private Sub AddRacerRows()
For i As Integer = 1 To racersInShift
Dim row As New DataGridViewRow
dgvRacers.Rows.Add(row)
Next
End Sub
Private Sub dgvRacers_CellValueChanged(sender As Object, e As DataGridViewCellEventArgs)
‘See code above
End Sub
Private Sub SetUsedRacersForRow(rowIndex As Int16)
‘See code above
End Sub
Public Function GetCurrentComboBoxCell() As DataGridViewComboBoxCell
‘See code above
End Function
‘Lastly a method to set a whole `DataGridviewComboBoxColumn` which is used to initialize all the combo box columns
Public Function GetNewComboBoxColumn(colName As String, colHeader As String) As DataGridViewComboBoxColumn
Dim newComboCol = New DataGridViewComboBoxColumn()
newComboCol.DisplayStyle = DataGridViewComboBoxDisplayStyle.DropDownButton
newComboCol.FlatStyle = FlatStyle.Flat
newComboCol.Items.Add("")
newComboCol.HeaderText = colHeader
newComboCol.Name = colName
For Each curRacer In AllRacers
newComboCol.Items.Add(curRacer)
Next
Return newComboCol
End Function
I hope this helps, I am guessing there is an easier way to do this.

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...

System.NullReferenceException on a ForEach of a datagrid

So all is in the question, I have a datagrid view who's parcoured by a foreach in his rows collection like so dataGridView1.Rows and I get and error of null type in the second if of the for each
Sub DataColumnFirstDouble(ByRef dGridView As DataGridView, ByVal iCol As Integer)
Dim bFirstRow As Boolean = False
Dim sTemp As String = ""
For Each RW As DataGridViewRow In dGridView.Rows
If (bFirstRow) Then
If (RW.Cells(iCol).Value.ToString() = sTemp) Then
RW.Cells(iCol).Selected = True
dGridView.CurrentCell.Style.BackColor = Color.LightGreen
dGridView.CurrentCell.Style.ForeColor = Color.White
End If
End If
sTemp = RW.Cells(iCol).Value.ToString()
bFirstRow = True
Next
End Sub
By the way the Datagrid is populated with 1 entry going
LongString, Number, Number
Hello , 8 , 8
The bug occur when I click on a new row also the function is called on the event of row leave
Need some help
By the way what I try to do is to check when the user enter the name in the longstring space who's a primary unique key in a database but It seems I can't find anythings to handle it by vb so I try to parse it every times he leave the rows to check if there's any double
It isn't clear where the error is, you should debug to figure out which variable exactly is null. So I'll assume it's RW.Cells(iCol).Value.
If there's no value in the cell, it might be null. This mean ToString won't work.
If (bFirstRow) Then
If RW.Cells(iCol).Value IsNot Nothing AndAlso RW.Cells(iCol).Value.ToString() = sTemp Then
RW.Cells(iCol).Selected = True
dGridView.CurrentCell.Style.BackColor = Color.LightGreen
dGridView.CurrentCell.Style.ForeColor = Color.White
End If
End If
You could even check if RW.Cells(iCol) exists, maybe it's trying to fetch the data in a cell that doesn't exists in the row.

How to Set DataGridView Row Tag

I am using a double click event on a listview that will add three columns to a datagridview. I'm not sure how to set the "Tag" property on the "selectedText" variable.
Private Sub lwArticles_DoubleClick(sender As Object, e As System.EventArgs) Handles lwArticles.DoubleClick
Dim selectedText = lwArticles.SelectedItems(0).SubItems.Item(0).Text 'Article No
Dim selectedDesc = lwArticles.SelectedItems(0).SubItems.Item(1).Text 'Description
Dim currRowNo As String = ""
Dim alreadyExists = False
For i As Integer = 0 To dgvDetail.Rows.Count - 1
currRowNo = dgvDetail.Rows(i).Cells(0).Value
If currRowNo = selectedText Then
alreadyExists = True
dgvDetail.Rows(i).Cells(2).Value += 1
Exit For
End If
Next
'If the entry doesn't exist, add it
If Not alreadyExists Then
dgvDetail.Rows.Add(New String() {selectedText, selectedDesc, 1})
End If
End Sub
After this I loop through the row's tags to see the article numbers. It will be near my dgvDetail.Rows.Add() that I should be setting the Tag property to equal the selectedText ... Any one know how to do this?
Edit:
The datagridview columns being populated are: "Article Number", "Description" and "Quantity". The quantity is set in the loop, basically if I've double clicked on the same thing twice, it will increment the third column (Cell(2)) by one.
The Add "function" for the DataGridView control returns the index of the row in the grid, so you can try using that to reference the row:
Dim rowIndex As Integer
rowIndex = dgvDetail.Rows.Add(New String() {selectedText, selectedDesc, 1})
dgvDetails.Rows(rowIndex).Tag = selectedText