Guye Incognito
Guye Incognito

Reputation: 2844

C# background worker, winform. "Cross-thread operation not valid:"

I'm trying to get background worker functioning in the most basic way with a windows form, for instance get a background process to change text in a label.. I got the basic background worker code here.. http://www.albahari.com/threading/part3.aspx Heres the code in my form.. Trying to make it so you press a button and then background worker thread is spawned which changes text in the label

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;

       namespace WindowsFormsApplication4
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }


            BackgroundWorker _bw = new BackgroundWorker();

             void backgroundio()
            {
                _bw.DoWork += bw_DoWork;
                _bw.RunWorkerAsync("Message to worker");

            }

             void bw_DoWork(object sender, DoWorkEventArgs e)
            {
                // This is called on the worker thread
                label1.Text = (string)(e.Argument);        // writes "Message to worker"
                // Perform time-consuming task...
            }

             void button1_Click(object sender, EventArgs e)
             {
                 backgroundio();
             }

        }
    }

For the label1.Text = (string)(e.Argument); I get this error.

Cross-thread operation not valid: Control 'label1' accessed from a thread other than the thread it was created on.

Thank for any help !! :)

Actually while I'm here can somebody explain this line?

 _bw.DoWork += bw_DoWork;

I dont get how += makes any sense in this context. how can you add those things?

Upvotes: 2

Views: 11543

Answers (3)

Praveen M B
Praveen M B

Reputation: 1

You can not update UI controls from DoWork event. UI can be Updated from _bw_RunWorkerCompleted.

Pass the values you want to update in UI elements from DoWork event to RunWorkerCompleted Even through event arguments and update the label in Completed event.

Upvotes: 0

Cheeso
Cheeso

Reputation: 192457

Q1

Your bw_doWork method is a static. This means there is only one of those methods for all instances of your class. That method cannot access instance-specific properties or fields or methods. That explains the compiler error.

If you change that method to NOT be static it will allow you to reference label1 within it.


Q2.

The syntax you refer to is a shortcut to add an event handler to that event.

It just means "Add this handler to the list of handlers for the given event." The long-handed way of doing it is with AddEventHandler.

http://msdn.microsoft.com/en-us/library/system.reflection.eventinfo.addeventhandler.aspx

Q3

The cryptic message you get at runtime indicates that you cannot update the UI objects on the non-uI thread. (The bg worker implies a different thread.) The solution is to perform the update you want on the UI thread.

void bw_DoWork(object sender, DoWorkEventArgs e)
{
    // This is called on the worker thread
    UpdateLabel((string)e.Argument));
      ...more work here...
}

void UpdateLabel(string s)
{
    if (this.label1.InvokeRequired)
    {
        // It's on a different thread, so use Invoke.
        this.BeginInvoke (new MethodInvoker(() => UpdateLabel(s));
    }
    else
    {
        // It's on the same thread, no need for Invoke
        this.label1.Text = s;
    }
}

To learn more about it, http://msdn.microsoft.com/en-us/library/ms171728(v=vs.90).aspx

Upvotes: 9

Onkelborg
Onkelborg

Reputation: 3997

In the DoWork-event you should perform the work you want to be executed on a different thread, ie. "the background work that won't freeze your application".

Then you have a Progress-event (I think, something similar at least) - this is where you update your GUI, ie. change the text or your label. Don't perform any heavy work here, it's your main thread.

In your DoWork-event, ie. the background thread, you may report the progress to the main thread using a method on your BackgroundWorker object (I don't remember the name of the method, something like Report, Progress or something), the Progress-event will then be called on the main thread.

Upvotes: 2

Related Questions