WinForm和循环

时间:2010-05-26 19:26:59

标签: c# winforms loops

我有一个WinForm设置和一个循环的过程,直到在窗体上按下按钮。

当我尝试运行我的代码时,表单甚至都没有显示。我怀疑这是因为代码卡在循环中并且不足以显示WinForm。如何在该点之后显示要显示的表单和循环?

7 个答案:

答案 0 :(得分:4)

如果您正在循环,因为您需要在等待输入时定期对GUI执行某些操作,我建议您使用Timer control及其Tick event

如果你想在等待时做非GUI事情,more traditional timer更适合这项任务,

答案 1 :(得分:2)

你应该在后台线程中运行循环。 BackgroundWorker类使这很容易做到。

答案 2 :(得分:1)

您的表单加载冻结,因为Windows窗体的UI在单个线程中运行。您在此线程的Load事件上放置的逻辑正在该线程上运行。

您可以使用Windows窗体上的BackgroundWorker component轻松地在单独的线程上运行循环。在后台工作程序的事件DoWork上,放置具有应该运行的循环的代码,而不阻止您的UI。在Form.Load事件上,您可以通过调用方法RunWorkerAsync来启动后台工作程序组件。在按钮的事件处理程序上,您可以通过调用CancelAsync method来放置代码来停止后台工作程序。

文章How to: Implement a Form That Uses a Background Operation详细说明了如何完成它。


关于无法从后台工作程序组件更新TextBox文本的注释。这是因为不允许从不同的线程修改Windows窗体控件的状态(后台工作程序代码在一个单独的线程上运行)MSDN文档说:

  

对Windows窗体控件的访问本质上不是线程安全的。如果有两个或多个线程操纵控件的状态,则可以强制控件进入不一致状态。其他与线程相关的错误也是可能的,例如竞争条件和死锁。确保以线程安全的方式访问控件非常重要。

如何从后台线程更新Windows窗体控件的状态示例将类似于下面的示例(假设新值已存储在名为text的String变量中):

// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.textBox1.InvokeRequired)
{   
  SetTextCallback d = new SetTextCallback(SetText);
  this.Invoke(d, new object[] { text });
}
else
{
  this.textBox1.Text = text;
}

我从How to: Make Thread-Safe Calls to Windows Forms Controls文章中借用了这段代码。它可以为您提供有关如何处理多线程窗体的更多信息。

答案 3 :(得分:1)

不要那样做。

Windows Forms(与大多数现代用户界面开发工具包一样)是事件驱动的框架。你永远不应该使用一个“等待”某事发生的循环;相反,你想使用一个触发某事的事件

基本上发生的事情是:WinForms有一个运行消息泵的循环,它监听来自Windows的事件并触发C#事件以响应它们。您的代码在与消息泵相同的线程上执行(必须这样,因为在WinForms中只允许一个线程触及任何给定的控件)。因此,如果您将该线程放入循环中,那么应该抽取消息的WinForms代码不会,并且您的用户界面似乎挂起,因为它没有响应来自Windows的任何消息。 (如果你一直点击它,你将填满消息队列并得到一个对话框,上面写着“这个应用程序已经停止响应,你想终止吗?”或类似的东西。)

正确的解决方案是执行以下操作之一:

另一种可行的解决方案,但不是一个好主意:

答案 4 :(得分:0)

您可以使用表单加载事件来触发循环的开始。

所以它会处理事件Me.Load 但是,你的循环是否必须在UI中发生?

答案 5 :(得分:0)

这是因为您的循环使窗口函数不能处理消息,例如那些告诉它重绘自身的消息。在循环内部调用Application.DoEvents()以允许UI继续运行。

但是,你需要问问自己为什么你首先要像这样循环。如果你是,比如复制一堆文件,这可能是有道理的。但是,对于大多数任务,响应计时器滴答应该可以解决问题,并且不会阻止UI。

答案 6 :(得分:0)

您应该使用BackgroundWorker组件在后台线程中运行循环。

请记住,后台线程无法直接与UI控件交互 要在UI上报告进度,您应该在后台线程中调用BackgroundWorker的ReportProgress方法,并处理ProgressChanged事件以更新UI。

单击按钮时可以调用CancelAsync方法,并循环直到CancellationPending属性为true