跨线程异常

本文关键字:异常 线程 | 更新日期: 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线程上正确地引发其ProgressChangedRunWorkerCompleted事件。由于这里的情况并非如此,您可以使用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事件将在该线程上引发,并且不会发生异常。