2011-04-04 33 views
6

我有後續的按鈕單擊事件:C# - 代碼處理順序 - 奇怪的行爲

private void btnRun_Click(object sender, EventArgs e) 
    { 
     label1.Visible = true; 

     if (SelectDatabase()) 
     { 
      if (string.IsNullOrEmpty(txtFolderAddress.Text)) 
       MessageBox.Show("Please select a folder to begin the search."); 
      else 
      { 

       if (cbRecurse.Checked == false || Directory.GetDirectories(initialDirectory).Length == 0) 
       { 
        CheckSingleFolder(); 
       } 
       else 
       { 
        CheckSingleFolder(); 
        directoryRecurse(initialDirectory); 
       } 

           } 
     } 


    } 

實際上,它做了一些檢查,然後開始尋找特定文件的一些目錄遞歸。但是,直到目錄被遞歸之後,才能使標籤可見的第一行代碼纔會出現?任何人都知道爲什麼會這樣?

謝謝。

+0

嘗試刷新您的表單,如果您的功能持有它,可能會有所幫助。 'form1.refresh();' – Prix 2011-04-04 13:42:19

回答

8

你在UI線程中正在做所有事情,這是一個非常糟糕的主意 - UI無法更新,對事件做出反應直到完成。

您應該使用後臺線程並使用Control.BeginInvoke或使用BackgroundWorker進度更新UI等。

基本上有在WinForms的兩個黃金規則(與WPF/Silverlight的類似):

  • 不要做任何事情可以採取在UI線程的時間顯著量
  • 別t觸摸任何線程的任何UI元素其他比UI線程
+0

然後等待新線程完成的最佳方式是什麼?我有另一種方法,必須等到遞歸完成。如果我使用單獨的線程,然後使用while(thread.isalive){}之類的東西,它顯然會阻塞該線程,直到新線程完成。你會推薦什麼?謝謝。 – 2011-04-04 13:49:47

+0

@Darren:使文件處理代碼回調到UI線程,調用後續需要的任何方法(例如重新啓用按鈕等)。 – 2011-04-04 13:51:37

+0

非常感謝。所以我簡單地說,例如,使用這樣的東西:btnRun.Invoke((MethodInvoker)委託{/ /運行方法}); – 2011-04-04 13:58:24

1

您的整個方法當前以阻止單元的形式運行 - 添加Application.DoEvents()作爲解決方法,但實際上您應該在後臺線程中執行此類處理,即使用後臺工作程序。

+3

Blech。 Application.DoEvents是一個黑客 - 這個代碼不應該在UI線程上執行。 – 2011-04-04 13:41:33

+0

gaah我只是在寫這個 – BrokenGlass 2011-04-04 13:42:36

+0

而且非常危險的黑客。我很高興你補充說明;你從我身上僥倖逃脫了。 ;-)有太多的答案使用錯誤的建議來使用Application.DoEvents。 – 2011-04-04 13:47:01

1

代碼在繪製用戶界面的同一個線程上執行。因此,在代碼執行時,您的UI不會被重新繪製。一旦按鈕點擊代碼完成後,用戶界面將重新繪製,並且label1被無形地繪製。

您可以使用例如TaskBackgroundWorker將代碼移動到單獨的線程中。但是,您不能直接從不同的線程設置UI屬性,因此您需要小心地從UI線程設置UI屬性,或者關於如何從另一個線程更新GUI,請執行see this question

1

視圖不會更新,直到代碼塊完成。所以我會爲遞歸部分提出一個BackgroundWorker

1

解釋:標籤被設置爲可見,並且它被無效(需要重繪),但是Windows消息泵在它運行空閒之前不會開始重新繪製。所以你的代碼會阻止它。

一個簡單的解決方案是在將其設置爲可見之後立即調用label1.Update()

更好的解決方案是將耗時的代碼移動到線程(Backgroundworker)。