C# - 无法使用 Invoke() 将文本附加到后台线程的控件
您好,我在 C# 中从工作线程调用 richTextBox 时遇到问题。我正在使用 InvokeRequired/Invoke 方法。请查看我的代码:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void ThreadSafe(MethodInvoker method)
{
if (InvokeRequired)
Invoke(method);
else
method();
}
private void WorkerThread(object data)
{
string msg = "\nhello, i am thread " + data.ToString();
ThreadSafe(delegate
{
richTextBox1.AppendText(msg);
});
}
private void button1_Click(object sender, EventArgs e)
{
Thread[] workers = new Thread[3];
for (int i = 0; i < 3; i++)
{
workers[i] = new Thread(WorkerThread);
workers[i].Start(i);
string msg = "\nthread " + i.ToString() + "started!";
richTextBox1.AppendText(msg);
}
int j = 3;
while (j > 0)
{
for (int i = 0; i < 3; i++)
{
Thread.Sleep(250);
richTextBox1.AppendText("\nChecking thread");
if (workers[i].Join(250))
{
string msg = "\nWorker thread " + i.ToString() + " finished.";
richTextBox1.AppendText(msg);
workers[i] = null;
j--; // decrement the thread watch count
}
}
}
}
}
它在富文本框中打印以下内容:
thread 0started!
thread 1started!
thread 2started!
Checking thread
Checking thread
Checking thread
Checking thread
....
它不断地显示,“hello”消息不会被打印,并且用户界面被冻结。 然后我将 Invoke() 更改为 BeginInvoke(),我知道我不应该这样做,然后结果是这样的:
thread 0started!
thread 1started!
thread 2started!
Checking thread
Worker thread 0 finished.
Checking thread
Worker thread 1 finished.
Checking thread
Worker thread 2 finished.
hello, i am thread 0
hello, i am thread 1
hello, i am thread 2
这是什么原因,我该怎么办?
提前致谢。
Greetings, I'm having problem invoking a richTextBox from a worker thread in C#. I'm using the InvokeRequired/Invoke method. Please see my code:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void ThreadSafe(MethodInvoker method)
{
if (InvokeRequired)
Invoke(method);
else
method();
}
private void WorkerThread(object data)
{
string msg = "\nhello, i am thread " + data.ToString();
ThreadSafe(delegate
{
richTextBox1.AppendText(msg);
});
}
private void button1_Click(object sender, EventArgs e)
{
Thread[] workers = new Thread[3];
for (int i = 0; i < 3; i++)
{
workers[i] = new Thread(WorkerThread);
workers[i].Start(i);
string msg = "\nthread " + i.ToString() + "started!";
richTextBox1.AppendText(msg);
}
int j = 3;
while (j > 0)
{
for (int i = 0; i < 3; i++)
{
Thread.Sleep(250);
richTextBox1.AppendText("\nChecking thread");
if (workers[i].Join(250))
{
string msg = "\nWorker thread " + i.ToString() + " finished.";
richTextBox1.AppendText(msg);
workers[i] = null;
j--; // decrement the thread watch count
}
}
}
}
}
It prints the following in the rich text box:
thread 0started!
thread 1started!
thread 2started!
Checking thread
Checking thread
Checking thread
Checking thread
....
It goes on and on, the "hello" message doesn't get printed, and the UI is frozen.
Then I changed Invoke() to BeginInvoke(), which I know I shouldn't do, then the result is like this:
thread 0started!
thread 1started!
thread 2started!
Checking thread
Worker thread 0 finished.
Checking thread
Worker thread 1 finished.
Checking thread
Worker thread 2 finished.
hello, i am thread 0
hello, i am thread 1
hello, i am thread 2
What is the reason and what do I do?
Thanks in advance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
Invoke
方法同步运行您的委托 — 它会等到 UI 线程实际运行它,然后再将控制权返回给调用者。由于 UI 线程正在等待您的线程完成,因此您会遇到死锁。
相比之下,
BeginInvoke
方法异步运行委托 — 它立即返回,并且委托仅在一段时间后(当 UI 线程空闲时)运行。The
Invoke
method runs your delegate synchronously—it waits until the UI thread actually runs it before returning control to the caller.Since the UI thread is waiting for your threads to finish, you get a deadlock.
By contrast, the
BeginInvoke
method runs your delegate asynchronously—it returns immediately, and the delegate only runs some time later, when the UI thread is free.在离开
button1_Click
方法之前,您正在等待工作线程完成。这是一个问题,因为您的线程只有能够运行在同一线程上调用AppendText
方法的委托才能完成。当您更改为
BeginInvoke
时,您不再遇到此问题,因为您的工作线程不会阻止等待调用AppendText
方法的委托。如果您尝试阻止 UI 线程直到工作线程完成,只要它们依赖于对
Invoke
的调用,您就无法这样做。You are waiting for the worker threads to complete before leaving your
button1_Click
method. This is a problem because your threads can't complete until they are able to run the delegate that calls theAppendText
method on that same thread.When you change to
BeginInvoke
you don't have this problem any more because your worker threads don't block waiting on the delegate that calls theAppendText
method.If you are trying to block the UI thread until the worker threads complete you simply will not be able to as long as they rely on the call to
Invoke
.您无法从另一个线程更新 UI 控件,这是答案
You can't update UI controls from another thread, here is the answer