Update the WPF UI now: how to wait for the rendering to finish ?

, , 19 Comments

UI first

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 🙂

 

19 Responses

  1. Guest

    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.

  2. Narek

    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.

  3. Peter

    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!

    • Donatello

      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().

  4. Kali

    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….

  5. no name here

    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.

Comments are closed.