Reputation: 148
Situation:
I have a context menu in a VB.NET form with fires an event handler on ItemClicked
. The auto-generated subroutine receives sender
and e
as parameters. As I don't reinvent the wheel multiple times, I linked this context menu to three text boxes. Let's name them Textbox1, Textbox2 and Textbox3.
Problem: How can I figure out in which textbox the menu was opened?
Okay, what did I already try?
sender
contains the menu itself,e.ClickedItem
just returns the single menu item that was selected.sender.Parent
is always nothingsender.OwnerItem
is also always Nothing`Me.Textbox1.Focused
is always False
, even if its the "parent" control of the menu.Upvotes: 3
Views: 2688
Reputation: 38875
The ContextMenuStrip
has a SourceControl
property which contains a reference to the control which opened the menu. The event fires from one of the ToolStripMenuItem
s in the ContextMenuStrip, so you have to get the "parent" first:
' cast sender to menuitem
Dim mi = CType(sender, ToolStripMenuItem)
' cast mi.Owner to CMS
Dim cms = CType(mi.Owner, ContextMenuStrip)
' the control which opened the menu:
Console.WriteLine(cms.SourceControl.Name)
Under certain conditions the SourceControl can get lost but you can track it yourself with a variable and the parent ContextMenuStrip Opening event:
' tracking var:
Private MenuSourceControl As Control
Private Sub cms_Opening(sender As Object, e As CancelEventArgs) Handles cms.Opening
' set reference in case/before it is lost
MenuSourceControl = CType(sender, ContextMenuStrip).SourceControl
End Sub
Private Sub CutToolStripMenuItem_Click(sender...
If MenuSourceControl IsNot Nothing Then
' do your stuff
' optionally clear the tracking var
MenuSourceControl = Nothing
End If
End Sub
It should be also easier to get the SourceControl when dealing with sub items
You can also capture the related control in the MouseDown
event of the related Control
in cases where the same menu is used with different controls:
Private Sub lv2_MouseDown(sender As Object,
e As MouseEventArgs) Handles lv2.MouseDown,
myLV.MouseDown, lv1.MouseDown ...
If e.Button = Windows.Forms.MouseButtons.Right Then
MenuSourceControl = DirectCast(sender, Control)
End If
End Sub
Upvotes: 2
Reputation: 148
Okay, I found a solution that works fine, and here's the code for all VB.NET coders that have the same problem.
The context menu is linked in TextBox1, so we need to add another event handler that saves the sending control into the menu:
Private Sub TextBox1_MouseUp(sender As Windows.Forms.Control, e As System.Windows.Forms.MouseEventArgs) Handles TextBox1.MouseUp
If e.Button = Windows.Forms.MouseButtons.Right Then
ContextMenu.Tag = sender
End If
End Sub
And this is the code of the event handler when clicking a menu item:
Private Sub ContextMenu_ItemClicked(sender As System.Object, e As System.Windows.Forms.ToolStripItemClickedEventArgs) Handles ContextMenu.ItemClicked
ContextMenu.Close()
If ContextMenu.Tag Is Nothing Then
Debug.Print("debug info: forgot to set sender? well ... KABOOM!")
Exit Sub
End If
Dim oParent As Windows.Forms.Control
Try
oParent = ContextMenu.Tag
Catch ex As Exception
Debug.Print("debug info: tag contains data other than sender control. well ... KABOOM!")
Exit Sub
End Try
' Do fancy stuff here.
' Release sender
ContextMenu.Tag = Nothing
End Sub
Upvotes: 2