一次性删除所有事件处理程序

时间:2009-07-19 16:23:04

标签: vb.net events

问题:我有一个包含对象列表的文档类。这些对象会引发SolutionExpiredDisplayExpired等事件。文档需要对此做出响应。

文档有时可以交换对象,但单个对象永远不应该是多个文档的“一部分”。

我的文档类包含许多用作事件处理程序的方法。每当对象进入文档时,我使用AddHandler来设置事件,每当从文档中删除对象时,我使用RemoveHandler来撤消损坏。但是,有些情况下很难确保所有步骤都得到适当的处理,因此我最终可能会遇到流氓事件处理程序。

长话短说;如何删除指向特定方法的所有处理程序?请注意,我没有可能的事件源列表,这些可以存储在任何地方。

类似的东西:

RemoveHandler *.SolutionExpired, AddressOf DefObj_SolutionExpired

3 个答案:

答案 0 :(得分:5)

您可以使用Delegate.RemoveAll()。 (您感兴趣的部分位于button2_Click

public void Form_Load(object sender, EventArgs e) 
{ 
    button1.Click += new EventHandler(button1_Click);
    button1.Click += new EventHandler(button1_Click);
    button2.Click += new EventHandler(button2_Click);
    TestEvent += new EventHandler(Form_TestEvent);
}
event EventHandler TestEvent;
void OnTestEvent(EventArgs e)
{
    if (TestEvent != null)
        TestEvent(this, e);
}
void Form_TestEvent(object sender, EventArgs e)
{
    MessageBox.Show("TestEvent fired");
}
void button2_Click(object sender, EventArgs e)
{
    Delegate d = TestEvent as Delegate;
    TestEvent = Delegate.RemoveAll(d, d) as EventHandler;
}
void button1_Click(object sender, EventArgs e)
{
    OnTestEvent(EventArgs.Empty);
}

您应该注意,它不会改变您传递给它的代理的内容,它会返回一个更改的委托。因此,您无法更改表单上已删除的按钮上的事件,因为button1.Click只能使用+=-=,不是=。这不会编译:

button1.Click = Delegate.RemoveAll(d, d) as EventHandler;

此外,请确保无论您在何处实施此项目,都要注意竞争条件的可能性。如果你要从另一个线程调用的事件中删除处理程序,你可能会遇到一些非常奇怪的行为!

答案 1 :(得分:1)

public class TheAnswer
{
    public event EventHandler MyEvent = delegate { };

    public void RemoveFromMyEvent(string methodName)
    {
        foreach (var handler in MyEvent.GetInvocationList())
        {
            if (handler.Method.Name == methodName)
            {
                MyEvent -= (EventHandler)handler;
            }
        }
    }
}

编辑2:对我的误解表示歉意 - 我发现您很清楚无法访问原始帖子中的事件来源。

我能想到解决此问题的最简单方法是实现对象到文档绑定的共享字典。当对象进入文档时,检查字典以查找到另一个文档的现有绑定;如果存在,删除引用旧文档的处理程序,然后再为新文档添加它们。无论哪种方式,使用新绑定更新字典。

我认为在大多数情况下,性能和内存影响可以忽略不计:除非您处理成千上万的小对象并经常在文档之间进行交换,否则每个键/值对的内存开销和性能都会受到影响每个查找操作都应该相当小。

作为替代方法:如果您可以检测(在文档事件处理程序中)事件的发件人不再与文档相关,则可以在那里分离事件。

这些似乎是你可能已经拒绝的那种想法 - 但也许不是!

答案 2 :(得分:1)

使用Delegate.RemoveAll(如果Delegate实例是私有的,可以使用反射)。