Sunday, September 18, 2011

Fire-and-forget background code execution

Finally, time for some code again.

In the course of writing some Windows Phone 7 apps for the Apps for Noord-Holland competition I've just hacked together a tiny class that wraps the BackgroundWorker class for one simpe case: you want a bit of code to execute in the background, fire-and-forget style:

var loadData = new peSHIr.BackgroundHelper(() =>
{
    // load something
    // load something else
    // and that's it, basically
});

So you're not really interested in giving the BackgroundWorker an argument, getting progress information, supporting cancellation, receiving a result or even when exactly the code is done running (by getting an event). You just want it to start now and eventually have it be done.

If you want/need this, here's a simple utility class you can use:

using System;
using System.ComponentModel;

namespace peSHIr
{
    public class BackgroundHelper
    {
        private Action work;
        private DoWorkEventHandler start;
        private RunWorkerCompletedEventHandler finish;
        private BackgroundWorker worker;

        public BackgroundHelper(Action executeInBackground)
        {
            work = executeInBackground;
            start = new DoWorkEventHandler(DoWork);
            finish = new RunWorkerCompletedEventHandler(WorkCompleted);
            worker = new BackgroundWorker();
            worker.DoWork += start;
            worker.RunWorkerCompleted += finish;
            worker.RunWorkerAsync();
        }

        private void DoWork(object sender, DoWorkEventArgs e)
        {
            if (work != null) work();
        }

        private void WorkCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            worker.DoWork -= start;
            worker.RunWorkerCompleted -= finish;
            worker = null;
            start = null;
            finish = null;
        }

        public bool IsBusy
        {
            get {
                return work != null && worker != null ? worker.IsBusy : false;
            }
        }
    }
}

Be sure to keep your multi-threading in order, though. So if the code stores something, use appropriate locking. Or if you access GUI elements, go through the proper Dispatcher. But that almost goes without saying, right? Also, error handling for the code you give this class is obviously left as an excercise for the reader. ;-)

Enjoy!

2 comments:

  1. @LocalJoost just pointed out that WinRT (Windows 8) does not include BackgroundWorker any more. Not a big problem: there you'd have to have to make an effort to write anything blocking anyway because the APIs are geared so heavily towards asynchronicity anyway..

    ReplyDelete
  2. After actually reading this code again I noticed event handlers aren't cleaned if you construct this utility with a null Action. Oh well, if you do that, you're asking for it. Correction left as exercise for the reader... ;-)

    ReplyDelete