WPF developers cannot avoid using the
Dispatcher class. When we have to access controls or other UI parts on other threads (not
UI thread), we should use
Dispatcher.Invoke method. Also,
Dispatcher can be used to delay a task until the current task is executed.
Developers often used
Dispatcher.BeginInvoke in the past. And Microsoft adds a new method which’s name is
.NET Framework 4.5.
Are there any differences between these methods? And how does
The original link is 深入了解 WPF Dispatcher 的工作原理（Invoke/InvokeAsync 部分）. But this blog was written in Chinese, so I translate its content to English. Waterlv is an MVP(Microsoft Most Valuable Professional), and he is good at .NET Core\WPF\.NET. Here is his Blog.
BeginInvoke method has existed when the
Dispatcher class is added in the
.NET framework 3.0. Are you familiar with
Begin prefix? Yes, it is the
Begin\End asynchronous programming model(APM) which is introduced in
.NET Framework 1.1. Although
BeginInvoke is not completely implemented according to the APM model(there is no End and no
IAsyncResult result), but this method is also thread-related. Not only does the name carry
Begin for the means of asynchronous execution, but there are still ancient types like
Delegate in the parameter list. All the details above show that the
BeginInvoke method is an old API.
Every developer is still feeling excited about the
async/await asynchronous model which was introduced in
.NET Framework 4.5‘s updates. This model allows developers to write asynchronous codes as simple as synchronous codes. This is a new asynchronous programming model which is recommended by Microsoft, and its name is
TAP (Task-based Asynchronous pattern). And
Dispatcher.InvokeAsync was introduced in this version. So, what are the differences between
Firstly, we should read the source codes of these methods.
There are five overload methods, and it is easy to find that three of them are marked by special attribute to make them invisible in IntelliSense list (but you can find them when you use ReSharper). Are there any differences among these methods? The answer is NO. After reading these methods’ code, we can find that they all call the same method named
LegacyBeginInvokeImpl. Here is the code of the method.
And its name’s prefix
Legacy gives us some information about Microsoft’s altitude this method. It probably means Microsoft does not want to maintain this code anymore. Maybe, a few years later it will be marked as an
Here is the code of
public DispatcherOperation InvokeAsync(Action callback);
This is what the TAP code looks like. After reading these method’s code we can find that the implementation of these methods is almost the same. Here, I post the third method’s source code.
What is the feeling when you read these codes? Yeah, there must be a voice in your mind and it says that ‘I read them before’. They are almost the same as
Finally, we knew the answer to why Microsoft recommended
InvokeAsync instead of
BeginInvoke. Microsoft had changed
BeginInvoke‘s implementation to TAP model but didn’t change its name and the parameters list in
NET Framework 4.5. So, they added another six methods(
InvokeAsync), and these all methods above do the same thing.
BeginInvoke has the same codes, we don’t have to introduce both methods. So, in the following paragraphs, we are going to introduce more details about
All information above told us that the core of the
InvokeAsync method is
InvokeAsyncImpl. Here are the steps of the
DispatcherOperation.Therefore, the task and priority we passed will be processed together;
DispatcherOperationto a queue of
PriorityQueue<DispatcherOperation>. This queue implements a
SortedListclass, every time it pops a task is depending on its priority.
RequestProcessing, send a message to a hidden window at last.
When the hidden window received that message, it will take a task from the
PriorityQueueand execute it. (The real situation is more complicated, all details will be shown below).
In this progress, it calls
TryPostMessage to send messages. Here is the method’s code.
UnsafeNativeMethods.TryPostMessage(new HandleRef(this, _window.Value.Handle), _msgProcessQueue, IntPtr.Zero, IntPtr.Zero);
It is important to notice that there is a
_window, but what does this
_window mean? After reading the constructor of the
Dispatcher class, we found this
_window. It is not the
Window class we usually know, it a hidden window of
Win32, and its usage is to send and receive the schedule message of the
Dispatcher class. For more details about this window, visit
MessageOnlyHwndWrapper‘s source code, and you will find it calls
UnsafeNativeMethods.CreateWindowEx method to create this window in its base class
Since it can send a message to
_window, it is natural to
Hook its message handler, like this:
// Create the message-only window we use to receive messages
WndProcHook method, it handles three types of messages.
- Close the hidden window (
- Handle the scheduled task of the
Dispatcherclass (this message is registered at the static constructor method of
Why does it handle the message about the timer?
After researching, it is clear that Microsoft split all priorities into three types.
- Foreground priority (from
DispatcherPriority.Send, the number is 6 to 10).
- Background priority (from
DispatcherPriority.Send, the number is 4 to 5).
- Idle priority (from
DispatcherPriority.ApplicationIdle, the number is 1 to 3)
But, it needs to notice that the
Background priority and
Idle priority are treated as one type of priority in Microsoft’s code. So, in fact, there are just two types of priority, the
Background. And there is one point to distinguish them is user’s input.
If a user’s input occurs, a timer will be turned on, and during this time interval, all
Background priority tasks will not be executed. But
Foreground priority tasks will not be affected by the user’s inputs. Therefore, the user’s inputs will not be starved, and the WPF application will not be stuck from the input level.
It’s important to notice that
InvokeAsync is implemented according to the
TAP asynchronous model, and this method can be used with
await. How does it work?
After reading the source code of
InvokeAsync which is posted above, we noticed that the return value of the
InvokeAsync method is an instance of
DispatcherOperation. This instance is created at the beginning of the codes.
DispatcherOperation operation = new DispatcherOperation(this, priority, callback); There is an
Invoke method without a return value, but it will change the result of
Task. And the
DispatcherOperation class has implemented the
GetAwaiter method so we can use
await before this method.
For more information about
await, see How to write a custom awaiter – Lucian’s VBlog.
If you think the theory of
Invoke is easier than
InvokeAsync, probably you may ignore a very import question -
deadlock. If the
Invoke implemented according to the
Synchronous wait method, the UI thread will be blocked when it calls the
Invoke method on the current thread. And the
Action passed by
Invoke method will be executed on UI thread, but this thread is blocked, so
Invoke method must have other implementation, and there are two branches for this implementation developed by Microsoft.
If the task’s priority is the highest priority (the number is 10), it will call the
If the task’s priority is lower than 10, it will call
DispatcherOperation.Waitmethod to wait.
Here is a part of the source code of
public DispatcherOperationStatus Wait(TimeSpan timeout)
In this method above, it calls
Dispatcher.PushFrame, and this method can wait without blocking the thread. For more theories visit Learn more about how WPF Dispatcher works.(Part 2 - PushFrame).
- We recommended using
BeginInvokeif your application’s framework version is higher than 4.5.
Invoketasks by priority by creating a hidden message window.
Invokemethod avoids blocking UI thread by the
- Asynchronous model
- WPF message mechanism