Working with .NET Framework Task Parallel Library and Windows Presentation Foundation

Windows
Presentation Foundation (WPF)
embraced the power of DirectX and made the
GPU a first-class citizen on .NET. Task
Parallel Library (TPL)
has made .NET Parallel
Programming
more accessible. Separately WPF and TPL comprise great
leaps in developer productivity and application quality. Combine the two
technologies and a .NET developer mixes the full capabilities of a modern GPU
with the responsiveness that can only be achieved with asynchronous code.

Like all .NET technologies there are many approaches to
combining the classes within the .NET Framework. Using
some code samples I’m going to demonstrate how to incorporate TPL into WPF.

Sample Overview

The sample code simulates doing work with the Thread.Sleep
method and then updates a TextBox with the current time and date. Had the goal
been to write a synchronous solution, rather than asynchronous solution, the
code would have looked like the example below.

Thread.Sleep(4000);
_txtUpdate.Text = "Updated on " + DateTime.Now.ToString();

Of course, most users don’t like an unresponsive User
Interface. I’m not aware of many users who would tolerate a 4 second wait each
time they pressed a button. Therefore most developers opt for an asynchronous
version of the code above. The asynchronous version of the code above that
utilizes TPL appears below.

//Work to perform
Task<string> doWork = new Task<string>(() =>
	{
		Thread.Sleep(4000);
		return "Updated on " + DateTime.Now.ToString();
	}
);

//Update the Text value
Action<Task<string>> toUpdate = t =>
{
	try{ _txtUpdate.Text = t.Result;}
	catch (Exception ex)
	{
	Debugger.Break();
	}
};

//Link the two
doWork.ContinueWith(toUpdate, TaskScheduler.FromCurrentSynchronizationContext());
//Schedule the work and return from the push button event
doWork.Start();

At first glance it may appear that the code complexity grew
a magnitude or two. In reality most of the additional code was added so the
two lines appearing in the synchronous example could be executed by TPL. To
execute code in TPL a developer must divide the work into Tasks.

Tasks

A complete review of the Task class is beyond the scope of
this article. You’ll find more information in this article on ‘Understanding
Tasks in .NET Framework 4.0 Task Parallel Library
‘. Though there is more
to a Task class; Tasks can be considered a wrapper for a Delegate. I like to
think of Tasks as TPL units of work.

The sample utilizes two Tasks. The first Task executes the
simulated work and the second Task updates the User Interface. Later in the
article I’ll address why two Tasks were required.

TPL executes a Task on a ThreadPool managed by a
TaskScheduler class. TaskSheduler decides where and when to execute a Task. Like the sample, most applications use the default TaskScheduler that
accompanies the default ThreadPool. .NET supports multiple TaskShedulers and
even custom TaskSchedulers. In fact the sample leverages the default
TaskScheduler and a second TaskScheduler designed for applications built on
WPF. I’ll discuss the second TaskScheduler later in the article.

Developers accustomed to using the Asynchronous
Programming Model (APM)
; probably wondered why it was not used in the
sample. There was no point to leveraging APM. TPL capabilities covered what
was previously done using APM.

The results of the simulated work Task is joined to the User
Interface update with a call to the ContinueWith method. ContinueWith creates
a Continuation.

Continuations

A complete explanation of Continuations is beyond the scope
of this article. You can find more information on Continuations in this
article on ‘Microsoft .NET Framework 4.0 Task Parallel Library Continuations‘.

I think of a Continuation as a way to link the results of
one executing Task to the results of another Task, much the way a developer
makes a callback when a dependent operation completes. ContinueWith has a
variety of overloads. The sample utilizes an overload that would commonly be
selected for doing work that updates the User Interface.

The first part of the sample ContinueWith overload accepts
an Action tied to a Task class. With access to the sample workload target Task
class, the update UI code retrieves the result of the Task class. The Result
is a string containing the DateTime information.

The second parameter in the ContinueWith overload accepts a
TaskScheduler. The sample gets a TaskScheduler tied to the
SynchronizationContext.

SynchronizationContext

Earlier I mentioned that there was a reason for dividing the
work into two Tasks. WPF UI elements can only be updated from the Thread they
were created in. This is called Thread Affinity. The default TaskScheduler
executes Tasks on Threads in the ThreadPool. Because of Thread Affinity the UI
update Task had to execute on the Thread attached to the WPF
DispatcherSynchronizationContext.

A complete explanation of the Dispatcher and the underlying
WPF SchronizationContext is beyond the scope of this article, but you’ll find
more information among the resources at the end of the article.

Task.Start hands the Task off to TPL and the appropriate
scheduler.

If all the additional TPL code seemed a bit heavy; rest
assured a better way is in the works.

Async – The Future

Coming in future versions of C#
and VB.NET
are Asyc keywords that accomplish what was done in the sample code with a few
additional lines of code beyond the synchronous example. You can read more
about how to do what the new Async language features in this article on ‘Awaiting
Future C# Asynchronous Features Brought to you by .NET Parallel Computing
‘.

Conclusion

Windows Presentation Foundation made the power of DirectX
more widely available to .NET developers. Task Parallel Library has made
asynchronous coding more accessible to .NET developers. Using new TPL
techniques and classes like Continuations and TaskSchedulers, a developer can
execute WPF code asynchronously without relying on the Asynchronous Programming
Model.

Resources

Task
Schedulers

It’s all About
the SynchronizationContext

Build More
Responsive Apps with the Dispatcher

More by Author

Must Read