0

When I need to perform an action that takes quite long, I call it in a BackgroundWorker like this, so it does not freeze the UI;

BackgroundWorker bgWorker = new BackgroundWorker();

bgWorker.DoWork += (s, e) => { 
    //Do something long lasting
    for(int i = 0; i < x; i++){

        //Performing action i of x

        //While doing so update the progressbar
        prgBar.Dispatcher.Invoke(() =>{
            prgBar.Value += ((i / x) * 100.0);
        });

    }
};  

bgWorker.RunWorkerCompleted += (s, e) => { 
    //Finish up things
}; 
bgWorker.RunWorkerAsync();

Is this 'the way to go' to update the UI or is it 'not done'? The same question applies for the BackgroundWorker (Maybe just start a new thread instead of a BackgroundWorker?)

Revils
  • 1,478
  • 1
  • 14
  • 31
  • 1
    I just wanted to note that if you want to update the UI without freezing because of a background task, the usual way nowadays is the async-await method. – Xavier Peña Mar 27 '16 at 15:18

2 Answers2

3

If you need to update some UI components from a background thread you should use the Dispatcher in order to marshal the call to the main thread. This being said, you seem to be trying to update some progress bar. The BackgroundWorker class already provides a mechanism for that. So you can simply have a ProgressBar control on your form and then:

var bgWorker = new BackgroundWorker();

// Specify that this worker supports progress
bgWorker.WorkerReportsProgress = true;

bgWorker.OnProgressChanged += e => 
{
   // This is called on the main thread. It safe to update your UI components here
   myProgressBar.Value = e.ProgressPercentage;
};

bgWorker.DoWork += (s, e) => 
{ 
    // Do something long lasting
    for(int i = 0; i < x; i++) {
        //Performing action i of x

        // While doing so notify the subscribers of the progress event
        var progress = (int)((i / x) * 100.0);
        bgWorker.ReportProgress(progress);
    }
};  

bgWorker.RunWorkerCompleted += (s, e) => 
{ 
    //Finish up things
}; 

bgWorker.RunWorkerAsync();
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
1

No, it is not. THe main issue is your progress bar - it is craeted on the background worker thread, not the UI thread. It also is never really hanging on anything - where is it shown?

The proper way is to have a form that contains the progress bar, and to open it in the UI thread (or start shoting it just) BEFORE starting the background worker, then hide it on completed.

The update logic with Dispatcher is "correct" although it at the moment hits a not-properly initialized progress bar. But the invoke is what you have to do.

TomTom
  • 61,059
  • 10
  • 88
  • 148