2

I am working on application that uses BackgroundWorker Thread. I have a button click event on which I'm doing following things

 btnLocate_Click(Object sender, EventArgs e)
 {
    BackgroundWorker bw = new BackgroundWorker();
    bw.DoWork += bw_DoWork;
    bw.RunWorkerCompleted += bw_RunWorkerCompleted;
    bw.RunWorkerAsync(lstNumbers.CheckedItems[0].ToString());
 }

In the Background Worker do work event I'm adding some values in globally defined ObservableCollection like this

private void bw_DoWork(object sender, DoWorkEventArgs e)
{
    try
    {
        lock (locker)
        {
            _RecData.Add(new RecNumberData
                    {
                        // Some Values 
                    });
         }
    }

In BackgroundWorker complete event I'm setting this collection as data source for grid and start a timer that create a new BackgroundWorker and do the same job again.

private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{  
    grid.DataSource = RecData;
    timer1.Start();
}

private void timer1_Tick(object sender, EventArgs e)
{
    timer1.Stop();
    BackgroundWorker bw = new BackgroundWorker();
    bw.DoWork += bw_DoWork;
    bw.RunWorkerCompleted += bw_RunWorkerCompleted;
    bw.RunWorkerAsync(lstNumbers.CheckedItems[0].ToString());
}

Now the code runs fine when first time BackgroundWorker runs. But when second time it runs after Timer ticking event, Exception raised at line Cross Thread Opeartion Detected.

_RecData.Add(new RecNumberData
    {
        // Some Values 
    });

What could be the cause?

Rajeev Kumar
  • 4,901
  • 8
  • 48
  • 83

3 Answers3

3

Speculation without seeing more code, but I would suspect that:

  • When you are adding values to the collection the first time through, the collection isn't bound to the UI => no problem

  • The second time through it is bound to the UI (in the first complete event), so your background worker is attempting to update the UI.

The solution might be to create a second observable collection for your second BackgroundWorker. Or defer adding the results to the collection until the Completed event.

Joe
  • 122,218
  • 32
  • 205
  • 338
  • 1
    Exactly the problem is. When i remove `DataSource = RecData`, code runs second time succesfully. But i need to get workaround for this. – Rajeev Kumar Sep 08 '14 at 11:14
  • 2
    @Rajeev Either don't use a background thread, or enqueue the updates to `RecData` into the GUI thread, or collect the updates and apply them from the GUI thread once the background worker is done. – Peter Sep 08 '14 at 11:23
  • I was running into this same issue while trying to refresh my data by using the same bgw as I used for loading. After finding this answer, I fixed my problem by simply setting `DataSource = null` before running the bgw again, then re-setting DataSource again upon completion. – sǝɯɐſ Jun 21 '18 at 13:10
2

You are modifying a GUI object from outside the GUI thread. You shouldn't do that.

By setting RecData as the data source of a GUI object, every change to RecData will trigger a notification that will change the GUI object. After binding RecData you are changing RecData, and therefore your GUI object, from the background worker thread. Objects that are databound to a GUI object must not be modified by any thread other than the GUI thread.

You can use Control.BeginInvoke to enqueue an action on the GUI thread.

Peter
  • 5,608
  • 1
  • 24
  • 43
0

You're adding data to a variable that is used as a datasource to a graphical component (grid), you need to tell us what UI technology you're using (WPF? WInform?).

What's happening is you're doing something on a thread that isn't the one the UI runs on, and most UI technologies do not allow things that affect them running on another thread, there are mechanisms to work around this but they depend on the tech.

Most of the time you'll want to register the code that changes data the UI reads to run on a dispatcher (it will be queued and run on the main thread as soon as time is available)

Ronan Thibaudau
  • 3,413
  • 3
  • 29
  • 78