locked
How do I programmatically simulate a mouse Right-Click in VB to raise a Context Menu?

    Question

  • I've read the suggestion in the Studio Help system on simulating the mouse right-click event, but for the life of me I can't write anything that VB will accept ... can someone help please?

     

    It's simple - I want to raise a Context MenuStrip when I move the mouse over a button, ie. just the mouse moving over the button must cause the menu to appear at that position exactly as though the user has pressed the mouse right-button there. The action would be just like a JavaScript menu popping up on a web page. Can I do this from code without creating a special form?

     

    I appreciate that putting a normal ContextMenu on the button is the right way, but educating users to actually press the mouse right button is a big issue.

     

    A further benefit would be to have the context menu disappear when the mouse moves off it. Is that possible too? A sort of OnMouseLeave close the menu.

     

    In attempting to get round the problem another way I wrote a piece to ShowDialog another small form (with the appearance of a menu, using labels and MouseOver to drive the colour changes etc.) but handling the form's mouse enter and leave stuff is a nightmare - I used a panel for the menu area and made the form 20px bigger all round but with the Transparency Key set to the colour of the form (I used Maroon), and used MouseMove to track mouse position in this "run-out" border to control the exit detection process. Works absolutely fine on a Vista machine, fails completely in XP because it seems the transparency key kills any MouseMove detection ... whereas in Vista this is OK. Strange ... I thought XP and Vista should handle the same in VS?

     

    So - the proper right-click menu simulation is necessary.

     

    Any cute ideas much appreciated.

     

    Nick

    Tuesday, May 27, 2008 2:52 PM

Answers

  • Nick,

     

    ContextMenuStrip controls have .show and .hide methods you can call to programmatically show the contextmenu instead of assigning it to the specific control at design time, and letting the runtime handle the showing and hiding on the right mouse click.

     

    So in your buttons mousemove event, you can check and see if the menu is being shown, and if it is not then show it

     

    Code Snippet

    Private Sub Button1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Button1.MouseMove

    If Not ContextMenuStrip1.Visible Then

    ContextMenuStrip1.Show(Button1, button1.Location)

    End If

    End Sub

     

     

     

    however, hiding the menu when they leave the button may be a bit trickier. There is a mouseleave event, however it will fire when the mouse leaves the bounds of the button even if its to select a context menu item, or when the context menu.

     

    You might want to use a timer to dismiss the contextmenu, or even have an item in the context menu that is called "close menu" which does just that.

    Tuesday, May 27, 2008 4:27 PM
    Moderator
  • Put this code in a new, empty form class to test it:

     

    Code Snippet

    Friend WithEvents cms As New ContextMenuStrip

    Friend WithEvents btn As New Button

     

    Private justHidden As Boolean = False

     

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

    With cms

    .Items.Add("first item")

    .Items.Add("second item")

    .Items.Add("third item")

    End With

    With btn

    .Size = New Size(200, 200)

    .Location = New Point(10, 10)

    .Text = "New Button".ContextMenuStrip = cms

    End With

    Me.Controls.Add(btn)

    End Sub

    Private Sub btn_MouseEnter(ByVal sender As Object, ByVal e As System.EventArgs) Handles btn.MouseEnter

    If Not justHidden AndAlso Not cms.Visible Then

    Me.cms.Show(MousePosition)

    Dim t As New Timer

    With t

    .Interval = 1500

    AddHandler .Tick, AddressOf showTimer_tick

    .Start()

    End With

    End If

    End Sub

    Private Sub showTimer_tick(ByVal sender As Object, ByVal e As System.EventArgs)

    Dim t As Timer = sender

    t.Stop()

    t.Dispose()

    'only hide it if the mouseposition is outside the bounds'of the contextmenustripIf Not Me.cms.Bounds.Contains(MousePosition) Then

    hideCMS(Me.cms, New System.EventArgs())

    Else

    AddHandler Me.cms.MouseLeave, AddressOf hideCMS

    End If

    End Sub

    Private Sub hideCMS(ByVal sender As Object, ByVal e As System.EventArgs)

    RemoveHandler Me.cms.MouseLeave, AddressOf hideCMS

    Me.cms.Hide()

    Me.justHidden = TrueDim t As New Timer

    With t

    .Interval = 100

    AddHandler .Tick, AddressOf hideTimer_tick

    .Start()

    End With

    End Sub

    Private Sub hideTimer_tick(ByVal sender As Object, ByVal e As System.EventArgs)

    Dim t As Timer = sender

    t.Stop()

    t.Dispose()

    justHidden = False

    End Sub

     

     

    Tuesday, May 27, 2008 5:05 PM

All replies

  • Nick,

     

    ContextMenuStrip controls have .show and .hide methods you can call to programmatically show the contextmenu instead of assigning it to the specific control at design time, and letting the runtime handle the showing and hiding on the right mouse click.

     

    So in your buttons mousemove event, you can check and see if the menu is being shown, and if it is not then show it

     

    Code Snippet

    Private Sub Button1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Button1.MouseMove

    If Not ContextMenuStrip1.Visible Then

    ContextMenuStrip1.Show(Button1, button1.Location)

    End If

    End Sub

     

     

     

    however, hiding the menu when they leave the button may be a bit trickier. There is a mouseleave event, however it will fire when the mouse leaves the bounds of the button even if its to select a context menu item, or when the context menu.

     

    You might want to use a timer to dismiss the contextmenu, or even have an item in the context menu that is called "close menu" which does just that.

    Tuesday, May 27, 2008 4:27 PM
    Moderator
  • Put this code in a new, empty form class to test it:

     

    Code Snippet

    Friend WithEvents cms As New ContextMenuStrip

    Friend WithEvents btn As New Button

     

    Private justHidden As Boolean = False

     

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

    With cms

    .Items.Add("first item")

    .Items.Add("second item")

    .Items.Add("third item")

    End With

    With btn

    .Size = New Size(200, 200)

    .Location = New Point(10, 10)

    .Text = "New Button".ContextMenuStrip = cms

    End With

    Me.Controls.Add(btn)

    End Sub

    Private Sub btn_MouseEnter(ByVal sender As Object, ByVal e As System.EventArgs) Handles btn.MouseEnter

    If Not justHidden AndAlso Not cms.Visible Then

    Me.cms.Show(MousePosition)

    Dim t As New Timer

    With t

    .Interval = 1500

    AddHandler .Tick, AddressOf showTimer_tick

    .Start()

    End With

    End If

    End Sub

    Private Sub showTimer_tick(ByVal sender As Object, ByVal e As System.EventArgs)

    Dim t As Timer = sender

    t.Stop()

    t.Dispose()

    'only hide it if the mouseposition is outside the bounds'of the contextmenustripIf Not Me.cms.Bounds.Contains(MousePosition) Then

    hideCMS(Me.cms, New System.EventArgs())

    Else

    AddHandler Me.cms.MouseLeave, AddressOf hideCMS

    End If

    End Sub

    Private Sub hideCMS(ByVal sender As Object, ByVal e As System.EventArgs)

    RemoveHandler Me.cms.MouseLeave, AddressOf hideCMS

    Me.cms.Hide()

    Me.justHidden = TrueDim t As New Timer

    With t

    .Interval = 100

    AddHandler .Tick, AddressOf hideTimer_tick

    .Start()

    End With

    End Sub

    Private Sub hideTimer_tick(ByVal sender As Object, ByVal e As System.EventArgs)

    Dim t As Timer = sender

    t.Stop()

    t.Dispose()

    justHidden = False

    End Sub

     

     

    Tuesday, May 27, 2008 5:05 PM
  • Thank you both for your enlightenment - I'm up and running again.

    Nick

    Tuesday, May 27, 2008 5:38 PM