在WinForms应用程序中处理用户双击按钮的最佳方法是什么?

4
我正在开发一个WinForms应用程序,其中包含一个用户控件,用户控件中的按钮会触发事件并由其他代码处理。其中一个按钮启动了一些进程,如果它们同时运行将会导致问题。我已经在代码中添加了逻辑来管理状态,通常情况下,如果该进程已经在运行,用户无法再次运行该过程。但是,如果用户双击该按钮,它会快速启动两次进程,我很难防止这种情况发生。
我想知道,最好的解决方法是什么?
我最开始尝试在单击事件中禁用按钮,但第二次单击在第一次单击导致按钮被禁用之前就到达了。在代码中设置其他标志也没有解决这个问题。
我正在考虑在引发事件的代码上添加某种同步锁,但我想知道是否有更好的想法。
由于这个项目大部分已经完成,所以我寻找那些不涉及彻底重写应用程序(例如实施组合应用程序块)的答案,但如果您有这样的想法,请随时发布它们,因为在我的下一个项目中我可以使用它们。
8个回答

5

确保在事件处理程序中禁用按钮或进行任何其他锁定是您要做的/第一件事情。我会非常惊讶,如果您能在第一条指令之前排队两个单击事件,但我认为如果您使用的是非常缓慢且被其他应用程序拖垮的计算机,则这是可能的。

在这种情况下,请使用标志。

private bool runningExclusiveProcess = false;

public void onClickHandler(object sender, EventArgs e)
{
    if (!runningExclusiveProcess)
    {
        runningExclusiveProcess = true;
        myButton.Enabled = false;

        // Do super secret stuff here

        // If your task is synchronous, then undo your flag here:
        runningExclusiveProcess = false;
        myButton.Enabled = true;
    }
}

// Otherwise, if your task is asynchronous with a callback, then undo your flag here:
public void taskCompletedCallback()
{
    runningExclusiveProcess = false;
    myButton.Enabled = true;
}

如果您仍然可以通过类似的方式在两个点击内完成某项操作,请确保您没有意外订阅了双击事件,或者其他奇怪的事情正在发生。


2
如果您的任务是同步的,那么这就没有意义。双击中的第二次点击将在事件队列中等待,直到第一次点击退出。因此,如果您取消了标志,则第二次点击也会愉快地开始进程。 - rein
1
这个解决方案似乎不起作用。即使使用这个代码示例,我仍然可以快速点击按钮5次,它会处理5次。 - tzup
@tzup:这段代码不能防止用户多次点击。它只能在多线程环境中防止处理代码(即“超级机密内容”)同时执行超过一次。 - HanClinto
1
@tzup:只要它们轮流执行,一个接一个地执行,处理程序就可以愉快地执行多次。 - HanClinto

3

你是否处理了两次事件?

我非常惊讶地看到在你禁用按钮之前第二次点击已经发生。我建议检查一下是否重复连接了事件。我之前也曾经不小心这样做过,那么你就会几乎同时收到两个事件。


我也是无意中这样做的...花了一段时间才弄清楚为什么我的事件会触发两次..然后我自嘲地笑了。 - Jason Lautzenheiser
我想这种情况发生在我们所有人身上过。该死的自动事件布线! - John MacIntyre

2
那个按钮上的禁用标志只有在按钮事件处理程序完成后才会设置,任何额外的点击都将排队在第一个点击后面的Windows消息队列中。确保按钮事件处理程序快速完成以释放UI线程。有几种方法可以做到这一点,但所有方法都涉及要么生成一个线程,要么保持工作线程准备好并等待AutoResetEvent。

0

这个已经被确认的答案在某种程度上是正确的,但更像是一个轶事。对于未接触过编程的人来说,它缺少了太多代码,难以理解。我写了一篇关于如何使用计时器和线程的文章,其中的代码示例非常容易理解。试着阅读一下,并尝试通过在新线程中运行你的任务进程来设置上述示例中的标志:

http://www.robault.com/category/Threading.aspx


0

你有没有给按钮加上图标?当然,使用代码来防止同时运行两个进程是可以的,但是如果你的按钮看起来和表现得像一个传统的命令按钮(矩形,只有文本标签,“凸起”的表面在点击时会压下去),那么你就可以减少人为双击的情况。这只是一个想法。


0

一旦按钮被点击,立即禁用它。这样,事件就不会被处理两次。一旦事件被处理完毕,您可以重新启用按钮。


-1

在用户第一次点击按钮之后和任务开始之前禁用该按钮。当任务完成后,重新启用该按钮。


-3
我开始通过在单击事件中禁用按钮来解决问题,但第二次单击在第一次单击导致按钮被禁用之前就到来了。在代码中设置其他标志也没有捕获它。
鉴于WinForms本质上是单线程的,除非您使用新线程或BackgroundWorkers等,否则不可能在第一个处理完成之前触发第二个单击。
您能展示一个说明您问题的示例吗?

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接