我需要知道何时将显示工具条菜单项(为了在JIT基础上创建内容)。
我有一个非常大的层次结构。它可以在树视图中导航,但也可以通过“面包屑”导航,例如“Music> Pop> Michael Jackson> Bad”。面包屑由工具条实现,每个级别都带有LinkLabel。点击链接时,例如“音乐”,上下文菜单是与当前项目的所有兄弟一起动态构建的。
我试图创建一个总是加载整个层次结构的错觉。当我获取数据时,我确保获得足够的信息来呈现节点并知道该节点是否有子节点。如果它确实有子节点,我创建一个具有特殊含义的虚拟节点“此项目已卸载子节点”并将其作为唯一的子节点。这会导致树视图将节点呈现为可扩展。然后,我使用树视图的BeforeExpand事件来获取下一个级别,并及时更新节点集合,当它实际显示时。
这适用于树,但我需要为breadcrumbs样式的上下文菜单做同样的事情。我已经为有孩子的物品创建了一个子菜单,将我特殊的“卸载的孩子”物品放在那里。问题是我无法找到一个事件,让我知道该子菜单即将显示的时间。这可以通过悬停,点击,键盘导航等方式实现;我真的不想破解它,如果有一个更合适的钩子我还没有找到..
换句话说,我需要的东西相当于“BeforeExpand”但是对于ToolStripMenuItem(根据MS自己的命名指南,事件btw应该被称为“NodeExpanding”,它表示动名形式(“ing”)应该使用而不是“Before”前缀和过去时(“Expanded”)而不是“After”前缀。
我希望我很清楚我正在尝试做什么,而且有人知道如何解决这个问题!
答案 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,代码的目的是找出解决我的问题的方法,而不是编写在其他方面很棒的代码!