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

How do I prevent any button click events from queuing until the event handle is finished with the first call

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

    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;
    }

当我 运行 调试并快速单击按钮两次或三四次时,调试输出会在上一次单击后大约五秒显示每次单击。我希望它显示的是单击并放下其余部分,直到第一个事件完成。

我还尝试禁用该按钮,并暂时从 Button_click 事件中删除处理程序。都是一样的结果。

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

学习如何使用 BackgroundWorker 或 Task classes 来避免此类麻烦非常重要。只需将按钮设置为 Enabled 属性 即可解决此问题。

从消息队列中清除鼠标点击在技术上是可行的。但是做起来很难看,它需要 pinvoke。我会犹豫 post 替代方案,不要认为这通常是一个好的策略。您需要阅读 this post 才能深入了解为什么 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() 问题至关重要,它确保当用户在代码为 运行.[=13= 时单击 window 的关闭按钮时您的程序不会崩溃]

使用 this post 中的沙漏 class 提供更多反馈。

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

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
    }
}

所以现在方法 运行 只有在上次完成时才有效。