ParallelWork: Feature rich multithreaded fluent task execution library for WPF

ParallelWork is an open source free helper class that
lets you run multiple work in parallel threads, get success,
failure and progress update on the WPF UI thread, wait for work to
complete, abort all work (in case of shutdown), queue work to run
after certain time, chain parallel work one after another.
It’s more convenient than using .NET’s
BackgroundWorker because you don’t have to declare one
component per work, nor do you need to declare event handlers to
receive notification and carry additional data through private
variables. You can safely pass objects produced from different
thread to the success callback. Moreover, you can wait for work to
complete before you do certain operation and you can abort all
parallel work while they are in-flight. If you are building highly
responsive WPF UI where you have to carry out multiple job in
parallel yet want full control over those parallel jobs completion
and cancellation, then the ParallelWork library is the right
solution for you.

I am using the ParallelWork library in my PlantUmlEditor
project, which is a free open source UML editor built on WPF. You
can see some realistic use of the ParallelWork library
there. Moreover, the test project comes with 400 lines of Behavior
Driven Development flavored tests, that confirms it really does
what it says it does.

The source code of the library is part of the
“Utilities” project in PlantUmlEditor
source code hosted at Google Code.

The library comes in two flavors, one is the ParallelWork
static class, which has a collection of static methods that you can
call. Another is the Start class, which is a fluent wrapper
over the ParallelWork class to make it more readable and
aesthetically pleasing code.

ParallelWork allows you to start work immediately on
separate thread or you can queue a work to start after some
duration. You can start an immediate work in a new thread using the
following methods:

  • void StartNow(Action doWork, Action onComplete)
  • void StartNow(Action doWork, Action onComplete,
    Action failed)

For example,

ParallelWork.StartNow(() =>
{
    workStartedAt = DateTime.Now;
    Thread.Sleep(howLongWorkTakes);
},
() =>
{
    workEndedAt = DateTime.Now; 
});

Or you can use the fluent way Start.Work:

Start.Work(() =>
    {
        workStartedAt = DateTime.Now;
        Thread.Sleep(howLongWorkTakes);
    })
    .OnComplete(() =>
    {
        workCompletedAt = DateTime.Now;
    })
    .Run();

Besides simple execution of work on a parallel thread, you can
have the parallel thread produce some object and then pass it to
the success callback by using these overloads:

  • void StartNow(Func doWork, Action
    onComplete)
  • void StartNow(Func doWork, Action
    onComplete, Action fail)

For example,

ParallelWork.StartNow<Dictionary<string, string>>(
    () =>
    {
        test = new Dictionary<string,string>();
        test.Add("test", "test");

        return test;
    },
    (result) =>
    {
Assert.True(result.ContainsKey("test"));
});

Or, the fluent way:

Start<Dictionary<string, string>>.Work(() =>
    {
        test = new Dictionary<string, string>();
        test.Add("test", "test");

        return test;
    })
    .OnComplete((result) =>
    {
        Assert.True(result.ContainsKey("test"));
    })
    .Run();

You can also start a work to happen after some time using these
methods:

  • DispatcherTimer StartAfter(Action onComplete, TimeSpan
    duration)
  • DispatcherTimer StartAfter(Action doWork,Action
    onComplete,TimeSpan duration)

You can use this to perform some timed operation on the UI
thread, as well as perform some operation in separate thread after
some time.

ParallelWork.StartAfter(
    () =>
    {
        workStartedAt = DateTime.Now;
        Thread.Sleep(howLongWorkTakes);
    },
    () =>
    {
        workCompletedAt = DateTime.Now;
    },
    waitDuration);

Or, the fluent way:

Start.Work(() =>
    {
        workStartedAt = DateTime.Now;
        Thread.Sleep(howLongWorkTakes);
    })
    .OnComplete(() =>
    {
        workCompletedAt = DateTime.Now;
    })
    .RunAfter(waitDuration);

There are several overloads of these functions to have a
exception callback for handling exceptions or get progress update
from background thread while work is in progress. For example, I
use it in my PlantUmlEditor to
perform background update of the application.

// Check if there's a newer version of the app
Start<bool>.Work(() =>
{
    return UpdateChecker.HasUpdate(Settings.Default.DownloadUrl);
})
.OnComplete((hasUpdate) =>
{
    if (hasUpdate)
    {
        if (MessageBox.Show(Window.GetWindow(me),
            "There's a newer version available. 
Do you want to download and install?"
, "New version available", MessageBoxButton.YesNo, MessageBoxImage.Information) == MessageBoxResult.Yes) { ParallelWork.StartNow(() => { var tempPath = System.IO.Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), Settings.Default.SetupExeName); UpdateChecker.DownloadLatestUpdate(Settings.Default.DownloadUrl, tempPath); }, () => { }, (x) => { MessageBox.Show(Window.GetWindow(me), "Download failed. When you run next time,
it will try downloading again."
, "Download failed", MessageBoxButton.OK, MessageBoxImage.Warning); }); } } }) .OnException((x) => { MessageBox.Show(Window.GetWindow(me), x.Message, "Download failed", MessageBoxButton.OK, MessageBoxImage.Exclamation); });

The above code shows you how to get exception callbacks on the
UI thread so that you can take necessary actions on the UI.
Moreover, it shows how you can chain two parallel works to happen
one after another.

Sometimes you want to do some parallel work when user does some
activity on the UI. For example, you might want to save file in an
editor while user is typing every 10 second. In such case, you need
to make sure you don’t start another parallel work every 10
seconds while a work is already queued. You need to make sure you
start a new work only when there’s no other background work
going on. Here’s how you can do it:

private void ContentEditor_TextChanged(object sender, EventArgs e)
{
  if (!ParallelWork.IsAnyWorkRunning())
  {
     ParallelWork.StartAfter(SaveAndRefreshDiagram,
                                 TimeSpan.FromSeconds(10));
  }
}

If you want to shutdown your application and want to make sure
no parallel work is going on, then you can call the
StopAll() method.

ParallelWork.StopAll();

If you want to
wait for parallel works to complete without a timeout, then you can
call the WaitForAllWork(TimeSpan timeout). It will block the
current thread until the all parallel work completes or the timeout
period elapses.

result = ParallelWork.WaitForAllWork(TimeSpan.FromSeconds(1));

The result is
true, if all parallel work completed. If it’s false, then the
timeout period elapsed and all parallel work did not complete.

For details how this library is built and how it works, please
read the following codeproject article:

ParallelWork: Feature rich multithreaded fluent task
execution library for WPF

http://www.codeproject.com/KB/WPF/parallelwork.aspx

If you like the article, please vote for me.

Open Source WPF UML Design tool

PlantUmlEditor is my
new free open source UML designer project built using WPF and .NET
3.5. If you have used plantuml before, you know
that you can quickly create sophisitcated UML diagrams without
struggling with a designer. Especially those who use Visio to draw
UML diagrams (God forbid!), you will be at heaven. This is a super
fast way to get your diagrams up and ready for show. You can
*write* UML diagrams in plain English, following a simple syntax
and get diagrams generated on-the-fly.

This editor really saves time designing UML diagrams. I have to
produce quick diagrams to convey ideas quickly to Architects,
Designers and Developers everyday. So, I use this tool to write
some quick diagrams at the speed of coding, and the diagrams get
generated on the fly. Instead of writing a long mail explaining
some complex operation or some business process in English, I can
quickly write it in the editor in almost plain English, and get a
nice looking activity/sequence diagram generated instantly. Making
major changes is also as easy as doing search-replace and
copy-pasting blocks here and there. You don’t get such agility in
any conventional mouse-based UML designers.

PlantUML editor screencast

I have submited a full codeproject article to give you a detail
walkthrough how I have built this. Please read this article and
vote for me if you like it.

PlantUML Editor: A fast and simple UML editor using WPF

http://www.codeproject.com/KB/smart/plantumleditor.aspx

You can download the project from here:

http://code.google.com/p/plantumleditor/