停止在winform按钮上执行的功能单击

时间:2008-11-03 19:37:58

标签: c# winforms multithreading

  1. 在一个简单的winform应用程序中,我调用了一个在按钮单击事件上无休止地创建文件的函数。我将Application.DoEvents()添加到循环中。

  2. 我按红色X关闭表格。

  3. 表单关闭,但文件仍在继续创建......

  4. 我认为它在按钮线程上,但不应该是背景线程吗?尝试在循环函数上将Thread.CurrentThread.IsBackGround更改为True无济于事。

    想法?

5 个答案:

答案 0 :(得分:5)

您使用Application.DoEvents这一事实是问题的第一个迹象:它表明您在UI线程中做得太多了。它几乎不适合结构良好的程序。 UI线程并不意味着任何长时间运行的任务。 (不可否认,如果绘制你的UI需要很长时间,你几乎没有选择 - 但这表明你应该简化你的用户界面...而且我怀疑它并不适用于这种情况。)

相反,您应该在单独的线程中执行长时间运行的任务(创建文件)。 BackgroundWorker非常适合这种情况 - 您可以使用它将进度报告回UI,并且UI可以调用CancelAsync方法来请求它停止。您需要检查工作线程中的CancellationPending属性,以查看是否已请求取消,并正确停止。

编辑:只是为了澄清我认为发生了什么 - 我怀疑你的表格正在关闭,但程序将不会终止,直到事件循环结束。你保持事件循环与文件创建循环一致,因此问题。

请注意,按钮没有线程 - 只有一个用于整个UI。 (在某些情况下,您可能需要多个UI线程,但这种情况很少见 - 如果您已经完成它,您就会知道它。)

答案 1 :(得分:2)

将此表单级变量添加到表单的代码中:

private bool _StillOpen = true;

然后将无限循环代码包装在按钮中,如下所示:

while (_StillOpen)
{
    // do whatever your method does
    Application.DoEvents();
}

最后,将此代码添加到表单的FormClosing事件中:

_StillOpen = false;

这将允许您在单击关闭按钮时关闭表单。理想情况下,您希望在后台线程上执行此类操作,但此标记方法可能是您当前问题的快速解决方法。

答案 2 :(得分:1)

在UI线程上执行按钮单击处理程序。

当您调用Application.DoEvents时,您将让UI线程处理窗口消息。这样做的一个结果是,每次用户单击该按钮时,单击处理程序方法的新“实例”(堆栈框架)以及许多其他堆栈框架都会添加到堆栈中。像这样:

{windows forms methods incl. message pump}
  **ClickHandler**
    Application.DoEvents
     {windows forms methods incl. message pump}
      **ClickHandler**
       Application.DoEvents
        {windows forms methods incl. message pump}
          etc.

这一切都非常可怕。

如果您想在后台运行代码,可以使用更好的替代方法

  • BackgroundWorker组件。
  • 用于在线程池中运行代码的标准.NET委托机制(BeginInvoke,EndInvoke,IAsyncResult等)。
  • 如果你想实现一个长时间运行的后台线程,而不是将“工作块”放到池中,你可以创建并启动一个线程,它被设置为后台线程。

答案 3 :(得分:0)

您是否为该ButtonClick代码专门创建了一个新线程?如果没有,那么它与表单在同一个线程上,因此“X”按钮应该停止它。

在任何一种情况下,您都可以设置一个标志(isClosing),并在“while true”循环中检查该标志。

答案 4 :(得分:0)

您是否尝试拨打Thread.CurrentThread.Abort()? 这不是推荐的方法,但如果您无法从函数中访问函数s source code it might help (even though you say you are calling DoEvents`。

如果您确实可以访问源代码,那么您可以在那里进行检查,让循环知道它必须停止。

此外,您可以使用background worker组件,或创建不同的线程,并从外部(即从表单)控制它