Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

How to Create a Time Based & Cancelable BackgroundWorker for Windows Phone (and Others)

DZone's Guide to

How to Create a Time Based & Cancelable BackgroundWorker for Windows Phone (and Others)

· Mobile Zone
Free Resource

Download this comprehensive Mobile Testing Reference Guide to help prioritize which mobile devices and OSs to test against, brought to you in partnership with Sauce Labs.

backgroundworkerTimebased

While working on my current project, I needed a solution for a running code with a time offset. Well, you might say, no problem after all, and it is true.

The challenge at this point was to find a way to keep it cancelable at any time. And so the fun started.

After digging a bit deeper into the MSDN documentation, the BackgroundWorker class already have a bunch of methods and properties that are very helpful for this case.

As it is always the case when you work with multiple threads, it can cause some headache. But I got around it and thought it might be helpful for some of you.

Here is how I solved the scenario:

First, declare a static BackgroundWorker so you need to set it up only once on the page you want to use it. In the Loaded or OnNavigatedTo event, we are instantiating our BackgroundWorker.

worker = new BackgroundWorker();
worker.WorkerSupportsCancellation = true;
worker.WorkerReportsProgress = true;

Now, let’s add two very important properties: WorkerSupportsCancellation and WorkerReportsProgress. Both need to be set to true, otherwise you will get one InvalidOperationException after the other when running the code.

In my case, I created a separate method to start the BackgroundWorker and hook up to all important events:

private void RunBackgroundWorker()
        {
            worker.RunWorkerCompleted += worker_RunBackgroundWorkerCompleted;

            //delegating the DoWork event
            worker.DoWork += ((s, args) =>
            {
                //generating a loop
                for (int i = 0; i < 100; i++)
                {

                    if (worker.CancellationPending == true)
                    {
                        //set cancel to true to finish the cancellation on the next run in the loop
                        args.Cancel = true;
                    }
                    else
                    {
                        //calculate your time: seconds * 1000 / 100
                        Thread.Sleep(50);
                        worker.ReportProgress(i);
                    }
                }
            });

            //can be used to fill a progress bar/show percentage
            worker.ProgressChanged += worker_ProgressChanged;

            //start the BackgroundWorker
            worker.RunWorkerAsync();
        }

You might notice that I created a loop that runs up to 100. This is necessary for my solution, as this is the key to make the BackgroundWorker cancelable in my solution. Every 50 milliseconds, the CancellationPending property gets checked as I am looping through until the count reaches 100.  I am setting an offset of 50 milliseconds, as I want to have an offset of 5 seconds.

Next, let us set up a button that cancels the background task (can be used in other events/methods, too):

public void CancelButton_Click(object sender, RoutedEventArgs e)
{
    //check this always to avoid InvalidOperationExceptions
   if (worker.WorkerSupportsCancellation == true)
   {
         //request cancellation of the BackgroundWorker
         //this sets the CancellationPending property to true
        worker.CancelAsync();
    }
 }

Important: Always check if the Cancellation is supported by your BackgroundWorker to avoid those ugly InvalidOperationExceptions. Then, simply call the CancelAsync() method of your BackgroundWorker to set the CancellationPending property to true.

When the BackgroundWorker has completed (or cancelled), the value of the CancellationPending property is passed to the RunBackgroundWorkerCompletedEvent, where you can simply use the e.Cancelled property to continue your code (which will then be back on your main application thread):

private void worker_RunBackgroundWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if (e.Cancelled == true)
    {
       //your code in case the BackgroundWorker was cancelled
    }
    else
    {
       //your code in case the BackgroundWorker was running until the end
    }
}

The last event I want to mention is the ProgressChanged event. It can be used to display a percentage or similar things, I just use it to see when the cancellation gets active:

private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
     //your code here, for example display percentage or fill a progress bar

     //use the line below to check the percentage and if CancellationPending property gets changed
     //Debug.WriteLine(e.ProgressPercentage + "  " + worker.CancellationPending);
}

With this few methods we can create a time based  offset on a BackgroundWorker while keeping it cancelable at any time. The code above  should work in similar form also on other platforms like Windows 8 or Xamarin.

As always, I hope this will be helpful for some of you.

Happy coding!

Analysts agree that a mix of emulators/simulators and real devices are necessary to optimize your mobile app testing - learn more in this white paper, brought to you in partnership with Sauce Labs.

Topics:

Published at DZone with permission of Marco Siccardi, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}