Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/326.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#_Winforms_Event Handling - Fatal编程技术网

C# 在事件句柄完成第一次调用之前,如何防止任何按钮单击事件排队

C# 在事件句柄完成第一次调用之前,如何防止任何按钮单击事件排队,c#,winforms,event-handling,C#,Winforms,Event Handling,我想防止按钮点击排队。在测试中,我有一个表单、一个按钮,在代码中,我有一个事件处理程序: private void button1_Click(object sender, EventArgs e) { if (_codeRunning) return; _codeRunning = true; //Application.DoEvents(); //button1.Enabled =

我想防止按钮点击排队。在测试中,我有一个表单、一个按钮,在代码中,我有一个事件处理程序:

    private void button1_Click(object sender, EventArgs e)
    {
        if (_codeRunning)
            return;

        _codeRunning = true;

        //Application.DoEvents();

        //button1.Enabled = false;

        _click ++;

        Debug.WriteLine("Click Number: " + _click);

        Task.Delay(5000).Wait();

        //button1.Enabled = true;

        _codeRunning = false;
    }
当我运行debug并快速单击按钮两次、三次或四次时,debug输出会在最后一次单击后大约五秒钟显示每次单击。我希望它显示的是一次单击并删除其余部分,直到第一个事件完成


我还尝试禁用按钮,以及从按钮单击事件中临时删除处理程序。结果都是一样的。

当你像这样挂断UI线程时,你会遇到各种各样的麻烦。这当然是其中之一,当用户疯狂地敲打按钮试图让一些明显的事情发生时,没有什么令人愉快的事情发生。当然,这些点击不会丢失,它们存储在消息队列中。要激活事件处理程序,请在事件处理程序停止运行时再次单击事件处理程序

了解如何使用BackgroundWorker或Task类来避免此类问题非常重要。仅设置按钮的Enabled属性就足以解决此问题

从技术上讲,清除消息队列中的鼠标单击是可行的。但做起来很难看,需要品沃克。我会犹豫不决地发布替代方案,不要认为这是一个好策略。您需要阅读一些文章来了解为什么DoEvents()是一个危险的方法

    private void button1_Click(object sender, EventArgs e) {
        button1.Enabled = false;
        button1.Update();
        '' long running code
        ''...
        Application.DoEvents();
        if (!button1.IsDisposed) button1.Enabled = true;
    }
Update()调用确保用户得到反馈,他需要知道反复敲打按钮不会有任何用处。DoEvents()调用将调度所有排队的鼠标单击,由于按钮仍然处于禁用状态,因此不会发生任何操作。IsDisposed测试对于解决DoEvents()的问题至关重要,它可以确保在代码运行时,当用户单击窗口的关闭按钮时,程序不会崩溃


使用中的沙漏类提供更多反馈。

我有一个按钮,单击事件将运行一个方法。同样的问题也发生了,当用户多次单击时,该方法被多次触发。因此,我创建了一个布尔值,并在方法启动时更改了它的值

private bool IsTaskRunning = false;

private void MyMethod()
{
    if ( IsTaskRunning==false )
    {
        IsTaskRunning=true;

        // My heavy duty code that takes a long time

        IsTaskRunning=false; // When method is finished
    }
}

因此,现在该方法只有在上次完成时才运行。

您正在使用5秒的延迟来绑定UI线程,因此在代码完成之前,它不会将任何进一步的窗口消息出列。您需要将缓慢的代码移入(比如)后台工作程序,然后设法知道是否有一个正在进行中。这种行为发生的原因是windows将消息循环中的所有单击排队。你的主线程无法删除它们,因为他等待了5秒。也许你可以将你的局部变量_coderrunning设置为true(你已经设置了),然后启动一个新的线程来执行所有其他的工作,包括将_coderrunning设置为false。如果这样做,主线程可以删除所有单击消息(是的,它也会调用事件处理程序,但是如果代码正在运行,并且什么也不会发生,则返回)。也许你必须声明你的代码运行是不稳定的。@Damien\u不信者Deam 9秒太慢了…:-(优雅且有效!这个好的欺骗怎么可能不比公认的答案好?这不如公认的答案好,因为按钮仍然处于启用状态,因此从UI的角度来看,用户可能认为他们一直按下按钮,它会做一些事情,但事实并非如此。禁用按钮可能更可取。