Coolguy
Coolguy

Reputation: 2285

Cross thread operation not valid when use backgroundworker

Below is my coding:

    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();
    }

When I run this background worker coding, there's an error stating "Cross-thread operation not valid: Control 'comboBox15' accessed from a thread other than the thread it was created on."

How do I solve this problem guys?

Upvotes: 3

Views: 5006

Answers (5)

user2244754
user2244754

Reputation: 21

In BackgroundWorker, when we call any user controls its problem. Please use this property in Window Form Load event:

 CheckForIllegalCrossThreadCalls = false;

Upvotes: 1

Jon Skeet
Jon Skeet

Reputation: 1500065

You can't UI elements from a non-UI-thread. Ideally, provide the relevant information to the background worker before it starts, e.g.

string text = combo15.Text;
bw.DoWork += (sender, args) => TransmitStuff(combo15.Text, args);

...

void TransmitStuff(string printerId, DoWorkEventArgs e)
{
    ...
}

If you can use .NET 4.5 and C# 5, you could use an async method to quite possibly make all of this easier... but I realize that's unlikely to be an option for you.

EDIT: While you can use Invoke, that ends up being quite messy - and you've got potentially inconsistent state. I generally think it's tidier to work out all the state you need before you start the long-running operation, validate it all, and then hand it to the operation. If you need to update the UI during the operation, you can use the BackgroundWorker progress facilities.

Upvotes: 1

Dor Cohen
Dor Cohen

Reputation: 17080

You can use 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 == "")
    {
    }
}

also read the following:
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

Upvotes: 5

BugFinder
BugFinder

Reputation: 17858

You can get round it by passing the value such as below.

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
}

Upvotes: 0

Thomsen
Thomsen

Reputation: 773

You can only access gui controls from your main thread.

Move the

if (comboBox15.Text == "")

part to button3_click

Upvotes: 0

Related Questions