WPF is really awesome to build reactive applications and data binding is here to push useful information inside of the User Interface. All is done magically and it’s wonderfully simple to create an application without knowledge of the internals of the WPF’s rendering.
Now, I wan’t to talk about something which can useful in every WPF application : how to wait for the rendering UI to be done. This can also be rephrased to : “how to force the rendering after I performed an action ?“.
Why would I need this ?
You can find a lot of reasons to need this:
- You are doing a long-running job that can only be done on the UI thread (good bye BackgroundWorker) and you want to tell the user the progress of the task.
- The rendering of a control takes a lot of time to be done and you want to be sure that the “wait please” Textblock” is rendered instead of a white screen.
- You need to wait that the UI rendering following an action is done.
- You are a geek and you want to know how you can do this !
You are adding a lot of items to a binded collection and you want to wait for the rendering of each added item to be done. By doing this, the data won’t seems to be push into the ItemsControl by packet but one by one. No apparent freeze of the UI.As pointed out by a lot of people, there is really better ways to do this.
Here is a non-exhaustive list of things that can only be done on the UI-Thread and which are time-consuming (if you have some others, please give me them in the comments):
- Create UI controls may be long(exemple),
- Im my previous project using Mogre 3D, I needed to initialize some parts of the 3D engine in the main UI Thread,
- Sometimes applying the content to a view is very long because the XAML is really complex (more to come on this in a later post),
- etc.
Please tell me how can I do this !
What is wonderful is that the solution takes only one little line of code. One line of code.
To keep it simple, the rendering of the UI is perform on the UI thread via the Dispatcher. It can be considered as a tasks processer, each of these task being assigned a priority. The rendering of the UI is one of these tasks and all you have to do is tell the Dispatcher: “perform an action now with a priority less than the rendering”. The current work will then wait for the rendering to be done.
Here is the snippet this sentence transposing in .Net:
[csharp]Dispatcher.Invoke(new Action(() => { }), DispatcherPriority.ContextIdle, null);[/csharp]
I promised: only one line of code.
The code starts an empty action via the Dispatcher’s Invoke method. The priority given to the Dispatcher is ContextIdle which is lesser that Render so the Dispatcher will wait for the rendering to be done before to execute the empty action(I agree that waiting to do nothing is quite strange but.. 🙂 ).
Because the call to Invoke is blocking, your code won’t go on until the rendering is effectively done.
That is exactly what is required.
Wait… there is no drawback ?
Of course there is! And a big one named ‘performance’. By doing the calls to Dispatcher.Invoke, you are forcing a switch between thread execution and it costs a lot of processing which can be disastrous in term of performance. My disclaimer is so: do this only when necessary, really necessary.
By the way, you can quite easily limit the occurrence of the context switches by doing the call every X(where X can be 5…) added items instead of after each item add.
One more thing
I discovered that when I use this technique inside of the Loaded event handler of a Windows, it’s content was staying white until the long-running job stops. To make it work, I started the job in the ContentChanged method to be sure the content is rendered once first. Notice that it’s necessary only when you need to execute a long-running job on the UI-thread.
[csharp] protected override void
OnContentChanged(object oldContent, object newContent)
{
base.OnContentChanged(oldContent, newContent);
Dispatcher.BeginInvoke(new Action(MyLongProcessing), null);
}[/csharp]
That’s all for today, feel free to add comments 🙂
31/08/2011 20 h 23 min
Thanks for posting, it could come in handy someday… This technique is actually quite similar to the Application.DoEvents method in WinForms.
BTW, you don’t need to specify the delegate type when you call Invoke: the DispatcherExtensions class provides overloads of Invoke that take an Action as parameter http://msdn.microsoft.com/en-us/library/system.wi…
31/08/2011 19 h 28 min
Thanks for the comment and your addition which is really useful !
28/03/2012 17 h 54 min
Today is that day for me 🙂
Thanks btw, Jonathan.
28/03/2012 18 h 57 min
You are welcome !
03/02/2012 15 h 49 min
The technique of using the Dispatcher to invoke an empty method at the ContextIdle priority will work, however you should beware of a potential side effect.
As soon as you Invoke at priority Input (or below, where ContextIdle is), the thread's message queue will be pumped and you could introduce reentrency if you are not specifically guarding against it.
For example, if you make the Invoke call in a button click handler, any additional button click events that are pending will get serviced before the empty Action routine is run.
You can guard against these problems, but you need to be aware that it could happen if the user starts clicking hard and fast while your update logic is running.
On the other hand, if you attempt to Invoke at a priority above ContextIdle, the render updates won't take effect.
30/03/2012 15 h 05 min
Thanks for the info.
I think it is close to : http://geekswithblogs.net/NewThingsILearned/archi….
But I prefer this link because it only force "Render" priority instead of "ContextIdle" priority.
30/03/2012 15 h 14 min
Thank your for your comment and visiting my blog !
16/04/2012 4 h 54 min
Nice, I used it for my 3D rendering http://alloysvisualisation.codeplex.com/, null is not unnecessary, though.
12/04/2013 5 h 38 min
Thanks for the great article.
I was wondering if a similar technique can be applied in a Silverlight application. The same scenario is very common in Silverlight also, when you need to wait untill the UI rendering is finished but I could not find any solution. The suggested method can not be applied as Silverlight does not support DispatcherPriority.
22/08/2014 11 h 20 min
Any idea how I would do this in VB.NET? I'm banding my hand to have this achieved… Thanks!
08/12/2015 15 h 27 min
Dispatcher.CurrentDispatcher.Invoke(New Action(Sub()
End Sub), DispatcherPriority.ContextIdle, Nothing)
Note that End Sub needs to be on a separate line from Sub().
14/01/2015 15 h 05 min
Thank you/ merci
J`avais vraiment désespéré à trouver une solution
24/02/2015 17 h 56 min
Doesn't work reliably from what I've observed, a hack.
29/06/2015 6 h 18 min
I actually delight in reading your blog post Update the
WPF UI now: how to wait for the rendering to finish ?
| Jonathan ANTOINE’s thoughts on WPF, Silverlight, WinRT, NUI….
20/10/2015 8 h 51 min
Thanks a lot!!!!! saved lots of time for me! thanks again!
06/02/2016 15 h 15 min
Very good! Clean and simple.
12/03/2016 19 h 40 min
It's an old post, but I just wanted to say thank you. I've been searching half a week for reason why a dispatched UI operation is not freed from memory which lead to kind of "memory leak".
Your example made it easy to pinpoint the line that caused the problem.
In the end there was one line which triggered very stealthy endless loop – everything functioned perfectly but the loop did not let go off some resources.