从其他类的线程安全更新WinForm控件

时间:2012-01-10 18:22:26

标签: c# .net winforms multithreading thread-safety

有人可以帮助我解决以下问题:

有两个类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) { ... }
}

4 个答案:

答案 0 :(得分: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 :(得分: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;
        }
    }

答案 2 :(得分:2)

根据Sonu的建议,delegate可用于线程安全调用,您可以使用Linq缩短代码:

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

有关详细信息,请参阅this link

答案 3 :(得分:1)

与UI控件的交互必须在UI线程上完成。您可以在后台线程上构建字符串,但是在与UI线程进行交互之前,您应该使用Control.Invoke或Control.BeginInvoke编组UI线程。

网上有很多这样的例子和堆栈溢出。