2012-01-10 63 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