2017-07-26 89 views
0

背景線程在我的Windows窗體應用程序仍被凍結我的UI

目前工作的一個Windows窗體應用程序,我要求創建。我遇到了一個在調用資源密集型進程時UI凍結的問題。我目前正在使用線程,據我所知,該線程用於防止UI凍結並接管整個PC。

問題

目前,當我使用的線程中調用我的基類中的方法是打開位於遠程服務器上的文件。這種方法有大約30到45秒的延遲。我正在創建我的後臺線程並調用它來啓動。當被調用時啓動,如果觸發,但是當它啓動時,不會等待我的線程完成,基本上給我一個空的異常。所以經過一番挖掘,我發現爲了等待線程完成,你必須調用.Join()。但是,當Join被調用時,它完全凍結了我的UI。所以我的創造力試圖創造一個工作周圍,並創建一個while循環,直到線程不再活着並繼續。但是,這也會凍結用戶界面。所以我錯過了什麼?未提及MSDN Doc

代碼示例

class BaseClass 
{ 
    public CWClient ClientFileContext(string clientFile, bool compress) 
    { 
     Client clientContext = null; 
     try 
     { 
      if (compress == true) 
      { 
       clientContext = appInstance.Clients.Open2(clientFile, superUser, passWord, OpenFlags.ofCompressed); 
      } 
      else 
      { 
       clientContext = appInstance.Clients.Open2(clientFile, superUser, passWord, OpenFlags.ofNone); 
      } 
     } 
     catch (Exception ex) 
     { 
      //TODO 
     } 
     return clientContext; 
    } 
} 

    public partial class Form1 : Form 
    { 
    private void button1_Click(object sender, EventArgs e) 
    { 
     BaseClass wpSec = new BaseClass(); 
     CWClient client = null;    

     Thread backgroundThread = new Thread(
      new ThreadStart(() => 
      { 
       client = wpSec.ClientFileContext(selectedFileFullPath, true); 
      } 
     )); 
     backgroundThread.Start(); 
     //backgroundThread.Join(); << Freezes the UI 
     var whyAreYouNotWorking = "Stop"; 
    } 
    } 

解決方法我試過

while (backgroundThread.IsAlive == true) 
{ 
    for (int n = 0; n < 100; n++) 
    { 
     Thread.Sleep(500); 
     progressBar1.BeginInvoke(new Action(() => progressBar1.Value = n)); 
    } 
} 
    // This also freezes the UI 
+1

是的,加入(立即在開始之後)否定了整個線程設置。你期望什麼?它也會使任何Control.Invoke()調用發生死鎖。 –

+1

這裏的簡單答案是使用BackgroundWorker –

+0

所以你知道,如果你阻止你的UI線程並強制它在你的後臺工作完成之前什麼都不做,你的UI將被凍結,而當你不這樣做的時候,它不會。所以......你的問題是什麼?你已經知道如何解決你的問題,*不要阻塞UI線程*。您已經顯示了代碼不要自行阻止UI線程。 – Servy

回答

3

我還要考慮這樣做的asyncawait模式。解釋了這個帖子:Using async await still freezes GUI

你的代碼應與此類似(基類不改變):

public partial class Form1 : Form 
{ 
    private async void button1_Click(object sender, EventArgs e) 
    { 
     BaseClass wpSec = new BaseClass(); 
     CWClient client = await Task.Run(() => 
      { 
       return wpSec.ClientFileContext(selectedFileFullPath, true); 
      } 
    ); 
     var whyAreYouNotWorking = "Stop"; 
    } 
} 

這是背的最信封的東西,但我希望,讓基本思路啓動任務,然後等待async方法中的結果。如果你不需要你的BaseClass掛起,那也可以在lambda中,只留下你真正想要的東西。

從@Chris Dunaway上面的鏈接也非常好。 http://blog.stephencleary.com/2013/08/taskrun-vs-backgroundworker-round-3.html

編輯:作爲@BradlyUffner提到,這也是你應該使用async void,應該寧可選擇在幾乎所有其他情況下,返回TaskTask<T>的幾次之一。

+0

對於閱讀此答案的人來說,請注意這顯示了應該使用'async void'的極少數*有效*位置之一。除非你明白'async' *非常好,並且確切地知道你在做什麼,所以'async'應該返回'Task'或'Task ', –

+0

從我讀的東西中,我採取了不同的方法,我在基類中的函數是一個異步任務。按照你的方式做這件事有什麼好處嗎?我會更新我的代碼示例。 – EasyE

+0

公平點@BradleyUffner,我同意,通常你應該照你說的去做。我會編輯並提及。 –

相關問題