Ben*_*est 3 .net c# events winforms
我对表单上的控件有很多,并且有一个特定的时间我想暂停所有事件的处理.通常我只是做这样的事情,如果我不想处理某些事件:
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
}
Run Code Online (Sandbox Code Playgroud)
但我有很多需要更新的处理程序.只是好奇.NET是否比更新每个处理程序方法更快.
您必须创建自己的机制才能执行此操作.但这并不算太糟糕.考虑添加另一层抽象.例如,一个名为FilteredEventHandlermyOpRunning的状态的简单类调用真实事件处理程序,或者抑制事件.该类看起来像这样:
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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后当你挂钩事件时,执行以下操作:
this.Control.WhateverEvent += new FilteredEventHandler(() => myOpRunning, RealEventHandler).FakeEventHandler;
Run Code Online (Sandbox Code Playgroud)
当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!
Run Code Online (Sandbox Code Playgroud)
因为你正在联系一名代表并解开一个完全不同的代表!当然,两个委托都是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;
Run Code Online (Sandbox Code Playgroud)
在这种情况下,我要做的是让FilteredEventHandler.FakeEventHandler方法将其"this"引用传递给RealEventHandler.这涉及将RealEventHandler的签名更改为另一个参数:
public void RealEventHandler(object sender, EventArgs e, FilteredEventHandler filter);
Run Code Online (Sandbox Code Playgroud)
或者更改它以获取您创建的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
Run Code Online (Sandbox Code Playgroud)
现在,被调用的RealEventHandler可以取消订阅,因为它引用了传递给其参数的正确FilteredEventHandler对象.
我最后的建议是不要做任何这个! Neolisk在评论中钉了它.做这样复杂的事情表明设计存在问题.对于任何需要在未来维护此代码的人(即使您,令人惊讶!)来说,要弄清楚所涉及的非标准管道将是困难的.
通常,当您订阅事件时,您只需执行一次并忘记它 - 尤其是在GUI程序中.