C# 如何从至少两个级别的底层子菜单项中获取对 ContextMenuStrip 的引用

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

如何从其底层子菜单项获取对 ContextMenuStrip 的引用,该子菜单项是 ToolStripDropDownMenu 的 ToolStripMenuItem,而 ToolStripDropDownMenu 是此 ContextMenuStrip 的 ToolstripMenuItem 的下拉菜单?

问题出在 ToolStripDropDownMenu class,其中找不到 属性 引用上层对象,例如其关联的 ToolStripMenuItem.Its Parent、Container 属性和 GetContainerControl() 方法全部 return 为空。

我的目的是在单击其任何基础菜单项时了解 ContextMenuStrip 的 SourceControl。

您可以使用 OwnerItem 属性 得到 ToolStripItem:

private void toolStripComboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
    var comboBox = sender as ToolStripComboBox;
    var twoLevelParent = comboBox.OwnerItem.OwnerItem;
}

您需要一个反向循环来获得第一个 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 属性.

考虑以下扩展方法:

public static 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;
    }
}

下面是一个显示如何获取 ContextMenuStrip.SourceControl in the ItemClicked 事件的示例:

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