【问题标题】:Cross thread operation not valid when use backgroundworker使用backgroundworker时跨线程操作无效
【发布时间】:2012-09-12 13:00:10
【问题描述】:

下面是我的代码:

    Form2 msgForm;
    private void button3_Click_1(object sender, EventArgs e)
    {

        bw.WorkerReportsProgress = true;
        bw.WorkerSupportsCancellation = true;
        bw.DoWork += new DoWorkEventHandler(bw_DoWork);
        //bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
        bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);

        msgForm = new Form2();

        try
        {
            bw.RunWorkerAsync();

            msgForm.ShowDialog();
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
    }

    void bw_DoWork(object sender, DoWorkEventArgs e)
    {
        if (comboBox15.Text == "")
        {
            //MessageBox.Show("Please select Printer ID.", "Status", MessageBoxButtons.OK, MessageBoxIcon.Error);
            //return;
        }
        // Coding that transmit protocol and will last around 2 minutes.
    }

    void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        msgForm.Close();
    }

当我运行此后台工作程序编码时,出现错误,指出“跨线程操作无效:控件'comboBox15'从创建它的线程以外的线程访问。”

我该如何解决这个问题?

【问题讨论】:

标签: c#


【解决方案1】:

你可以使用Invoke:

// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.comboBox15.InvokeRequired)
{
    this.Invoke((MethodInvoker) delegate {if (comboBox15.Text == ""){// What you want to do}});
}
else
{
    if (comboBox15.Text == "")
    {
    }
}

还请阅读以下内容:
http://msdn.microsoft.com/en-us/library/ms171728(v=vs.80).aspx
http://msdn.microsoft.com/en-us/library/aa288468(v=vs.71).aspx
Anonymous method in Invoke call

【讨论】:

    【解决方案2】:

    您不能使用非 UI 线程中的 UI 元素。理想情况下,在后台工作人员启动之前向其提供相关信息,例如

    string text = combo15.Text;
    bw.DoWork += (sender, args) => TransmitStuff(combo15.Text, args);
    
    ...
    
    void TransmitStuff(string printerId, DoWorkEventArgs e)
    {
        ...
    }
    

    如果您可以使用 .NET 4.5 和 C# 5,则可以使用异步方法来使这一切变得更容易……但我意识到这不太适合您。

    编辑:虽然您可以使用Invoke,但最终会变得非常混乱 - 而且您可能会遇到不一致的状态。我通常认为在开始长时间运行的操作之前计算出您需要的所有状态,验证所有状态,然后将其交给操作会更整洁。如果在操作过程中需要更新 UI,可以使用BackgroundWorker 进度工具。

    【讨论】:

    • 我很困惑,我认为非 UI 线程的读取操作很好,不是吗?
    • @Rotem:不,那仍然无效。
    【解决方案3】:

    在BackgroundWorker中,当我们调用任何用户控制它的问题时。请在 Window Form Load 事件中使用此属性:

     CheckForIllegalCrossThreadCalls = false;
    

    【讨论】:

      【解决方案4】:

      您只能从主线程访问 gui 控件。

      移动

      如果 (comboBox15.Text == "")

      部分到 button3_click

      【讨论】:

      • 但是汤姆森,我需要在传输协议时使用comboBox15中的值。怎么样?
      【解决方案5】:

      您可以通过传递如下值来绕过它。

      private void Dowork()
      {
          backgroundWorker1.RunWorkerAsync(comboBox1.Text);
      }
      
      private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
      {
          String selected = (String)e.Argument;
          if (String.IsNullOrEmpty(selected)) return;
          //do stuff
      }
      

      【讨论】:

      • BudFinder,我正在使用你的答案,可以完美运行。但是当后台工作程序运行时,我的表单会冻结。如何解决?
      • 我的没有。如果失败,将字符串设置为组合框的值,传递它,并记住“dowork”例程中的所有代码必须引用传递的字符串,而不是组合框。 ..
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-13
      • 2020-08-08
      • 1970-01-01
      • 1970-01-01
      • 2011-07-11
      相关资源
      最近更新 更多