4

我正在开发一个 WinForms 应用程序,其中有一个用户控件。用户控件中的按钮将事件引发到要由其他代码处理的表单。其中一个按钮启动一些进程,如果它们同时运行会导致问题。我在代码中有管理状态的逻辑,因此如果进程已经在运行,用户通常无法运行该进程。但是,如果用户双击该按钮,它将以如此快的速度启动该过程两次,以至于我很难阻止它。

我想知道,处理这个问题的最佳方法是什么?

我首先在单击事件中禁用按钮,但在第一次单击之前第二次单击会导致按钮被禁用。在代码中设置其他标志也没有捕捉到它。

我正在考虑在引发事件的代码上添加某种同步锁,但我想知道你们是否有更好的主意。

由于这个项目大部分已经完成,我正在寻找不涉及彻底重写应用程序(如实现复合应用程序块)的答案,但是,也可以随意发布这些想法,因为我可以在我的下一个项目中使用它们.

4

8 回答 8

5

确保您的按钮禁用或您所做的任何其他锁定是您在事件处理程序中所做的 /first/ 事情。如果您甚至可以在第一条指令触发之前将两个点击事件排队,我会感到非常惊讶,但我想如果您使用的是一台非常慢且被其他应用程序困住的计算机,这是可能的。

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

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

如果您仍然可以通过两次点击来完成类似的操作,那么请确保您没有意外订阅了 doubleClick 事件,或者发生了其他任何奇怪的事情。

于 2008-10-31T22:28:41.953 回答
3

您是否两次处理该事件?

在您禁用按钮之前,我惊讶地看到第二次点击即将到来。我希望确保您不会两次连接该活动。我以前偶然这样做过。然后,您将几乎立即获得两个事件。

于 2008-11-01T00:17:32.060 回答
2

在按钮事件处理程序完成之前,不会设置该按钮上的禁用标志,并且任何额外的点击都将在第一次点击之后的 Windows 消息队列中排队。确保按钮事件处理程序快速完成以释放 UI 线程。有几种方法可以做到这一点,但都涉及生成线程或保持工作线程准备就绪并等待 AutoResetEvent。

于 2008-10-31T22:23:49.437 回答
0

无论如何,您是否用图标标记按钮?一定要使用代码来防止同时运行两个进程,但是如果您的按钮看起来和操作起来像传统的命令按钮(矩形,仅文本标签,“凸起”的表面,按下点击)。只是一个想法。

于 2008-11-03T12:27:05.677 回答
0

单击后立即禁用该按钮。因此,该事件不能被处理两次。处理完事件后,您可以重新启用该按钮。

于 2008-11-04T12:09:46.413 回答
0

检查的答案很接近,如果充其量是轶事。对于没有经验的人来说,它缺少太多没有意义的代码。我写了一篇关于使用定时器和线程的文章,代码示例非常容易理解。尝试通读它并查看是否可以通过在新线程中运行任务进程来设置上面示例中的标志:

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

于 2009-06-28T20:11:28.800 回答
-1

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

于 2008-10-31T22:18:02.927 回答
-4

我首先在单击事件中禁用按钮,但在第一次单击之前第二次单击会导致按钮被禁用。在代码中设置其他标志也没有捕捉到它。

鉴于 WinForms 本质上是单线程的,在第一次处理完成之前应该不可能触发第二次单击(除非您使用新线程或 BackgroundWorkers 等)。

你能给我们看一个例子来说明你的问题吗?

于 2008-11-04T12:15:13.327 回答