如何解决丢失事件ToolStripMenuItem.Showing?

时间:2013-01-08 15:57:34

标签: .net winforms toolstripmenu

我需要知道何时将显示工具条菜单项(为了在JIT基础上创建内容)。

我有一个非常大的层次结构。它可以在树视图中导航,但也可以通过“面包屑”导航,例如“Music> Pop> Michael Jackson> Bad”。面包屑由工具条实现,每个级别都带有LinkLabel。点击链接时,例如“音乐”,上下文菜单是与当前项目的所有兄弟一起动态构建的。

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

这适用于树,但我需要为breadcrumbs样式的上下文菜单做同样的事情。我已经为有孩子的物品创建了一个子菜单,将我特殊的“卸载的孩子”物品放在那里。问题是我无法找到一个事件,让我知道该子菜单即将显示的时间。这可以通过悬停,点击,键盘导航等方式实现;我真的不想破解它,如果有一个更合适的钩子我还没有找到..

换句话说,我需要的东西相当于“BeforeExpand”但是对于ToolStripMenuItem(根据MS自己的命名指南,事件btw应该被称为“NodeExpanding”,它表示动名形式(“ing”)应该使用而不是“Before”前缀和过去时(“Expanded”)而不是“After”前缀。

我希望我很清楚我正在尝试做什么,而且有人知道如何解决这个问题!

1 个答案:

答案 0 :(得分:0)

事实证明我可以使用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,代码的目的是找出解决我的问题的方法,而不是编写在其他方面很棒的代码!