2010-02-08 137 views
0

我有一個線程從一個網站收集URL列表並更新UI,因爲它是這樣做的。這工作正常。但是,我需要主線程來等待鏈接被收集。我試圖加入,但是這會鎖定用戶界面。這是我的例子。正如你現在所看到的,foreach循環在線程運行的同時被調用。我希望foreach在線程運行後運行。線程和正在等待

任何想法?

/** This thread will add links to list<string> linkList **/ 
Thread linkListThread = new Thread(new ThreadStart(getLinkList)); 
linkListThread.Start(); 
foreach (String link in linkList) 
{ 
    txtOutput.Text += link; 
} 
+0

A面提示,你可以這樣做'txtOutput.Text =的string.join( 「」,linkList.ToArray() )',在記憶上更快更好。 – 2010-02-08 12:45:04

+0

如果您當前的線程只是產生另一個線程來完成這項工作,然後必須等待該線程完成,那麼爲什麼要使用兩個線程來完成此任務?爲什麼不直接調用直接完成工作的代碼呢? – 2010-02-10 11:12:11

回答

1

移動需要的線程已經完成到事件處理程序BackgroundWorker.RunWorkerCompleted

更新後運行該代碼:處理程序在右側調用(調用的)線程 - 這樣你就可以安全地更新UI。

請參閱上述msdn頁面上的代碼片段。

+1

不,RunWorkerCompleted代碼由後臺工作者自動在窗體的線程上下文中調用。 – 2010-02-08 12:57:03

+0

我調用的方法... getLinkList(),是否需要更改爲private void getLinkList(Object sender,DoWorkEventArgs args)? 所以我可以調用bw.DoWork + = getLinkList; ? – 2010-02-08 13:00:54

+0

是的。但是,也可以雙擊設計器中的DoWork事件,並將getLinkList()中的代碼複製到新創建的事件處理程序中。別忘了:永遠不要在DoWork中處理異常!他們將傳遞給e.Error中的RunWorkerCompleted事件。 – 2010-02-08 13:03:09

6

您可以使用後臺工作器。或者讓線程方法在完成時在主上下文中調用方法,傳遞您收集的項目列表。

編輯
我想我應該詳細說明我的第二種方法。

List<string> links = new List<string>(); 

然後,你將這個名單給線程,填補它:

你可以創建線程之前準備一張列表實例

Thread t = new Thread(new ParameterizedThreadStart(FillList)); 
t.Start(links); 

線程方法採用列表,填充它並調用一個顯示UI中細節的方法:

private static void FillList(object state) 
{ 
    List<string> links = (List<string>)state; 

    // Fill data 

    this.Invoke((MethodInvoker)delegate() { HandleNewLinks(links); })); 
} 

HandleNewLinks方法效果正如人們所預料:

private void HandleNewLinks(List<string> links) 
{ 
    foreach (string link in links) 
     // Do something... 
} 
+0

+1 - 這就是我想說的,所以我刪除了我的答案。儘管不要忘記你需要使處理線程安全。 – ChrisF 2010-02-08 12:47:54

+0

當然,但我假設在這個示例中,該線程只創建一次以解耦填充列表並顯示結果。無論如何,我最喜歡的解決方案是後臺工作人員...... – 2010-02-08 12:55:26

0

目前尚不清楚你想要什麼:無論是應用程序等待(並且是反應遲鈍),或應用程序不會等待並保持響應。在後一種情況下,您可能需要禁用一些控件/可能的操作,直到列表完成加載。

一個骯髒的解決方法是做一些自旋等待(Join與超時幾毫秒,返回結果是否完成)與一些Application.DoEvents()調用。

+0

我希望應用程序保持響應狀態。我需要創建2個線程並加入它們嗎? IE瀏覽器。線程收集鏈接,並輸出一個線程? 將加入等待,直到線程完全完成? – 2010-02-08 12:46:58

+0

UI線程將執行輸出(您不應該從另一個線程訪問WinForms控件),另一個線程完成工作(獲取鏈接)。所以UI線程有一個'while(!workerThread.Join(20)){Application.DoEvents(); }'這將等待另一個線程完成,同時保持消息泵(從而UI)運行。 – Lucero 2010-02-08 13:28:17

0

要簡單的辦法是有你的工作線程回調到上完成的主要應用,你再繼續完成線程,並在您的主UI計數這樣做:

while(runningThreads != 0) 
{ 
    Application.DoEvents(); 
} 

,並有螺紋電話:

void OnThreadCompleted() 
{ 
    runningThreads--; 
} 

更好地使用BackgroundWorker而不是創建自己的線程,因爲它具有所有的回調機制。

0

我們已經使用了後臺工作類似的東西,和它的工作很好,有兩個意見:

  1. 不要添加文字與+ =,因爲它會經過幾個減慢你的速度大大的文本框百行。改用AppendText。

  2. 如果您向接口添加大量信息並且有睡眠時間(處理過程中),線程可能會「睡着」。我們通過每200行刪除文本框中的文本來修復它(結果寫入文件,所以我們沒有丟失任何東西)。

0

一種選擇是簡單地在主線程中使用Invoke

void YourMethod() 
{ 
    Thread linkListThread = new Thread(new ThreadStart(getLinkList)); 
    linkListThread.Start(); 
} 

void getLinkList() 
{ 
    List<string> linkList = new List<string>(); 
    // Your tasks 

    // Done 
    LinkListComplete(linkList); 
} 

void LinkListComplete(List<string> linkList) 
{ 
    if (InvokeRequired) 
    { 
     Invoke(new Action<List<string>>(LinkListComplete),linkList); 
     return; 
    } 

    foreach (String link in linkList) 
    { 
     txtOutput.Text += link; 
    } 
}