ContextMenuStrip selected item lost in UserControl - vb.net

I have a VB.NET User Control which is embedded into another User Control and that into a form. The inner User Control has a contextmenustrip triggered by a DataGridView row click. This successfully activates the event handler (I see the "OK" message), but the sender does not send the selected item (I don't see the other MsgBox messages). Here is the code:
Public CMSV As ContextMenuStrip
Private grdSourceViewerCurrentRow As Long
Public Sub grdSourceViewer_RowHeaderMouseClick(sender As Object, e As DataGridViewCellMouseEventArgs) Handles grdSourceViewer.RowHeaderMouseClick
'code to review/edit source details
Select Case e.Button
Case Windows.Forms.MouseButtons.Right
grdSourceViewerCurrentRow = e.RowIndex 'retain for downstream code
CMSV = New ContextMenuStrip
AddHandler CMSV.MouseClick, AddressOf SourceViewDocumentationEdit
CMSV.Items.Add("Edit")
CMSV.Items.Add("Transfer to Evidence")
Dim Pt As Point = New Point()
Pt.X = grdSourceViewer.PointToClient(Cursor.Position).X
Pt.Y = grdSourceViewer.PointToClient(Cursor.Position).Y + 20
CMSV.Show(sender, Pt)
Case Windows.Forms.MouseButtons.Left
Exit Sub
Case Else
Exit Sub
End Select
End Sub
Public Sub SourceViewDocumentationEdit()
MsgBox("OK") 'I can see it reaches here
Dim cc As ToolStripItemCollection = CMSV.Items
Dim SelectedItem As Integer = -1
Dim SelectedValue As String = ""
For i As Integer = 0 To cc.Count - 1
If cc.Item(i).Selected Then
SelectedItem = i
SelectedValue = cc.Item(SelectedItem).Text
Exit For
End If
Next
Select Case SelectedValue
Case "Edit"
MsgBox("Edit code here")
Case "Transfer to Evidence"
MsgBox("Transfer code here")
End Select
End Sub
What is wrong here? Why am I losing the info about the item that was clicked?

Why are you recreating the menu each time?
At any rate, store the ToolStripMenuItem returned by CMSV.Items.Add() and wire that up instead.
Simplified example:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
CMSV = New ContextMenuStrip
Dim TSMI As ToolStripMenuItem
TSMI = CMSV.Items.Add("Edit")
AddHandler TSMI.Click, AddressOf TSMI_Click
TSMI = CMSV.Items.Add("Transfer to Evidence")
AddHandler TSMI.Click, AddressOf TSMI_Click
' ...
End Sub
Private Sub TSMI_Click(sender As Object, e As EventArgs)
Dim TSMI As ToolStripMenuItem = DirectCast(sender, toolstripmenuitem)
Select Case TSMI.Text
Case "Edit"
Debug.Print("...Edit Code...")
' use "grdSourceViewerCurrentRow " in here?
Case "Transfer to Evidence"
Debug.Print("...Transfer to Evidence Code...")
' use "grdSourceViewerCurrentRow " in here?
End Select
End Sub

You need to use a ToolStripMenuItem and not just a string. Then you can add the handler for it's click event.
Dim tsmi As New ToolStripMenuItem
tsmi.Text = "Edit"
AddHandler tsmi.Click, AddressOf ItemClicked
CMSV.Items.Add(tsmi)
Then the event sub:
Private Sub ItemClicked(sender As Object, e As EventArgs)
'item clicked
'sender object would be the ToolStripMenuItem
End Sub

Related

Make checkbox.Checked = True whose corresponding PictureBox is clicked

I have 28 CheckBoxes in a windows form. Each box has PictureBox above it. When the user clicks on a PictureBox, I want to change the BackColor of the PictureBox to green, and make its corresponding CheckBox.Checked = True
The code I am using:
Private Sub PictureBox1_Click
PictureBox1.BackColor = Color. Green
CheckBox1.Checked = true
For 28 it will be a lengthy process. Is there any easy solution?
Programmatically add MouseClick even handlers to all your PictureBoxes in Form_Load. The event handler will parse the sender (PictureBox) and find the CheckBox based on the fact that the corresponding controls' names end in the same index. Remove the handlers when the form closes.
Private pictureBoxPrefix As String = "PictureBox"
Private checkBoxPrefix As String = "CheckBox"
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For Each pb In Me.Controls.OfType(Of PictureBox).Where(Function(p) p.Name.Contains(pictureBoxPrefix))
AddHandler pb.MouseClick, AddressOf PictureBox_MouseClick
Next
End Sub
Private Sub PictureBox_MouseClick(sender As Object, e As MouseEventArgs)
Dim index = Integer.Parse(pb.Name.Replace(pictureBoxPrefix, ""))
Dim pb = CType(sender, PictureBox)
Dim cb = CType(Me.Controls.Find($"{checkBoxPrefix}{index}", True).First(), CheckBox)
pb.BackColor = Color.Green
cb.Checked = True
End Sub
Private Sub Form1_Closed(sender As Object, e As EventArgs) Handles Me.Closed
For Each pb In Me.Controls.OfType(Of PictureBox).Where(Function(p) p.Name.Contains(pictureBoxPrefix))
RemoveHandler pb.MouseClick, AddressOf PictureBox_MouseClick
Next
End Sub
In the Load() event of your form, use Controls.Find() to get a reference to both the PictureBoxes and CheckBoxes. Store the CheckBox reference in the Tag() property of each PictureBox. Wire up the Click() event of you PB. In that event, change the color of the PB, then retrieve the CheckBox from the Tag() property and check the box as well:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For i As Integer = 1 To 28
Dim PB As PictureBox = Me.Controls.Find("PictureBox" & i, True).FirstOrDefault
Dim CB As CheckBox = Me.Controls.Find("CheckBox" & i, True).FirstOrDefault
If Not IsNothing(PB) AndAlso Not IsNothing(CB) Then
PB.Tag = CB
CB.Tag = PB
AddHandler PB.Click, AddressOf PB_Click
AddHandler CB.CheckedChanged, AddressOf CB_CheckedChanged
End If
Next
End Sub
Private Sub PB_Click(sender As Object, e As EventArgs)
Dim pb As PictureBox = DirectCast(sender, PictureBox)
Dim cb As CheckBox = DirectCast(pb.Tag, CheckBox)
If pb.BackColor.Equals(Color.Green) Then
pb.BackColor = Color.Empty
cb.Checked = False
Else
pb.BackColor = Color.Green
cb.Checked = True
End If
End Sub
Private Sub CB_CheckedChanged(sender As Object, e As EventArgs)
Dim cb As CheckBox = DirectCast(sender, CheckBox)
Dim pb As PictureBox = DirectCast(cb.Tag, PictureBox)
pb.BackColor = If(cb.Checked, Color.Green, Color.Empty)
End Sub

How to disable and get name for control in FlowLayoutPanel from ContextMenuStrip in VB.Net

My program contains buttons in a FlowLayoutPanel.
I want to disable any button when right click on it and click "Disable" in the ContextMenuStrip.
My code is:
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
For i As Integer = 0 To 30
Dim btn As New Button
btn.Name = i
btn.Text = i
btn.ContextMenuStrip = ContextMenuStrip1
FlowLayoutPanel1.Controls.Add(btn)
Next
End Sub
End Class
declare a public varibale for keeping a control
public ctrl as button = nothing
you can create a right click by putting this code on mouse down...
If e.Button <> Windows.Forms.MouseButtons.Right Then Return
Dim cms = New ContextMenuStrip
ctrl = sender
Dim item1 = cms.Items.Add("Disable")
item1.Tag = 1
AddHandler item1.Click, AddressOf Disable
end if
and in the diable sub you can code like this...
Private Sub Disable()
ctrl.enabled = false
End Sub

vb.net how I get a list of active and open forms in MDIparent inside MenuStrip Horizontally?

Please, How I get a similar Open And Active child forms that are located in the "Windows" ToostripMenuItem in MdiParent as the picture below. but I want them horizontally, is there anyway to that? I appreciate your help.
UPDATE: SOLUTION
I figured out a way to do what I want, and here is the solution
first this code is to add a ToolStripMenuItem to the mdiparent on form_load
Me.MdiParent = MDIParent1
mdf.BackColor = Color.Red
mdf.Text = Me.Text
AddHandler mdf.Click, AddressOf mdf1_Click
MDIParent1.MenuStrip.Items.Add(mdf)
then the ToolStripMenuItem click handler on the form
Private mdf As New ToolStripMenuItem
Private Sub mdf1_Click(ByVal sender As Object, ByVal e As EventArgs)
Me.BringToFront()
End Sub
and this code is to remove the ToolStripMenuItem when the form is closed in (Form_formclosing) event
Try
Dim ParentForm As MDIParent1 = MDIParent1
Dim OptionsMenuStrip As MenuStrip = ParentForm.Controls("MenuStrip")
Dim Items As ToolStripItemCollection = OptionsMenuStrip.Items
Dim removeThese As New List(Of ToolStripMenuItem)
For Each Item As ToolStripMenuItem In Items
If Item.Text = Me.Text Then
removeThese.Add(Item)
End If
Next
For Each item In removeThese
Items.Remove(item)
item.Dispose()
Next
Catch ex As Exception
MsgBox(ex.Message)
End Try
and to set the back color to red of the ToolStripMenuItem of the active form in MdiParent_MdiChilActivate event
Private Sub MDIParent1_MdiChildActivate(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.MdiChildActivate
Try
Dim activeChild As Form = Me.ActiveMdiChild
Dim ParentForm As MDIParent1 = Me
Dim OptionsMenuStrip As MenuStrip = ParentForm.Controls("MenuStrip")
Dim Items As ToolStripItemCollection = OptionsMenuStrip.Items
For Each Item As ToolStripMenuItem In Items
If Item.Text = activeChild.Text Then
Item.BackColor = Color.Red
Else
Item.BackColor = Color.LightGray
End If
Next
Catch
End Try
End Sub
and the result: (The active form is the red ToolStripMenuItem):

How to customize the click event of dynamically created buttons from string array?

Here is the code I have:
Public Class Form2
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
AddNewButton()
End Sub
Public Sub AddNewButton()
Dim buttonTop As Integer = 100
For Each item As String In Globals.candidates
Dim btn As New System.Windows.Forms.Button()
Dim Location As New Point(100, (buttonTop + 20))
btn.Location = Location
btn.Text = item
btn.Width = 150
AddHandler btn.Click, AddressOf Me.buttonClick
Me.Controls.Add(btn)
buttonTop += 20
Next
End Sub
Private Sub buttonClick()
Dim result As Integer = MessageBox.Show(String.Format("Did you select {0} ?", ???????????), "Confirmation", MessageBoxButtons.YesNo)
If result = DialogResult.Yes Then
MessageBox.Show("Yes pressed")
Else
MessageBox.Show("No pressed")
End If
End Sub
End Class
Globals.candidates is a global string array variable that holds a name "LastName, FirstName" and when the form is loaded I call the AddNewButton() Sub and it creates buttons for each item in the string array. No problem.
If you see in my code the "??????????" section, I don't know how to reference the dynamically created buttons's text so that I can display the proper "Did you select thisButton.text" properly.
Any help is appreciated.
Thanks!
EDIT:
Code changed as per suggestions: (Working)
Public Class Form2
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
AddNewButton()
End Sub
Public Sub AddNewButton()
Dim buttonTop As Integer = 100
For Each item As String In Globals.candidates
Dim btn As New System.Windows.Forms.Button()
Dim Location As New Point(100, (buttonTop + 20))
btn.Location = Location
btn.Text = item
btn.Width = 150
AddHandler btn.Click, AddressOf Me.buttonClick
Me.Controls.Add(btn)
buttonTop += 20
Next
End Sub
Private Sub buttonClick(sender As Object, e As EventArgs)
Dim btn As Button = DirectCast(sender, System.Windows.Forms.Button)
Dim result As Integer = MessageBox.Show(String.Format("Did you select {0} ?", btn.Text), "Confirmation", MessageBoxButtons.YesNo)
If result = DialogResult.Yes Then
MessageBox.Show("Yes pressed")
Else
MessageBox.Show("No pressed")
End If
End Sub
End Class
You need to put the proper signature on your event handler:
Private Sub buttonClick(sender As Object, e As EventArgs)
Then, you can use the sender object (which will be whichever button was clicked)
Dim button As Button = DirectCast(sender, System.Windows.Forms.Button)
Dim result As Integer = MessageBox.Show(String.Format("Did you select {0} ?", button.Text), "Confirmation", MessageBoxButtons.YesNo)
To get a reference to the button clicked you need to declare the event handler of the button click with the two parameters that are passed to it by the form engine.
Private Sub buttonClick(sender as Object, e as EventArgs)
Now, this correct event handler receives a parameter named sender that is the control reference to the button clicked. You could cast it to a button and then extract the Text property
Private Sub buttonClick(sender as Object, e as EventArgs)
Dim btn = DirectCast(sender, System.Windows.Forms.Button)
if btn IsNot Nothing then
Dim result As Integer = MessageBox.Show(String.Format("Did you select {0} ?", btn.Text), "Confirmation", MessageBoxButtons.YesNo)
If result = DialogResult.Yes Then
MessageBox.Show("Yes pressed")
Else
MessageBox.Show("No pressed")
End If
End If
End Sub
This should be enough in this simple case where you have just a string data, but, if you need to associate a more complex object (like an instance of a Person class for example) you could use the Tag property of every dynamically added button to store there a reference to the instance of the class
As a side note, your code works also without the declaration of the two parameters because you have the Option Strict configuration set to OFF. This is a bad practice because it introduces subtle errors in you parameters usage and in automatic conversions of type. If you are just starting with a new project remember to set its property Option Strict to ON

ListView right clicking VB.Net

So I have my code, and it's kind of working... It shows the contextmenu on the listview when I right click, but I don't think the select case is working, when I click on either edit or delete, nothing happens. Here's my code
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
ComboBox1.SelectedItem = "TRUE"
Dim ctx As New ContextMenu
Dim i1 As New MenuItem("&Edit")
Dim i2 As New MenuItem("&Delete")
AddHandler i1.Click, AddressOf ContextMenuHandler
AddHandler i2.Click, AddressOf ContextMenuHandler
ctx.MenuItems.Add(i1)
ctx.MenuItems.Add(i2)
Me.ListView1.ContextMenu = ctx
End Sub
Private Sub ContextMenuHandler(ByVal Sender As Object, ByVal e As EventArgs)
Dim mi As MenuItem = DirectCast(sender, MenuItem)
Select Case mi.Text.ToLower()
Case "edit"
ListViewToText()
Case "delete"
Try
If ListView1.SelectedItems.Count > 0 Then
ListView1.Items.Remove(ListView1.SelectedItems(0))
End If
Catch ex As Exception
End Try
End Select
End Sub
Thank you!
The Select Case block isn't working because the text is "&edit" and "&delete". The & will appear as part of the Text property.
Note that if you are going to customize the ContextMenuHanndler function for every item that is clicked then a better strategy is to just have a different handler for each one
AddHandler i1.Click, AddressOf EditHandler
AddHandler i2.Click, AddressOf DeleteHandler
Private Sub EditHandler(ByVal Sender As Object, ByVal e As EventArgs)
ListViewToText()
End Sub
Private Sub DeleteHandler(ByVal Sender As Object, ByVal e As EventArgs)
Try
If ListView1.SelectedItems.Count > 0 Then
ListView1.Items.Remove(ListView1.SelectedItems(0))
End If
Catch ex As Exception
End Try
End Sub
Dim i1 As New MenuItem("&Edit")
Dim i2 As New MenuItem("&Delete")
Private Sub ContextMenuHandler(ByVal Sender As Object, ByVal e As EventArgs)
Dim mi As MenuItem = DirectCast(sender, MenuItem)
Select Case mi.Text.ToLower()
Case "edit"
ListViewToText()
Case "delete"
Try
If ListView1.SelectedItems.Count > 0 Then
ListView1.Items.Remove(ListView1.SelectedItems(0))
End If
Catch ex As Exception
End Try
End Select
Change the Case name from "Edit" to "&Edit" same as the declared name above..