跨线程异常
本文关键字:异常 线程 | 更新日期: 2023-09-27 18:24:59
我有一段时间有问题
此行:
txtPastes.Text = (string)e.UserState;
抛出跨线程异常,我没有找到任何解决方案
txtPastes
-文本框
GuiUpdate
-BackgroundWorker
lstAllPastes
-字符串列表
private void GuiUpdate_DoWork(object sender, DoWorkEventArgs e)
{
while (true)
{
while (lstAllPastes.Count == 0) ;
for (int i = 0; i < lstAllPastes[0].Length; i++)
{
GuiUpdate.ReportProgress(0, lstAllPastes[0].Substring(0, i));
Thread.Sleep(1);
}
lstAllPastes.RemoveAt(0);
}
}
private void GuiUpdate_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
txtPastes.Text = (string)e.UserState;
}
private void GuiUpdate_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
}
您不能从UI线程以外的任何线程更新UI控件。通常,BackgroundWorker
将负责在UI线程上正确地引发其ProgressChanged
和RunWorkerCompleted
事件。由于这里的情况并非如此,您可以使用Invoke
方法将UI更新逻辑编组到UI线程:
txtPastes.Invoke(new Action(() =>
{
// This code is executed on the UI thread.
txtPastes.Text = (string)e.UserState;
}));
如果你在WPF上,你需要在控件的调度器上调用Invoke
:
txtPastes.Dispatcher.Invoke(new Action(() =>
{
txtPastes.Text = (string)e.UserState;
}));
更新:正如Thomas Levsque和Hans Passant所提到的,您应该调查为什么您的ProgressChanged
事件没有在UI线程上引发。我怀疑您在应用程序初始化生命周期中过早启动BackgroundWorker
,这可能会导致竞争条件,如果在初始化txtPastes
文本框之前引发第一个ProgressChanged
事件,则可能会导致NullReferenceException
。
当然,这应该是可行的。此异常的原因在您的代码段中不可见。重要的是BackgroundWorker在何时何地启动。它的RunWorkersync()方法使用SynchronizationContext.Current属性来确定哪个线程需要执行ProgressChanged事件处理程序。
当出现以下情况时,可能会出错:
- 在Application.Run()调用之前,您启动BGW太早了。Winforms或WPF还没有机会安装自己的同步提供程序
- 您在工作线程中调用了BGW的RunWorkerSync()方法。只支持封送至UI线程,消息循环是使在另一个线程上运行的代码正常工作的关键因素
- 具有txtPastes控件的窗体是在另一个线程上创建的。在UI线程上启动BGW时,仍然存在线程不匹配
- 表单的Show()方法是在另一个线程上调用的。这会在错误的线程上创建本机Windows窗口
确保从UI线程启动BackgroundWorker
;如果这样做,ProgressChanged
事件将在该线程上引发,并且不会发生异常。