从另一个线程写入文本框?

我无法弄清楚如何使一个C#Windows窗体应用程序写入一个线程的文本框。 例如在Program.cs中,我们有标准的main()来绘制表单:

static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); } 

然后我们在Form1.cs中:

 public Form1() { InitializeComponent(); new Thread(SampleFunction).Start(); } public static void SampleFunction() { while(true) WindowsFormsApplication1.Form1.ActiveForm.Text += "hi. "; } 

我是否完全错误?

UPDATE

这里是从bendewey提供的工作代码示例:

 public partial class Form1 : Form { public Form1() { InitializeComponent(); new Thread(SampleFunction).Start(); } public void AppendTextBox(string value) { if (InvokeRequired) { this.Invoke(new Action<string>(AppendTextBox), new object[] {value}); return; } textBox1.Text += value; } void SampleFunction() { // Gets executed on a seperate thread and // doesn't block the UI while sleeping for(int i = 0; i<5; i++) { AppendTextBox("hi. "); Thread.Sleep(1000); } } } 

在你的MainForm中设置一个函数来设置文本框的InvokeRequired

 public void AppendTextBox(string value) { if (InvokeRequired) { this.Invoke(new Action<string>(AppendTextBox), new object[] {value}); return; } ActiveForm.Text += value; } 

虽然在你的静态方法,你不能只是打电话。

 WindowsFormsApplication1.Form1.AppendTextBox("hi. "); 

你必须有一个对Form1的静态引用,但这并不是真正的build议和必要的,你可以让你的SampleFunction不是静态的,如果这样的话你可以直接调用

 AppendTextBox("hi. "); 

它将附加在不同的线程上,并在需要时使用Invoke调用将其编组到UI中。

完整的示例

 public partial class Form1 : Form { public Form1() { InitializeComponent(); new Thread(SampleFunction).Start(); } public void AppendTextBox(string value) { if (InvokeRequired) { this.Invoke(new Action<string>(AppendTextBox), new object[] {value}); return; } textBox1.Text += value; } void SampleFunction() { // Gets executed on a seperate thread and // doesn't block the UI while sleeping for(int i = 0; i<5; i++) { AppendTextBox("hi. "); Thread.Sleep(1000); } } } 

或者你可以这样做

 public partial class Form1 : Form { public Form1() { InitializeComponent(); new Thread( SampleFunction ).Start(); } void SampleFunction() { // Gets executed on a seperate thread and // doesn't block the UI while sleeping for ( int i = 0; i < 5; i++ ) { this.Invoke( ( MethodInvoker )delegate() { textBox1.Text += "hi"; } ); Thread.Sleep( 1000 ); } } } 

我会尽可能经常使用BeginInvoke而不是Invoke ,除非您确实需要等到控件更新(在您的示例中不是这种情况)。 BeginInvoke将委托放在WinForms消息队列中,并让调用代码立即进行(在你的情况下, SampleFunction的for循环)。 Invoke不仅仅是发布委托,还要等到它完成。

所以在你的例子中的方法AppendTextBox你会像这样用BeginInvokereplaceInvoke

 public void AppendTextBox(string value) { if (InvokeRequired) { this.BeginInvoke(new Action<string>(AppendTextBox), new object[] {value}); return; } textBox1.Text += value; } 

那么,如果你想变得更花哨,那么还有SynchronizationContext类,它可以让你基本上像Control.Invoke/Control.BeginInvoke ,但是不需要知道WinForms控件引用的优点。 这是一个关于SynchronizationContext的小教程。

您需要从拥有该控件的线程执行该操作。

这就是我所做的,而不会增加太多的代码噪音:

 control.Invoke(() => textBox1.Text += "hi"); 

Invoke过载是Lokad共享库的简单扩展:

 /// <summary> /// Invokes the specified <paramref name="action"/> on the thread that owns /// the <paramref name="control"/>.</summary> /// <typeparam name="TControl">type of the control to work with</typeparam> /// <param name="control">The control to execute action against.</param> /// <param name="action">The action to on the thread of the control.</param> public static void Invoke<TControl>(this TControl control, Action action) where TControl : Control { if (!control.InvokeRequired) { action(); } else { control.Invoke(action); } } 

最简单的,不关心代表

 if(textBox1.InvokeRequired == true) textBox1.Invoke((MethodInvoker)delegate { textBox1.Text = "Invoke was needed";}); else textBox1.Text = "Invoke was NOT needed"; 

更简单的是只使用BackgroundWorker控件…

这是我做了什么来避免CrossThreadException并从另一个线程写入文本框。

这里是我的button点击function – 我想要生成一个随机数的线程,然后通过调用getID()获得他们的ID。 方法和该工作线程中的textBox值。

  private void btnAppend_Click(object sender, EventArgs e) { Random n = new Random(); for (int i = 0; i < n.Next(1,5); i++) { label2.Text = "UI Id" + ((Thread.CurrentThread.ManagedThreadId).ToString()); Thread t = new Thread(getId); t.Start(); } } 

这里是getId(workerThread)代码

 public void getId() { int id = Thread.CurrentThread.ManagedThreadId; //Note that, I have collected threadId just before calling //*this.Invoke* //method else it would be same as of UI thread inside the below code //block this.Invoke((MethodInvoker)delegate () { inpTxt.Text += "My id is" +"--"+id+Environment.NewLine; }); 

看看Control.BeginInvoke方法。 重点是永远不要从另一个线程更新UI控件。 BeginInvoke将调用调用到控件的UI线程(在你的情况下,表单)。

要获取表单,请从示例函数中删除静态修饰符,并使用this.BeginInvoke(),如MSDN示例中所示。