Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/261.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sql-server-2005/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 是否暂时停止引发或处理窗体事件?_C#_.net_Winforms_Events - Fatal编程技术网

C# 是否暂时停止引发或处理窗体事件?

C# 是否暂时停止引发或处理窗体事件?,c#,.net,winforms,events,C#,.net,Winforms,Events,我在表单上有很多控件,并且有一个特定的时间我想暂时停止处理我的所有事件。如果我不想处理某些事件,通常我会这样做: private bool myOpRunning = false; private void OpFunction() { myOpRunning = true; // do stuff myOpRunning = false; } private void someHandler(object sender, EventArgs e) { if

我在表单上有很多控件,并且有一个特定的时间我想暂时停止处理我的所有事件。如果我不想处理某些事件,通常我会这样做:

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是否有比更新每个处理程序方法更快的方法。

您可以通过反射来完成

public static void UnregisterAllEvents(object objectWithEvents)
{
    Type theType = objectWithEvents.GetType();

    //Even though the events are public, the FieldInfo associated with them is private
    foreach (System.Reflection.FieldInfo field in theType.GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance))
    {
        //eventInfo will be null if this is a normal field and not an event.
        System.Reflection.EventInfo eventInfo = theType.GetEvent(field.Name);
        if (eventInfo != null)
        {
            MulticastDelegate multicastDelegate = field.GetValue(objectWithEvents) as MulticastDelegate;
            if (multicastDelegate != null)
            {
                foreach (Delegate _delegate in multicastDelegate.GetInvocationList())
                {
                    eventInfo.RemoveEventHandler(objectWithEvents, _delegate);
                }
            }
        }
    }
}

为此,您必须创建自己的机制。不过也不算太糟。考虑添加另一层抽象。例如,一个名为
filteredventhandler
的简单类检查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);
        }
    }
}
当引发
WhateverEvent
时,它将调用
FilteredEventHandler.FakeEventHandler方法
。该方法将检查标志并调用或不调用真正的事件处理程序。这在逻辑上与您已经在做的几乎相同,但是检查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);
或者将其更改为获取您创建的包含对FilteredEventHandler的引用的EventArgs子类。这是更好的方法

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
public void RealEventHandler(对象发送方,filteredventargs e);
//还要更改FilteredEventHandler构造函数的签名:
公共筛选器事件处理程序(Func SupersEvent、EventHandler eventToRaise)
{
//. . .
}
//最后,更改FakeEventHandler方法以调用真实事件并将引用传递给自身
this.realEvent(发送方,新的filteredventargs(e,this))//将原始事件参数+引用传递给此特定的FilteredEventHandler
现在,被调用的RealEventHandler可以取消订阅自己,因为它引用了传递到其参数中的正确FilteredEventHandler对象

不过,我最后的建议是不要这样做!Neolisk在评论中提到了这一点。做这样复杂的事情表明设计有问题。对于将来需要维护此代码的任何人(令人惊讶的是,即使是您)来说,要找出所涉及的非标准管道是很困难的


通常,当您订阅事件时,您只需执行一次就可以忘记它—尤其是在GUI程序中。

您可以禁用所有这些控件所在的容器。例如,如果将它们放在
GroupBox
Panel
中,只需使用:
GroupBox.Enabled=false
panel.Enabled=false。您还可以禁用表单
From1.Enabled=false并显示等待光标。您仍然可以将这些控件复制并粘贴到表单以外的容器中。

禁用您的控件,以便用户知道您没有响应。将它们的Enabled属性设置为false。如果您必须处理过多的事件触发,我将首先考虑重新设计。代码中的错误位置发生了某些事情。你不应该那样。在解决问题的真正原因之前,执行这种管道应该只是一种临时措施。我唯一明确取消钩住事件的时间是eventhandler将执行可能再次引发相同事件的操作。GUI是我90%时间处理事件的地方现在如果我像这样删除处理程序:myControl.SomeEvent-=new FilteredEventHandler(),那么在FilteredEventHandler的终结器中删除RealEventHandler是否有效?我没有编写自己的事件的丰富经验,因此我不知道这会有什么影响,或者如果EventHandler是以与.NET中其他类型相同的方式最终确定的(我假设是)@AlexanderMiles,我已经更新了我的原始答案以解决这个特定问题。第二个你提到的通过特殊处理程序过滤事件,我觉得这是个坏主意。我对信息更感兴趣,现在我知道我需要找到一种更好的方法来创建事件驱动的GUI。这在我看来不是很“暂时”。
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