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

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

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(); } } catch(Exception e) { ... } } 

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; } } 

通常,您应该在BackgroundWorker运行这种耗时的操作。 定义工作方法:

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

和set作为DoWork事件处理程序:

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

要从其他线程安全地更新UI,请使用Control.BeginInvoke方法:

 mainForm.BeginInvoke( () => { mainForm.UpdateLog(); }); 

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

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

有关更多信息,请参阅此链接 。

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

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