Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to show a Context Menu when you right click a Menu Item

I am porting an MFC application to .NET WinForms. In the MFC application, you can right click on a menu or on a context menu item and we show another context menu with diagnostic and configuration items. I am trying to port this functionality to .NET, but I am having trouble.

I have been able to capture the right click, disable the click of the underlying menu and pop up a context menu at the right location, but the original menu disappears as soon as it loses focus.

In MFC, we show the new context menu by calling TrackPopupMenuEx with the TPM_RECURSE flag.

ContextMenu and the newer ContextMenuStrip classes in .NET only have a Show method. Does anyone know how to do this in .NET?

EDIT

I have tried using TrackPopupMenuEx through a p/invoke, but that limits you to using a ContextMenu instead of a ContextMenuStrip which looks out of place in our application. It also still does not work correctly. It doesn't work with the new MenuStrip and ContextMenuStrip.

I have also tried subclassing ToolStripMenuItem to see if I can add a context menu to it. That is working for MenuStrip, but ContextMenuStrip still allows the right click events to pass through as clicks.

like image 939
Rob Prouse Avatar asked Nov 11 '08 18:11

Rob Prouse


1 Answers

Edit, due to a comment:

In:

protected override void OnClick(EventArgs e)
{
    if (SecondaryContextMenu == null || MouseButtons != MouseButtons.Right)
    {
        base.OnClick(e);
    }
}

this part

 MouseButtons != MouseButtons.Right

should and does compile as it is a call to Control.MouseButtons. Since the Form inherits Control class, it is sufficient to call MouseButtons property directly.

Hope this helps:

public partial class Form1 : Form
{
    class CustomToolStripMenuItem : ToolStripMenuItem
    {
        private ContextMenuStrip secondaryContextMenu;

        public ContextMenuStrip SecondaryContextMenu
        {
            get
            {
                return secondaryContextMenu;
            }
            set
            {
                secondaryContextMenu = value;
            }
        }

        public CustomToolStripMenuItem(string text)
            : base(text)
        { }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (secondaryContextMenu != null)
                {
                    secondaryContextMenu.Dispose();
                    secondaryContextMenu = null;
                }
            }

            base.Dispose(disposing);
        }

        protected override void OnClick(EventArgs e)
        {
            if (SecondaryContextMenu == null || MouseButtons != MouseButtons.Right)
            {
                base.OnClick(e);
            }
        }
    }

    class CustomContextMenuStrip : ContextMenuStrip
    {
        private bool secondaryContextMenuActive = false;
        private ContextMenuStrip lastShownSecondaryContextMenu = null;

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (lastShownSecondaryContextMenu != null)
                {
                    lastShownSecondaryContextMenu.Close();
                    lastShownSecondaryContextMenu = null;
                }
            }
            base.Dispose(disposing);
        }

        protected override void OnControlAdded(ControlEventArgs e)
        {
            e.Control.MouseClick += new MouseEventHandler(Control_MouseClick);
            base.OnControlAdded(e);
        }

        protected override void OnControlRemoved(ControlEventArgs e)
        {
            e.Control.MouseClick -= new MouseEventHandler(Control_MouseClick);
            base.OnControlRemoved(e);
        }

        private void Control_MouseClick(object sender, MouseEventArgs e)
        {
            ShowSecondaryContextMenu(e);
        }

        protected override void OnMouseClick(MouseEventArgs e)
        {
            ShowSecondaryContextMenu(e);
            base.OnMouseClick(e);
        }

        private bool ShowSecondaryContextMenu(MouseEventArgs e)
        {
            CustomToolStripMenuItem ctsm = this.GetItemAt(e.Location) as CustomToolStripMenuItem;

            if (ctsm == null || ctsm.SecondaryContextMenu == null || e.Button != MouseButtons.Right)
            {
                return false;
            }

            lastShownSecondaryContextMenu = ctsm.SecondaryContextMenu;
            secondaryContextMenuActive = true;
            ctsm.SecondaryContextMenu.Closed += new ToolStripDropDownClosedEventHandler(SecondaryContextMenu_Closed);
            ctsm.SecondaryContextMenu.Show(Cursor.Position);
            return true;
        }

        void SecondaryContextMenu_Closed(object sender, ToolStripDropDownClosedEventArgs e)
        {
            ((ContextMenuStrip)sender).Closed -= new ToolStripDropDownClosedEventHandler(SecondaryContextMenu_Closed);
            lastShownSecondaryContextMenu = null;
            secondaryContextMenuActive = false;
            Focus();
        }

        protected override void OnClosing(ToolStripDropDownClosingEventArgs e)
        {
            if (secondaryContextMenuActive)
            {
                e.Cancel = true;
            }

            base.OnClosing(e);
        }
    }

    public Form1()
    {
        InitializeComponent();


        CustomToolStripMenuItem itemPrimary1 = new CustomToolStripMenuItem("item primary 1");
        itemPrimary1.SecondaryContextMenu = new ContextMenuStrip();
        itemPrimary1.SecondaryContextMenu.Items.AddRange(new ToolStripMenuItem[] { 
            new ToolStripMenuItem("item primary 1.1"),
            new ToolStripMenuItem("item primary 1.2"),
        });

        CustomToolStripMenuItem itemPrimary2 = new CustomToolStripMenuItem("item primary 2");
        itemPrimary2.DropDownItems.Add("item primary 2, sub 1");
        itemPrimary2.DropDownItems.Add("item primary 2, sub 2");
        itemPrimary2.SecondaryContextMenu = new ContextMenuStrip();
        itemPrimary2.SecondaryContextMenu.Items.AddRange(new ToolStripMenuItem[] { 
            new ToolStripMenuItem("item primary 2.1"),
            new ToolStripMenuItem("item primary 2.2"),
        });

        CustomContextMenuStrip primaryContextMenu = new CustomContextMenuStrip();
        primaryContextMenu.Items.AddRange(new ToolStripItem[]{
            itemPrimary1,
            itemPrimary2
        });

        this.ContextMenuStrip = primaryContextMenu;
    }
}
like image 54
Eren Aygunes Avatar answered Oct 09 '22 08:10

Eren Aygunes