使用backgroundworker时,交叉线程操作无效

时间:2012-09-20 07:31:15

标签: c#

以下是我的编码:

    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'从其创建的线程以外的线程访问。"

如何解决这个问题呢?

5 个答案:

答案 0 :(得分:5)

您可以使用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

答案 1 :(得分:1)

您不能使用非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进度工具。

答案 2 :(得分:1)

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

 CheckForIllegalCrossThreadCalls = false;

答案 3 :(得分:0)

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

移动

  

if(comboBox15.Text ==“”)

部分到button3_click

答案 4 :(得分:0)

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

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
}