您必须创建自己的机制来做到这一点。不过,这还不算太糟糕。考虑添加另一层抽象。例如,一个简单的类称为FilteredEventHandler
检查 myOpRunning 的状态并调用真实的事件处理程序或抑制该事件。该类看起来像这样:
public sealed class FilteredEventHandler
{
private readonly Func<bool> supressEvent;
private readonly EventHandler realEvent;
public FilteredEventHandler(Func<bool> supressEvent, EventHandler eventToRaise)
{
this.supressEvent = supressEvent;
this.realEvent = eventToRaise;
}
//Checks the "supress" flag and either call the real event handler, or skip it
public void FakeEventHandler(object sender, EventArgs e)
{
if (!this.supressEvent())
{
this.realEvent(sender, e);
}
}
}
然后,当您连接该事件时,请执行以下操作:
this.Control.WhateverEvent += new FilteredEventHandler(() => myOpRunning, RealEventHandler).FakeEventHandler;
When WhateverEvent
被提出,它会调用FilteredEventHandler.FakeEventHandler method
。该方法将检查标志并调用或不调用真正的事件处理程序。这在逻辑上与您已经在做的事情几乎相同,但是检查 myOpRunning 标志的代码仅位于一个位置,而不是散布在整个代码中。
编辑回答评论中的问题:
现在,这个例子有点不完整。完全取消订阅事件有点困难,因为您丢失了对已连接的 FilteredEventHandler 的引用。例如,你不能这样做:
this.Control.WhateverEvent += new FilteredEventHandler(() => myOpRunning, RealEventHandler).FakeEventHandler;
//Some other stuff. . .
this.Control.WhateverEvent -= new FilteredEventHandler(() => myOpRunning, RealEventHandler).FakeEventHandler; //Not gonna work!
因为您正在连接一名代表并取消另一名完全不同的代表!当然,两个委托都是 FakeEventHandler 方法,但那是一个实例方法,并且它们属于两个完全不同的 FilteredEventHandler 对象。
不知何故,您需要获取对您构造的第一个 FilteredEventHandler 的引用才能取消挂钩。像这样的东西是可行的,但它涉及跟踪一堆 FilteredEventHandler 对象,这可能并不比您试图解决的原始问题好:
FilteredEventHandler filter1 = new FilteredEventHandler(() => myOpRunning, RealEventHandler);
this.Control.WhateverEvent += filter1.FakeEventHandler;
//Code that does other stuff. . .
this.Control.WhateverEvent -= filter1.FakeEventHandler;
在这种情况下,我要做的就是让 FilteredEventHandler.FakeEventHandler 方法将其“this”引用传递给 RealEventHandler。这涉及更改 RealEventHandler 的签名以采用另一个参数:
public void RealEventHandler(object sender, EventArgs e, FilteredEventHandler filter);
或者将其更改为采用您创建的 EventArgs 子类,该子类保存对 FilteredEventHandler 的引用。这是更好的方法
public void RealEventHandler(object sender, FilteredEventArgs e);
//Also change the signature of the FilteredEventHandler constructor:
public FilteredEventHandler(Func<bool> supressEvent, EventHandler<FilteredEventArgs> eventToRaise)
{
//. . .
}
//Finally, change the FakeEventHandler method to call the real event and pass a reference to itself
this.realEvent(sender, new FilteredEventArgs(e, this)); //Pass the original event args + a reference to this specific FilteredEventHandler
现在,被调用的 RealEventHandler 可以自行取消订阅,因为它具有对传递到其参数的正确 FilteredEventHandler 对象的引用。
不过,我最后的建议是不要做任何这样的事!Neolisk 在评论中指出了这一点。做这样复杂的事情就表明设计有问题。对于将来需要维护此代码的任何人(甚至是您,令人惊讶!)来说,都很难弄清楚所涉及的非标准管道。
通常,当您订阅事件时,您只执行一次,然后就忘记了 - 尤其是在 GUI 程序中。