Search code examples
c#mousemouseleavecontextmenustrip

How to check if mouse is in ContextMenuStrip or in its items


I´m using ContextMenuStrip in my Form app as my drop down menu. Exactly, when I click on button, ContextMenuStrip shows right under it. Everithing is OK, but I really want to auto-close ContextMenuStrip after mouse leave its area. Ok, so I´m try to use MouseLeave event. Once again, everything is OK, but when I add dropdown items to some ToolStripItem in ContextMenuStrip, the mouseLeave event donť recognize this new area as a part of ContextMenuStrip. This is my newest attempt, but it is not finished. Any idea, how to resolve this problem?

    private void ContextMenuStrip_MouseLeave(object sender, EventArgs e)
    {
        ContextMenuStrip cms = (sender is ContextMenuStrip) ? sender as ContextMenuStrip : null;

        if (cms != null)
        {
            //List<Rectangle> cmsFullArea = new List<Rectangle>();
            //cmsFullArea.Add(new Rectangle(cms.Bounds.Location, cms.Bounds.Size));

            bool itemIsPressed = false;
            for (int i = 0; i < cms.Items.Count; i++)
            {
                if (cms.Items[i].Pressed) { itemIsPressed = true; break; }
            }

            if (!itemIsPressed) { cms.Close(); }
        }
    }

This works fine, when I leave CMS to dropDown items, but it is not working, when I leave them too after. I need to close whole CMS, when I leave any of his areas.


Solution

  • Add a region variable which will be ContextMenuStrip plus the DropDownMenus.

    private Region rgn = new Region();
    

    Initialize region:

    public Form1() {
        InitializeComponent();
    
        rgn.MakeEmpty();
    }
    

    When ContextMenuStrip opens update region:

    private void contextMenuStrip1_Opened( object sender, EventArgs e ) {
        rgn.Union( contextMenuStrip1.Bounds );
    }
    

    In leave event check if mouse is inside this region:

    private void contextMenuStrip1_MouseLeave( object sender, EventArgs e ) {
        Point pnt = Cursor.Position;
    
        if( rgn.IsVisible( pnt ) == false ) {
            rgn.MakeEmpty();
    
            contextMenuStrip1.Close();
        }
    }
    

    When you create a new ToolStripDropDownMenu adding items to eg toolStripMenuItem0, add these event handlers:

    //toolStripMenuItem0 is an item of your ContextMenuStrip
    toolStripMenuItem0.DropDown.MouseLeave += DropDown_MouseLeave;
    toolStripMenuItem0.DropDown.Opened += DropDown_Opened;
    toolStripMenuItem0.DropDown.Closed += DropDown_Closed;
    
    private void DropDown_Closed( object sender, ToolStripDropDownClosedEventArgs e ) {
        ToolStripDropDownMenu tsddm = (ToolStripDropDownMenu)sender;
    
        rgn.Exclude( tsddm.Bounds ); //remove rect from region
    }
    
    private void DropDown_Opened( object sender, EventArgs e ) {
        ToolStripDropDownMenu tsddm = (ToolStripDropDownMenu)sender;
    
        rgn.Union( tsddm.Bounds ); //add rect to region
    }
    
    private void DropDown_MouseLeave( object sender, EventArgs e ) {
        Point pnt = Cursor.Position;
    
        if( rgn.IsVisible( pnt ) == false ) {
            rgn.MakeEmpty();
    
            contextMenuStrip1.Close();
        }
    }
    

    Do the same for every DropDownMenu you create.