Revils
Revils

Reputation: 1508

Using background worker and updating UI

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?)

Upvotes: 0

Views: 796

Answers (2)

Darin Dimitrov
Darin Dimitrov

Reputation: 1038720

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

Upvotes: 3

TomTom
TomTom

Reputation: 62093

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.

Upvotes: 1

Related Questions