2013-09-27 61 views
0

我遇到過一些我不知道如何解釋的行爲。當我反覆畫上System.Windows.Forms.Form不小心不要掛線,幾秒鐘後,繪圖輸出會被凍結,我看到了可怕的(無響應)文本標題: Not Responding爲什麼將Form.Text更改爲非空會導致程序顯示「(Not Responding)」?

這張截圖是不是中期平局;在程序結束時,它正在繪製的圖像是完全紅色的,但繪圖已經停止了大約一半。 奇怪的是,如果我在繪圖之前跳過設置Form.Text屬性,它不會凍結。有人可以解釋爲什麼嗎?

我正在使用循環來繪製一些多線程圖形填充算法的進度,但看到屏幕輸出凍結。因爲我正在繪製,然後在循環中調用Thread.Sleep(),所以我應該預料到這種行爲(other posts指出我可能本應該使用BackgroundWorker,但僅僅使用Application.DoEvents()就停止了我的凍結)。

但是,當切斷代碼來查找我的錯誤時,真的讓我感到驚訝的是,當我刪除呼叫以更改form.Text時,它不再凍結!它並沒有呼籲制定者也做任何事情;分配給空字符串(form.Text = "";)也會導致它不凍結。所以,由於某種原因Text爲空時Windows不在意程序沒有響應,並且會很高興地繼續顯示繪圖進度! 發生了什麼事? Windows是否用不同的空白標題處理程序?

我將代碼降低到了看到凍結所需的最低限度。在程序運行時,表單圖像將被循環填充爲紅色。即使循環繼續運行,大約在填充的一半時停止。你看到它完成後會處理事件,並再畫一次來顯示整個圖像是紅色的,然後再停留兩秒鐘。

(如果您進行調試(F5),它不凍結運行。!你一定沒有調試(按Ctrl-F5)運行做出搞清楚這一切盡都更難)

using System.Drawing; 
using System.Threading; 
using System.Windows.Forms; 

// Include resources System.Drawing, System.Windows.Forms in VS before compiling 
class Program 
{ 
    static void Main(string[] args) { 
     Bitmap image = new Bitmap(400, 20); 

     Form form = new Form(); 
     form.Text = "some title"; // Comment this out to avoid the freeze 
     form.SetBounds(30, 30, image.Width + 16, image.Height + 38); 
     form.Show(); 
     Graphics graphics = Graphics.FromHwnd(form.Handle); 

     for (int x = 0; x < 400; ++x) 
      for (int y = 0; y < 20; ++y) { 
       image.SetPixel(x, y, Color.Red); 
       graphics.DrawImage(image, 0, 0); 
       Thread.Sleep(1); 
       // Calling this would prevent the freeze: 
       //Application.DoEvents(); 
      } 

     Application.DoEvents(); 
     graphics.DrawImage(image, 0, 0); 
     Thread.Sleep(2000); 
    } 
} 
+0

由於無響應的用戶界面,表單凍結。這沒有什麼可以形成標題 –

+0

我明白,使用戶界面不響應會導致它凍結。但是如果我將標題留空,它不會凍結。運行代碼不會給你這種行爲嗎? –

+0

沒有。至少在Windows 7上 –

回答

2

Thread.Sleep();會阻止你的gui線程。您的表單未更新,並且您的消息循環(處理鼠標/繪畫/鍵盤事件)被阻止。

調用Application.DoEvents將處理來自消息循環的消息,但這是一種不好的做法。即使循環未準備好,您也可以關閉表格。

我認爲問題是,form.Text = "some title";發送一條消息(WM_PAINT)到窗口重新繪製窗口,但它永遠不會被處理。哪些變成無響應。大概把Application.DoEvents放在form.Text = "some title";後面,可以解決這個問題。

如果要間隔更新圖形,應該查看Timer類。 http://msdn.microsoft.com/en-us/library/system.windows.forms.timer.aspx

+0

我相信分配給'form.Text'會發送一個paint消息,但是不會有任何後續調用'graphics.DrawImage()'發送類似的消息嗎?我嘗試在賦值後將該調用放到'DoEvents()',並且它仍然需要大約相同的時間來凍結。無論如何,我對解決凍結問題不感興趣,更多的是試圖理解爲什麼當我將這項任務評論出來時,它在幾秒鐘內不會凍結。 –

+0

+1指出'Application.DoEvents()'' – Koen

+0

不好的做法感謝指出'DoEvents()'是不好的做法;它促使我更多地瞭解它! [Jeff Atwood](http://www.codinghorror.com/blog/2004/12/is-doevents-evil.html)指出,「即使Microsoft建議使用它來代替簡單問題的硬核線程」,和[Eric Lippert](http://msdn.microsoft.com/en-us/magazine/hh456401.aspx)說:「DoEvents應該只用於解決最微不足道的情況下的響應問題。」如果這是一個有開始繪畫按鈕的UI,是的,「DoEvents」可能會導致問題。我認爲在這種情況下這是值得的。 –

相關問題