2017-04-03 26 views
0

我寫了一個單線程程序(的WinForms MEH)和我期待它的表現是這樣的:爲什麼沒有後臺工作人員不及時更新UI?

  1. 的MainForm開始進展顯示形式
  2. 進展的形式呈現完全
  3. 進展形式receieves事件operationStarted這增加一張轉圈圖片
  4. 長效手術開始
  5. 進度表接收事件操作完成或操作失敗並設置合適的圖像

會發生什麼是混亂。

  1. MainForm的進展開始顯示形式
  2. 進展形式不完全呈現!
  3. 計劃了一段時間
  4. 掛起當持久操作完成UI更新

爲什麼用更新的Windows窗體的滯後?

此減小的代碼,如果必要

private bool Run(int commandIndex, string fullCommand) 
    { 
     if (operationStarted != null) 
      operationStarted(commandIndex); 

     // start long lasting external process 

     if (exitCode != 0) 
     { 
      if (operationFailed != null) 
       operationFailed(commandIndex, Error); 

      return false; 
     } 

     if (operationCompleted != null) 
      operationCompleted(commandIndex); 

     return true; 
    } 

operationStarted,operationFailed & operationCompleted被正確地設置,以更新相應的圖像。

+1

您需要一個BackGroundWorker。你的_long_operations操作和UI一樣運行在同一個線程中,所以它阻塞了線程來阻止UI被刷新 – Pikoh

+0

問題是你的程序一步接一步地工作,所以它開始顯示進度,之後甚至在它的渲染會啓動您的持久操作並關閉您的操作,完成後,它會返回以繼續顯示UI。你需要一個Backgroundworker,它可以在另一個線程上執行此操作 –

回答

2

這是大大簡化,但我認爲它應該足夠。

Windows由在隊列系統中處理的消息驅動。

當您顯示一個窗口時,一個或多個消息被放入一個隊列並且必須被處理。

其中一條消息將成爲一條消息。爲了響應這個消息,你的程序應該在屏幕上繪製窗口(或者其中的東西)。

隊列系統的處理方式是,你的形式是由一個線程,不斷做類似資:

while (true) 
{ 
    var message = GetNextMessage(); 
    if (message == none) break; 
    ProcessMessage(message); 
} 

一個這個循環處理是一個消息,指示你的程序的消息的用戶點擊一個表格按鈕。

作爲對此的迴應,.NET將此消息作爲事件傳遞給事件處理程序,通常類似於「button1_Click」,然後執行該事件。

直到你的事件處理程序,這個click方法返回,這個循環沒有處理任何消息。因此,如果該按鈕點擊事件做了很長時間的事情,那麼你會被稱爲「阻止UI」,這基本上是「你沒有按順序返回到消息循環」。

相關問題