Search code examples
c#contextmenustrip

C# how to get referece to ContextMenuStrip from underlying sub menuitems of at least two levels


How to get the referece to ContextMenuStrip from its underlying sub menuitem which is a ToolStripMenuItem of a ToolStripDropDownMenu which is a Dropdown of a ToolstripMenuItem of this ContextMenuStrip?

the problem lies in the ToolStripDropDownMenu class,where can't find a property refer to upperlevel objects such as its assciated ToolStripMenuItem.Its Parent,Container properties and GetContainerControl() method all return null.

My purpose is to know the SourceControl of the ContextMenuStrip when any of its underlying menu items are clicked.


Solution

  • You need a backward loop to get the first OwnerItem property of a given ToolStripItem (or one of the derived classes) in a branch then you can get the main ToolStrip (which can be a ToolStrip, MenuStrip, StatusStrip, or ContextMenuStrip control) through the ToolStripItem.Owner property.

    Consider the following extension methods:

    public static class ToolStripExtensions
    {
        public static ToolStrip GetMainToolStrip(this ToolStripItem tsi)
        {
            if (tsi == null) return null;
            if (tsi.OwnerItem == null) return tsi.Owner;
    
            var oi = tsi.OwnerItem;
    
            while (oi.OwnerItem != null) oi = oi.OwnerItem;
    
            return oi.Owner;
        }
    
        public static ToolStrip GetMainToolStrip(this ToolStrip ts)
        {
            ToolStrip res = ts;
    
            var m = ts as ToolStripDropDownMenu;
    
            if (m?.OwnerItem != null)
                res = GetMainToolStrip(m.OwnerItem);
    
            return res;
        }
    }
    

    Here's an example that shows how to get the ContextMenuStrip.SourceControl in the ItemClicked event:

    private void cmnu_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
    {
        if (e.ClickedItem.GetMainToolStrip() is ContextMenuStrip cmnu)
            Console.WriteLine(cmnu.SourceControl.Name);
    }