Syntactic sugar for multi-threading in Windows Forms

March 19, 2009

Today I’m sharing bits of code that we found useful while working on Windows Forms UI code with my customer.

In .Net, the BackgroundWorker provides a nice way to handle out-of-UI thread work while being able to report some progress on the UI side.

Sometimes though, we felt that we wanted something more flexible for our needs, and came up with this helper built as a Control extension method:

public delegate void Action();

public static void InUIThread(
    this Control control, Action action)
{
    if (control.InvokeRequired)
        control.EndInvoke(
            control.BeginInvoke(action));
    else
        action();
}

Some real use from a form:

class MyForm
{
    void SomeMethodRunningInABackgroundThread()
    {
        /* some processing ... */
        this.InUIThread(() => {
            statusBar.Text = newStatus;
        });
        /* more processing ... */
        this.InUIThread(() => {
            listBox.Items.Add(message);
        });
    }		
}

The reverse is also possible — running something in a worker thread from the UI:

public static void InWorkerThread(
    this Control control, Action action)
{
    BackgroundWorker worker = new BackgroundWorker();
    worker.DoWork += (sender, e) => action();
    worker.RunWorkerAsync();
    while (worker.IsBusy)
        Application.DoEvents();
}

We don’t pass arguments nor return values unlike other kinds of sugar for that. That’s because we use lambdas all over the place — parameters and return values can be accessed in the lambda’s parent scope directly.