2
votes

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?

3
Remove the "static" keyword from all your code. Use it only when you know why you are using it.Hans Passant
Answered exact question. Full BkWorker sample is there - stackoverflow.com/a/11033200/763026. In Do_Work you cannot access UI. See the sample in my SO post. Copy-Past and run it.Angshuman Agarwal

3 Answers

9
votes

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

2
votes

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.

0
votes

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.