2012-01-10 112 views
4

可能有人請幫助我以下的問題:線程安全更新

有兩類MainForm,然後LWriter。下面是一個來自LWriter的方法,除了寫入文件之外,還向RichTextBox控件發送一些更新(通過mainForm.UpdateLog(text))。一切正常,但是,這個WriteOutput方法也做了一些廣泛的處理,在計算過程中凍結了表單。

我認爲WriteOutput應該封裝在一個單獨的線程中。有人能幫我解釋一下如何在一個線程中放置WriteOutput(LWriter類),然後以安全的方式從mainFrom調用mainForm.UpdateLog()。

我是新來的線程,因此幫助將不勝感激。

public void WriteOutput(string output, Links[] links) 
{ 
    try { 
     using (StreamWriter sw = new StreamWriter(output)) { 
     for (int x= 1; x<links.Length;x++) { 
     ... 
      sw.WriteLine(...); 
      sw.Flush();        
     } 
     mainForm.UpdateLog(<text>); 
     } 
    } catch(Exception e) { ... } 
} 
+2

爲什麼使線程複雜化?無論如何,在WinForms的背景中做一些最簡單的方法之一就是使用'BackgroundWorker'類。在DoWork方法中,您需要保護可能共享的任何對象(並且不*觸及UI)。在「DoWorkCompleted」事件中,您可以更新UI。 – 2012-01-10 18:28:19

回答

3

delegate可用於線程安全的調用

入住這http://msdn.microsoft.com/en-us/library/ms171728.aspx

  // This delegate enables asynchronous calls for setting 
    // the text property on a TextBox control. 
    delegate void SetTextCallback(string text); 

    // This method demonstrates a pattern for making thread-safe 
    // calls on a Windows Forms control. 
    // 
    // If the calling thread is different from the thread that 
    // created the TextBox control, this method creates a 
    // SetTextCallback and calls itself asynchronously using the 
    // Invoke method. 
    // 
    // If the calling thread is the same as the thread that created 
    // the TextBox control, the Text property is set directly. 

    private void SetText(string text) 
    { 
     // InvokeRequired required compares the thread ID of the 
     // calling thread to the thread ID of the creating thread. 
     // If these threads are different, it returns true. 
     if (this.textBox1.InvokeRequired) 
     { 
      SetTextCallback d = new SetTextCallback(SetText); 
      this.Invoke(d, new object[] { text }); 
     } 
     else 
     { 
      this.textBox1.Text = text; 
     } 
    } 
+0

非常感謝。它完全符合我的要求。 LG – 2012-01-10 19:20:44

6

通常,您應該在BackgroundWorker中運行這種耗時的操作。定義一個工作方法:

private void worker_DoWork(object sender, DoWorkEventArgs e) 
{ 
    // execute your WriteOutput method 
} 

,並設置是爲DoWork事件處理程序:

BackgroundWorker worker = new BackgroundWorker(); 
worker.DoWork += new DoWorkEventHandler(worker_DoWork); 
worker.RunWorkerAsync(); // start the worker 

安全地從不同的線程更新UI使用Control.BeginInvoke方法:

mainForm.BeginInvoke(
    () => { mainForm.UpdateLog(<text>); }); 
1

互動使用UI控件必須在UI線程上完成。您可以在後臺線程上構建字符串,但在與之交互之前,您應該使用Control.Invoke或Control.BeginInvoke封送到UI線程。

很多關於網絡和堆棧溢出的例子。

2

如鮮于建議,delegate可用於線程安全的調用,您可以使用LINQ縮短代碼:

this.BeginInvoke((Action) delegate() 
{ 
     //code to update UI 
}); 

請參閱this link瞭解更多信息。

+0

迄今爲止最優雅的解決方案。謝謝。 – 2015-02-11 09:03:35