【问题标题】:How to work around missing event ToolStripMenuItem.Showing?如何解决缺少的事件 ToolStripMenuItem.Showing?
【发布时间】:2013-01-09 23:54:12
【问题描述】:

我需要知道工具条菜单项何时显示(以便基于 JIT 创建内容)。

我有一个潜在的非常大的东西层次结构。它可以在树视图中导航,也可以通过“面包屑”导航,例如“音乐 > 流行音乐 > 迈克尔杰克逊 > 坏”。面包屑由工具条实现,每个级别都显示有一个 LinkLabel。单击链接时,例如“音乐”,一个上下文菜单与当前项目的所有同级一起动态构建。

我试图营造一种总是加载整个层次结构的错觉。当我获取数据时,我确保获得足够的信息来呈现一个节点并知道该节点是否有子节点。如果它确实有孩子,我创建一个具有特殊含义的虚拟节点“这个项目有卸载的孩子”并将其作为唯一的孩子。这会导致树视图将节点呈现为可展开的。然后,我使用树视图的 BeforeExpand 事件来获取下一个级别并及时更新节点集合,当它实际要显示时。

这对树很有效,但我需要对面包屑样式的上下文菜单做同样的事情。我已经为有孩子的项目创建了一个子菜单,将我的特殊“未加载的孩子”项目放在那里。问题是我找不到让我知道该子菜单何时显示的事件。这可以通过悬停、点击、键盘导航等方式实现;如果我还没有找到更合适的钩子,我真的不想破解它..

换句话说,我需要的是与“BeforeExpand”等效的东西,但对于 ToolStripMenuItem(根据 MS 自己的命名准则,事件 btw 应该称为“NodeExpanding”,即动名词形式(“ing”)应该使用而不是“Before”前缀,过去时(“Expanded”)而不是“After”前缀)。

我希望很清楚我想要做什么,并且有人知道如何解决这个问题!

【问题讨论】:

    标签: .net winforms toolstripmenu


    【解决方案1】:

    事实证明我可以使用 Paint 事件。我真的不认为它会起作用,但它确实起作用了。

    如果我们对 ToolStripMenuItem 使用术语“item”,对层次结构中的逻辑节点使用“node”,我们可以将 Paint 处理程序伪编码(实际上是我的 PoC 项目中的 C# 代码):

    void menuItem_Paint(object sender, PaintEventArgs e)
    {
        var item = (ToolStripMenuItem)sender;
    
        var node = item.Tag as Node;
        if (node == null || node.Parent == null || node.Parent.RealChildren)
            return;
    
        node = node.Parent;
        item = FindMenuItem(menu.Items, node);
    
        if (node != null)
            ReplaceDummyWithData(node, item);
    }
    
    void ReplaceDummyWithData(Node node, ToolStripMenuItem item)
    {
        Dbug("Removing dummy: {0}", node.Label);
    
        // Modify logical tree..
        node.Remove(node.Children[0]);
        MakeNode(node, "Data #1");
        MakeNode(node, "Data #2");
    
        // Rebuild menu items..
        item.DropDownItems.Clear();
        AddMenuItems(item.DropDownItems, node.Children);
        node.RealChildren = true;
    }
    

    我真的不认为这会起作用,但它似乎工作正常。我刚刚硬编码了一个无限深的层次结构,其中每个项目都有两个标记为“Data #1”和“Data #2”的孩子,但修改它并不难,因此项目是根据真实数据创建的。关键是要找出一种方法来即时修改菜单项树,这似乎是一种可以接受的方法。

    FindMenuItem 是对带有给定节点标记的项目的递归搜索,

    ToolStripMenuItem FindMenuItem(ToolStripItemCollection collection, Node node)
    {
        foreach (ToolStripMenuItem item in collection)
        {
            if (item.Tag == node)
                return item;
    
            var found = FindMenuItem(item.DropDownItems, node);
            if (found != null) 
                return found;
        }
        return null;
    }
    

    PoC 中的 MakeNode 总是会创建一个虚拟子节点,但在数据驱动的事情中,我会根据它是否真的有子节点来创建:

    Node MakeNode(Node parent, string label)
    {
        var n = new Node(parent) { Label = label, RealChildren = false };
        new Node(n) { Label = "dummy" };
        return n;
    }
    

    Node 构造函数取父节点;也许不是最易读的代码。它来自我的 PoC,代码的目的是找出我的问题的解决方案,而不是编写在其他方面都很棒的代码!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-10-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多