后台工作者 运行 但不打印任何内容
Background Worker is Running but Doesn't Print anything
我有一个叫 bgw
的 BackgroundWorker
,我把我叫 LogBoxForm
的习俗 Form
传给了他。自定义 Form
作业只是在上面打印一些东西。
LogBoxForm logBox = new LogBoxForm(); //both declared in the main Form
BackgroundWorker bgw = new BackgroundWorker();
主要Form
的Load
event
发起了两个bgw
事件:DoWork
和RunWorkerCompleted
像这样
bgw.DoWork += bgw_DoWork;
bgw.RunWorkerCompleted += bgw_RunWorkerCompleted;
然后当我按下名为 button9
的 Button
时,bgw
将按照此代码
的指示变为 运行
//Background worker
BackgroundWorker bgw = new BackgroundWorker();
private void button9_Click(object sender, EventArgs e) {
if (bgw.IsBusy)
return;
bgw.RunWorkerAsync(logBox);
}
void bgw_DoWork(object sender, DoWorkEventArgs e) {
LogBoxForm lbf = e.Argument as LogBoxForm;
try {
for (int i = 0; i < 5; ++i) {
lbf.WriteTimedLogLine("loop " + (i + 1).ToString());
Thread.Sleep(1000);
}
} catch (Exception exc) {
throw exc;
}
}
void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
logBox.WriteTimedLogLine("Completed!");
if (e.Error != null)
logBox.WriteTimedLogLine(e.Error.ToString());
}
它在 catch
行停止 这是我收到的错误消息:
System.InvalidOperationException: Cross-thread operation not valid:
Control 'richTextBoxAll' accessed from a thread other than the thread
it was created on.
我是 BackgroundWorker
的新用户,可能真的不知道这一切是如何发生的。我希望更有经验的人可以告诉我我的代码有什么问题。期待您的指导。
这应该是Thread Affinity的经典案例。由于 BackgroundWorker
在不同于 UI 线程的不同线程上运行,因此您需要调用 .Invoke
。查看此 link here 以查看封装 thread-safe 调用的扩展方法示例。
使用此扩展方法,您可以像这样编写 WinForms thread-safe 代码:
this.ThreadSafeInvoke(() => logBox.WriteTimedLogLine("loop " + (i + 1).ToString()));
这里的关键是,由于您在不同的线程上执行,.InvokeRequired
布尔值将 return 为真,然后您将执行传递给 [=16] 的 Action
=] 通过 .Invoke
-- 这将编组回 UI 线程。
如果您不想使用扩展方法,只需执行以下操作:
this.Invoke(new MethodInvoker(() =>
logBox.WriteTimedLogLine("loop " + (i + 1).ToString())));
扩展方法的优势是显而易见的。希望对您有所帮助。
我有一个叫 bgw
的 BackgroundWorker
,我把我叫 LogBoxForm
的习俗 Form
传给了他。自定义 Form
作业只是在上面打印一些东西。
LogBoxForm logBox = new LogBoxForm(); //both declared in the main Form
BackgroundWorker bgw = new BackgroundWorker();
主要Form
的Load
event
发起了两个bgw
事件:DoWork
和RunWorkerCompleted
像这样
bgw.DoWork += bgw_DoWork;
bgw.RunWorkerCompleted += bgw_RunWorkerCompleted;
然后当我按下名为 button9
的 Button
时,bgw
将按照此代码
//Background worker
BackgroundWorker bgw = new BackgroundWorker();
private void button9_Click(object sender, EventArgs e) {
if (bgw.IsBusy)
return;
bgw.RunWorkerAsync(logBox);
}
void bgw_DoWork(object sender, DoWorkEventArgs e) {
LogBoxForm lbf = e.Argument as LogBoxForm;
try {
for (int i = 0; i < 5; ++i) {
lbf.WriteTimedLogLine("loop " + (i + 1).ToString());
Thread.Sleep(1000);
}
} catch (Exception exc) {
throw exc;
}
}
void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
logBox.WriteTimedLogLine("Completed!");
if (e.Error != null)
logBox.WriteTimedLogLine(e.Error.ToString());
}
它在 catch
行停止 这是我收到的错误消息:
System.InvalidOperationException: Cross-thread operation not valid: Control 'richTextBoxAll' accessed from a thread other than the thread it was created on.
我是 BackgroundWorker
的新用户,可能真的不知道这一切是如何发生的。我希望更有经验的人可以告诉我我的代码有什么问题。期待您的指导。
这应该是Thread Affinity的经典案例。由于 BackgroundWorker
在不同于 UI 线程的不同线程上运行,因此您需要调用 .Invoke
。查看此 link here 以查看封装 thread-safe 调用的扩展方法示例。
使用此扩展方法,您可以像这样编写 WinForms thread-safe 代码:
this.ThreadSafeInvoke(() => logBox.WriteTimedLogLine("loop " + (i + 1).ToString()));
这里的关键是,由于您在不同的线程上执行,.InvokeRequired
布尔值将 return 为真,然后您将执行传递给 [=16] 的 Action
=] 通过 .Invoke
-- 这将编组回 UI 线程。
如果您不想使用扩展方法,只需执行以下操作:
this.Invoke(new MethodInvoker(() =>
logBox.WriteTimedLogLine("loop " + (i + 1).ToString())));
扩展方法的优势是显而易见的。希望对您有所帮助。