【发布时间】:2012-01-04 18:52:42
【问题描述】:
我正在尝试理解 Windows 窗体中某个长期存在的概念:UI 编程;以下代码来自 Chris Sells 的《Windows 窗体编程》一书(第 2 版,2006 年):
void ShowProgress(string pi, int totalDigits, int digitsSoFar) {
// Display progress in UI
this.resultsTextBox.Text = pi;
this.calcToolStripProgressBar.Maximum = totalDigits;
this.calcToolStripProgressBar.Value = digitsSoFar;
if( digitsSoFar == totalDigits ) {
// Reset UI
this.calcToolStripStatusLabel.Text = "Ready";
this.calcToolStripProgressBar.Visible = false;
}
// Force UI update to reflect calculation progress
this.Refresh();
}
此方法是小型示例应用程序的一部分,该应用程序具有另一种计算 Pi 的长期运行方法。每次计算一组数字时,都会调用 ShowProgress() 来更新 UI。正如书中解释的那样,这段代码是“错误”的做事方式,当应用程序最小化然后再次进入前台时,会导致 UI 冻结,导致系统要求应用程序重新绘制自己。
我不明白的地方:既然 this.Refresh() 被反复调用,为什么它不处理任何等待关注的系统重绘事件?
还有一个后续问题:当我在 this.Refresh() 之后立即添加 Application.DoEvents() 时,冻结问题就消失了。 这无需求助于 Invoke/BeginInvoke ,等等。有没有cmets?
【问题讨论】:
-
DoEvents 告诉系统忽略事件?它不处理事件?那为什么在使用 DoEvents 之后 UI 开始变得响应?
-
以下是我们自己的 Jeff Atwood 提供的更多背景信息:codinghorror.com/blog/2005/08/is-doevents-evil-revisited.html
-
@DJ KRAZE:欣赏你的 cmets,但你能说得更具体点吗?当你说“这只是跳过它们并刷新你的东西”时,你指的是 Refresh 还是 DoEvents?另外,我的问题不是关于要做什么,而是关于 Refresh 和 DoEvents 的幕后发生了什么。我熟悉当 UI 线程上的控件被更新时跨线程调用需要遵循协议的要求。
-
@DJKRAZE:哇,你的 cmets 不太连贯。但是,如果我对您的理解正确,您会说“如果有事件等待处理”,那么
DoEvents()“只是跳过它们并刷新你的东西”。那是完全错误 -- 事实上,它与DoEvents()实际所做的相反。 Wiktor Zychla 在他的回答中描述了这种行为,但DoEvents()基本上设置了第二个消息泵循环,并泵送消息直到队列为空。这非常危险,正是因为它不“跳过事件”——它处理队列中的任何内容,而不仅仅是“你的东西”。 -
我混合了措辞,因为我陷入了试图制定关于引用我在 Delphi 解释中所做的事情的初步答案的过程中。抱歉造成混淆
标签: c# .net winforms multithreading invoke