2009-07-19 72 views
5

问题:我有一个包含对象列表的文档类。这些对象会引发诸如SolutionExpired,DisplayExpired等事件。文档需要对此作出响应。一次移除所有事件处理程序

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

我的文档类包含一堆用作事件处理程序的方法。无论何时一个物体进入文档,我使用AddHandler来设置事件,并且每当从文档中移除一个物体时,我使用RemoveHandler来解除损坏。但是,有些情况下很难确保所有的步骤都被正确地采用,并且因此我最终可能会成为流氓事件处理程序。

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

喜欢的东西:

RemoveHandler *.SolutionExpired, AddressOf DefObj_SolutionExpired 
+0

可能的重复[如何从控件中删除所有事件处理程序](http://stackoverflow.com/questions/91778/how-to-remove-all-event-handlers-from-a-control) – ChrisF 2012-03-03 19:02:28

+0

可能重复[如何从控件中删除所有事件处理程序](https://stackoverflow.com/questions/91778/how-to-remove-all-event-handlers-from-a-control) – 2017-09-26 13:49:18

回答

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
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:道歉对我的误会 - 我看你是如何不让访问事件源在你原来的职位相当清楚。

我能想到解决这个问题最简单的方法涉及实现一个对象到文档绑定的共享字典。当一个对象进入文档时,检查字典是否存在与另一个文档的绑定;如果存在,请在添加新文档之前删除引用旧文档的处理程序。无论哪种方式,用新的绑定更新字典。

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

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

这些看起来像你可能已经拒绝的那种想法 - 但也许不是!

+0

本,感谢发布这个。恐怕对我来说(或者VB编译器)没什么意义。你可以请张贴原始的C#吗? – 2009-07-19 17:40:12

+1

我知道我应该离开原来的C#版本。 :-) – 2009-07-19 19:49:55