.NET Multiple ToolStripButtons in a single ContextMenuItem

谁说我不能喝 提交于 2019-12-01 12:04:08

A ContextMenuStrip is too attractive a target for custom popup windows that don't act like a context menu. It is desirable because it automatically pops down when the user clicks outside of the menu. It has limitations though, it just isn't a very good control host. The click problem is classical one, CMS captures the mouse to detect when the user clicks outside of the window.

This really ought to be a form. To give it the same behavior as a CMS requires a bit of work though. You have to detect mouse clicks that are off the window so you can make the window disappear. Capturing the mouse like CMS does doesn't work. One trick is using IMessageFilter, it lets you take a peek at input messages before they are delivered to the window with the focus. Here's a sample form that implements this:

public partial class MyContextMenu : Form, IMessageFilter {
    public MyContextMenu() {
        InitializeComponent();
        Application.AddMessageFilter(this);
    }
    protected override void OnFormClosed(FormClosedEventArgs e) {
        Application.RemoveMessageFilter(this);
        base.OnFormClosed(e);
    }
    public void Show(Control ctl, Point pos) {
        this.StartPosition = FormStartPosition.Manual;
        this.Location = ctl.PointToScreen(pos);
        while (!(ctl is Form)) ctl = ctl.Parent;
        this.Show((Form)ctl);
    }
    public bool PreFilterMessage(ref Message m) {
        // Detect mouse clicks outside of the form
        if (m.Msg == 0x201 || m.Msg == 0x204 || m.Msg == 0x207 || 
            m.Msg == 0xA1  || m.Msg == 0xA4  || m.Msg == 0xA7) {
            Point pos = new Point(m.LParam.ToInt32());
            Control ctl = Control.FromHandle(m.HWnd);
            if (ctl != null) pos = ctl.PointToScreen(pos);
            pos = this.PointToClient(pos);
            if (pos.X < 0 || pos.Y < 0 || pos.X >= this.Width || pos.Y >= this.Height) {
                this.Close();
            }
        }
        return false;
    }
}

Use the designer as normal to design the form. You want to at least give it a different FormBorderStyle. Use the provided Show() method overload the same way you use it for CMS. Do note that the form pops down only when you click on a window that's owned by the application, unlike a CMS. Feature, not a bug.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!