简体   繁体   中英

BackgroundWorker updating GUI without ProgressChanged in WPF

I have a programm (WPF) which performs measurements every, lets say, 10 seconds. The measurement time varies, so it could take 1 second or maybe 3 seconds, eg:

|o........|..o......|o........|...o.....|o..

|...measurement start   o...measurement finished

I want to have a ProgressBar, which shows when the next measurement task starts. Also, everytime a measurement is finished, i add the values to a graph element to display them.

Now here is the Problem: I have a BackgroundWorker which checks if its time to perform a measurement. If its time, the BackgroundWorker starts other Workers which perform the measurement.

Right now i have just implemented the function to show the data when the measurement is completed using the "bw.ReportProgress(0)" (the 0 is a dummy value with no use):

private void measure_interval_worker_DoWork(object sender, DoWorkEventArgs e)
{
        BackgroundWorker bw = sender as BackgroundWorker;
        DateTime timeToMeasure = DateTime.Now; 
        Boolean varsSaved = true; //if vars are saved

        while (!measure_interval_worker.CancellationPending)
        {                

            if (activeDevices.Count == 0 && varsSaved == false) //Devives are finished and vars aren't save yet
            {
                bw.ReportProgress(0); //In ProgressChanged the values are displayed
                varsSaved = true;
            }

            if (DateTime.Now >= timeToMeasure && activeDevices.Count == 0) //If its time to measure and all devices are done with measurement
            {
                timeToMeasure = DateTime.Now + measure_gap; //Next time to measure
                measure_workers = new List<BackgroundWorker>(); //Deleting the "old" workers?


                foreach (var dev in devices)
                {
                    //Add Key
                    varsSaved = false;
                    activeDevices.Add(dev.Key);

                    //And start worker
                    measure_workers.Add(new BackgroundWorker());
                    measure_workers[measure_workers.Count - 1].DoWork += measure_perform_DoWork;
                    measure_workers[measure_workers.Count - 1].RunWorkerAsync(dev.Key);
                }
            }
        }
    }

activeDevices is just a list where the measure_workers delete their names if they are done so a activeDevices.Count == 0 means that all measurement tasks are done.

I tried to use a dispatcher now for the progressbar like:

this.Dispatcher.BeginInvoke((Action)delegate()
            {
                pbProgress.Value = (int)((timeToMeasure - DateTime.Now).TotalSeconds/ measure_gap.TotalSeconds * 100);
            });

(placed it inside the measure_interval_worker while loop) but now if i start the measure_interval_worker the GUI freezes.

So how can i solve this?

I could use the ReportProgress for the ProgressBar but then i had the same problem for displaying the data because i dont know when the values are ready to display.

activeDevices is most probably not thread-safe. If it is a List<T> it's surely not. Use a ConcurrentBag, for example.

Furthermore, you shouldn't create a BackgroundWorker from another backgroundworker's DoWork method. It will not work as expected (because it's not created from the GUI thread).

The BackgroundWorker is a quick and easy way to use multi-threading in .NET, but it might not be the best candidate in your scenario. Anytime you want something more than the BackgroundWorker class offers, then you'll need to look into using either the Task class in .NET 4.0, or the new async and await keywords in .NET 4.5.

Using these classes, you will be able to run all of your measurements together and have the UI update their progress asynchronously. You can find out how to use them in the following pages on MSDN:

Start Multiple Async Tasks and Process Them As They Complete (C# and Visual Basic)
Asynchronous Programming with Async and Await (C# and Visual Basic)

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