我在窗体上的控件上有很多内容,并且有特定的时间想要暂时停止所有事件的处理。通常,如果我不想处理某些事件,我只会做这样的事情:

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程序中。

10-04 10:28