WPF 4.5 – Part 3 : New methods of the Dispatcher

, , 6 Comments

This is the third part of the serie on the WPF 4.5 new features.

The Dispatcher class is maybe one of the most used in WPF when you start doing thing asyncronously. It is the only way to update UI controls from an another thread.

Even if it was easy to use, the WPF teams added 13 methods which will ease up this. Especially with the new await keyword. In this post we will discover these new methods.

The new ‘classic’ methods

There is some overload which takes as a param a Func delegate. Where in prior versions, the available methods on the Dispatcher were not able to return something (except void) it is now possible.

The new methods of this kind are :

  • Invoke(Func)
  • Invoke(Func, DispatcherPriority)
  • Invoke(Func, DispatcherPriority, CancellationToken)
  • Invoke(Func, DispatcherPriority, CancellationToken, TimeSpan)

Prior to WPF 4.5, to return something, this code should have been written:
[csharp]//The function which returns something (here of type object)
Func<object> myReturningObjectFunction = () =>
{//For example only !
return new object();
};

object returnedOject = null;

//A mock action to be abble to return the object
Action mockAction = () => { returnedOject = myReturningObjectFunction(); };

//Actually invoke the method
Dispatcher.CurrentDispatcher.Invoke(mockAction, null);

//Here I can use the returned object
[/csharp]

Now, you can write a more maintanable code by using this one:
[csharp]public void CallingMethod()
{
object returnedOject = Dispatcher.CurrentDispatcher
.Invoke(MyReturningObjectFunction, null);
}

//This method can now live alone !
private object MyReturningObjectFunction()
{
//For example only !
return new object();
}
[/csharp]

Await-ready !

You surely are aware of the new-born ‘await’ keyword.
The WPF team is too and the Dispatcher is now await-ready !

Here is the new methods which are await-ready:

  1. InvokeAsync(Action)
  2. InvokeAsync(Action, DispatcherPriority)
  3. InvokeAsync(Action, DispatcherPriority, CancellationToken)
  4. InvokeAsync(Func)
  5. InvokeAsync(Func, DispatcherPriority)
  6. InvokeAsync(Func, DispatcherPriority, CancellationToken)

These method returns objects of the DispatcherOperation/DispatcherOperation type.
You can then use the await keyword on it or on its ‘Task’ property.
Here is an example:
[csharp]public async void CallingMethod()
{
await Dispatcher.CurrentDispatcher.InvokeAsync(MyReturningObjectFunction);
}
[/csharp]

Also, you can do some synchronisation and wait for a Dispatcher operation to be finished by using the DispatcherOperationWait method on the task. This is an extension method of the TaskExtensions class (available on System.Windows.Threading).
[csharp]DispatcherOperation<object> dispatcherOperation =
Dispatcher.CurrentDispatcher.InvokeAsync(MyReturningObjectFunction);

dispatcherOperation.Task.Wait();
[/csharp]

There is a disclaimer/warning on this last one “Calling Task.Wait will result in a deadlock if the operation is queued on a calling thread. For more information about using a Task to perform asynchronous operations, see Task Parallelism (Task Parallel Library).”

Cancellation

Finally, you may have noticed the new parameter of type CancellationToken.
This is part of the .NET 4 Cancellation Framework.
Under the hood, the Dispatcher operation you start creates a Task object which will be regulated by this cancellation token.
If the Task has not started, ie. your dispatcher operation has not, then it won’t start. If it has started it won’t be stopped and then continue its execution.

In fact, it’s up to the task’s action to check the cancellation token to stop itself. However, I didn’t find a way to pass the Cancellation token to the given Action instead of using the same trick I presented on the first paragraph about the returned object. 🙁

I didn’t find a scenario in which using the cancellation token is necessary but I think it’s coming from the things necessary to make the async keyword work.

This kind of scenario is a bit hard to reproduce in a demo but I managed to get a working example:
[csharp]//Create a token source
var cts = new CancellationTokenSource();

//Launch the cancel of the token
Task.Factory.StartNew(() => cts.Cancel());

//Launch an operation with priority normal
// this will delay the execution of the following Invoke call.
Dispatcher.BeginInvoke(new Action(() =>
{
int i = 0; while (i < 300)
//Update the UI to be sure to block the following
// action. Rendering will occur and takes precedence
{ i++; _counterTextBlock.Text = i.ToString(); }
}), null);

try
{
//Launch a task with the cancellation token
Dispatcher.Invoke(() => { while (true);},
DispatcherPriority.Background, cts.Token);
}
catch (OperationCanceledException ex)
{
//We are here because the token was cancelled
Console.WriteLine("The operation didn’t even start !");
}
[/csharp]

Bonus

As a bonus you also have two new methods which add nothing special except an easier use :

  1. Invoke(Action)
  2. Invoke(Action, DispatcherPriority, CancellationToken, TimeSpan)

You can also find the Dispatcher documenation on MSDN.

Regards,

 

6 Responses

  1. Thomas Levesque

    20/09/2011 22 h 50 min

    It was already possible to return something from Dispatcher.Invoke : the method takes a Delegate and returns an Object. It was just not very convenient, because you had to specify the delegate type explicitly, and cast the result to the appropriate type. They just added generic overloads that take a Func to make it more convenient.

    As for the overloads that take an Action, they were already available through extension methods defined in the DispatcherExtensions class <a href="http://(http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcherextensions.aspx)” target=”_blank”>(http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcherextensions.aspx). The fact they’re now instance methods shouldn’t break existing code that uses the extension methods, since instance methods always take precedence over extension methods.

    Anyway, these new methods should make life easier for us 🙂

Comments are closed.