简体   繁体   中英

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

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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM