释放动态创建的项目的事件处理程序

时间:2014-02-19 01:55:54

标签: c# winforms memory-leaks toolstripmenu

我正在使用ToolStripMenu文件中的条目填充XML。添加到菜单中的每个ToolStripItem会自动获取分配给它的十几个事件处理程序。用户可以选择更改XML并刷新菜单,使用以下命令清除所有内容:

menuStrip1.Items.Clear();

XML重新填充并刷新表单。似乎所有这些动态项的事件处理程序永远不会从内存中删除。大多数项目不直接位于menuStrip1上,而是位于menuStrip1上的动态创建的子菜单中。

尽管如此,我可以坐在那里刷新表单和内存只是气球失控,每次刷新大约5-10 MB时添加100 dynamic ToolStripItems.它可以快速达到数百MB崩溃应用程序。

ToolStripItems还会加载其他内容,例如属性和图标,但它似乎是使用大部分添加内存的事件处理程序。我评论了所有的处理程序,每次刷新后,内存变得更加可靠(但并非完全)。

是否有必要枚举所有菜单和子菜单,并单独释放每个事件处理程序以确保它不会粘在一起?

3 个答案:

答案 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();

然后我不必记得确切添加的内容。我可以将任何清理代码添加到列表中。