我正在使用ToolStripMenu
文件中的条目填充XML
。添加到菜单中的每个ToolStripItem
会自动获取分配给它的十几个事件处理程序。用户可以选择更改XML
并刷新菜单,使用以下命令清除所有内容:
menuStrip1.Items.Clear();
从XML
重新填充并刷新表单。似乎所有这些动态项的事件处理程序永远不会从内存中删除。大多数项目不直接位于menuStrip1上,而是位于menuStrip1
上的动态创建的子菜单中。
尽管如此,我可以坐在那里刷新表单和内存只是气球失控,每次刷新大约5-10 MB
时添加100 dynamic ToolStripItems.
它可以快速达到数百MB崩溃应用程序。
ToolStripItems
还会加载其他内容,例如属性和图标,但它似乎是使用大部分添加内存的事件处理程序。我评论了所有的处理程序,每次刷新后,内存变得更加可靠(但并非完全)。
是否有必要枚举所有菜单和子菜单,并单独释放每个事件处理程序以确保它不会粘在一起?
答案 0 :(得分:1)
如果你处理/删除事件处理程序和它订阅的对象,你应该没问题。否则,是的,你必须取消订阅每个处理程序。
或者看一下不同的订阅方式 - 不是编译器生成的事件。有关示例,请参阅http://paulstovell.com/blog/weakevents
答案 1 :(得分:0)
检查菜单条的ItemRemoved
事件。它将返回一个从菜单条中删除的项目。你可以在这里处理它,或者你可以从这里删除每个处理程序。
<强>已更新强>
获得父菜单后,可以使用递归函数调用删除所有子菜单的事件处理程序。
private void menuStrip1_ItemRemoved(object sender, ToolStripItemEventArgs e)
{
foreach (object child in ((ToolStripMenuItem)e.Item).DropDownItems)
{
if (child.GetType().Name == "ToolStripMenuItem")
RemoveHandler((ToolStripMenuItem)child);
}
}
private void RemoveHandler(ToolStripMenuItem item)
{
if (item.HasDropDownItems)
{
foreach (Object dropdown in item.DropDownItems)
{
if (dropdown.GetType().Name == "ToolStripMenuItem")
RemoveHandler((ToolStripMenuItem)dropdown);
}
}
else
{
//item.Click -= new EventHandler(MenuItem_Clicked);
//Remove event handlers
}
}
答案 2 :(得分:0)
我经常使用的一个技巧是创建一个private _cleanUp = New List<Action>()
类级变量,并使用它来清理事件处理程序。
因此,当我附加事件处理程序时,我还将分离代码添加到列表中,如下所示:
this.NameTextbox.Click += My_Handler;
_cleanUp.Add(() => this.NameTextbox.Click -= My_Handler);
然后在清理时,对于你的代码,我可以这样做:
_cleanUp.ForEach(a => a());
_cleanUp.Clear();
menuStrip1.Items.Clear();
然后我不必记得确切添加的内容。我可以将任何清理代码添加到列表中。