Question

I am trying to mimic the behavior of, for example, Windows Explorer and how the Favorites items can launch a context menu.

I currently am using:

contextMenu.Show((sender as ToolStripMenuItem).GetCurrentParent().PointToScreen(e.Location));

This occurs in the MouseDown event of the ToolStripMenuItem. The problem is that the menu closes immediately after right-click, and I don't know any way to suspend it while the context menu is open.

I've tried deriving from ToolStripMenuItem and overriding the MouseDown/MouseUp but I can't figure out how to keep it open on click.

Is there a good way of doing this?

Was it helpful?

Solution

One way that you could accomplish this is by using the ToolStripDropDown control to host a ListBox inside of the ToolStripDropDown.

This may require some tweaking regarding the AutoClose behavior, but it should get you started:

First in your main form, add the following line to your ToolStripDropDropDown item

toolStripDropDownButton1.DropDown = new CustomListDropDown();

Then create a custom drop down class as follows:

public class CustomListDropDown : ToolStripDropDown
{
    private ContextMenuStrip contextMenuStrip1;
    private ToolStripMenuItem toolStripMenuItem1;
    private ToolStripMenuItem toolStripMenuItem2;
    private ToolStripMenuItem toolStripMenuItem3;
    private System.ComponentModel.IContainer components;

    public ListBox ListBox { get; private set; }

    public CustomListDropDown()
    {
        InitializeComponent();

        this.ListBox = new ListBox() { Width = 200, Height = 600 };
        this.Items.Add(new ToolStripControlHost(this.ListBox));

        this.ListBox.ContextMenuStrip = contextMenuStrip1;
        this.ListBox.MouseDown += new MouseEventHandler(ListBox_MouseDown);

        contextMenuStrip1.Closing += new ToolStripDropDownClosingEventHandler(contextMenuStrip1_Closing);

        //add sample items
        this.ListBox.Items.Add("Item1");
        this.ListBox.Items.Add("Item2");
        this.ListBox.Items.Add("Item3");
        this.ListBox.Items.Add("Item4");
    }

    void contextMenuStrip1_Closing(object sender, ToolStripDropDownClosingEventArgs e)
    {
        this.Close();
        this.AutoClose = true;
    }

    void ListBox_MouseDown(object sender, MouseEventArgs e)
    {
        this.AutoClose = false;
        this.ListBox.SelectedIndex = this.ListBox.IndexFromPoint(e.Location);
    }

    private void InitializeComponent()
    {
        this.components = new System.ComponentModel.Container();
        this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components);
        this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem();
        this.toolStripMenuItem2 = new System.Windows.Forms.ToolStripMenuItem();
        this.toolStripMenuItem3 = new System.Windows.Forms.ToolStripMenuItem();
        this.contextMenuStrip1.SuspendLayout();
        this.SuspendLayout();
        // 
        // contextMenuStrip1
        // 
        this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
        this.toolStripMenuItem1,
        this.toolStripMenuItem2,
        this.toolStripMenuItem3});
        this.contextMenuStrip1.Name = "contextMenuStrip1";
        // 
        // contextMenuStrip1.ContextMenuStrip
        // 
        this.contextMenuStrip1.Size = new System.Drawing.Size(181, 48);
        // 
        // toolStripMenuItem1
        // 
        this.toolStripMenuItem1.Name = "toolStripMenuItem1";
        this.toolStripMenuItem1.Size = new System.Drawing.Size(180, 22);
        this.toolStripMenuItem1.Text = "toolStripMenuItem1";
        // 
        // toolStripMenuItem2
        // 
        this.toolStripMenuItem2.Name = "toolStripMenuItem2";
        this.toolStripMenuItem2.Size = new System.Drawing.Size(180, 22);
        this.toolStripMenuItem2.Text = "toolStripMenuItem2";
        // 
        // toolStripMenuItem3
        // 
        this.toolStripMenuItem3.Name = "toolStripMenuItem3";
        this.toolStripMenuItem3.Size = new System.Drawing.Size(180, 22);
        this.toolStripMenuItem3.Text = "toolStripMenuItem3";
        // 
        // CustomListDropDown
        // 
        this.Size = new System.Drawing.Size(2, 4);
        this.contextMenuStrip1.ResumeLayout(false);
        this.ResumeLayout(false);

    }
}

In my tests this worked reasonably well. Let me know how it goes.

OTHER TIPS

This is what I've had luck with, it's a bit more direct:

    public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }
    void MenuItemContext(object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left) return;

        ToolStripMenuItem mID = (ToolStripMenuItem)sender;

        ContextMenu tsmiContext = new ContextMenu();

        MenuItem Item1 = new MenuItem();
        MenuItem Item2 = new MenuItem();

        Item1.Text = "Item1";
        Item2.Text = "Item2";

        tsmiContext.MenuItems.Add(Item1);
        tsmiContext.MenuItems.Add(Item2);

        Item1.Click += new EventHandler(Item1_Click);
        Item2.Click += new EventHandler(Item2_Click);

        hndPass = mID.Text;

        tsmiContext.Show(menuStrip1, menuStrip1.PointToClient(new Point(Cursor.Position.X, Cursor.Position.Y)));
    }

    private String hndPass;

    void Item1_Click(object sender, EventArgs e)
    {
       MenuItem mID = (MenuItem)sender;
        MessageBox.Show("You clicked " + mID.Text + " in the context menu of " + hndPass);
    }
    void Item2_Click(object sender, EventArgs e)
    {
        MenuItem mID = (MenuItem)sender;
        MessageBox.Show("You clicked " + mID.Text + " in the context menu of " + hndPass); ;
    }
}

As ContextMenuStrip is derived from ToolStripDropDown, you could do this:

    private ContextMenuStrip CopyToContextMenu(ToolStripMenuItem mnuItemSource)
    {
        var mnuContextDestination =  new ContextMenuStrip();

        //Move itens from ToolStripMenuItem to ContextMenuStrip
        while (mnuItemSource.DropDown.Items.Count > 0)
        {
            mnuContextDestination.Items.Add(mnuItemSource.DropDown.Items[0]);
        }

        //Put ContextMenuStrip in ToolStripMenuItem using DropDown property
        mnuItemSource.DropDown = mnuContextDestination;

        return mnuContextDestination;
    }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top