我在窗体上的控件上有很多内容,并且有特定的时间想要暂时停止所有事件的处理。通常,如果我不想处理某些事件,我只会做这样的事情:
private bool myOpRunning = false;
private void OpFunction()
{
myOpRunning = true;
// do stuff
myOpRunning = false;
}
private void someHandler(object sender, EventArgs e)
{
if (myOpRunning) return;
// otherwise, do things
}
但是我有很多需要更新的处理程序。很好奇.NET是否具有比必须更新每个处理程序方法更快的方法。
最佳答案
您将必须创建自己的机制来执行此操作。不过还算不错。考虑添加另一层抽象。例如,一个名为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;
当
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程序中。