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