Posts
47
Comments
79
Trackbacks
0
Refresh / Update WPF controls
Sometime in the past, a friend asked me how to update a control to show status while his code is doing a loop of stuff.  Essentially changing the text of a label (or sophisticatedly we can say a text-based progress bar).  In my past coding with MFC and WinForms, it's fairly easy enough, you just invalidate and do an update (Invalidate / UpdateWindow in MFC or Invalidate / Update in WinForms).  This approach also coincides with how Windows UI operate, where you specify the region that needs to be redrawn and then you send a message to the message pump for that control to paint itself.

So, I expected something similar (if not exactly the same) to also be present in WPF; much to my surprise, there is no equivalent.   All my internet searches actually shows how to do this using background thread - it is the approach that needs to be taken in a proper programming context, however there are times when you just want to do something quick & dirty or you want to augment an existing app / port where you don't want to introduce new elements.  There are also considerations to be made when both UI and worker thread access the same data, especially with regard to data binding (see my post about collection change not supporting multi-threading out of the box).

So, I've decided to add a helper method to refresh a WPF control.  I really appreciated the Refresh method in WinForms (which executes both Invalidate & Update), so I'm renaming my method to be Refresh as well.  The code snippet below also show some C# specific techniques, namely: anonymous delegates and extension methods.

public static class ExtensionMethods

{

   private static Action EmptyDelegate = delegate() { };

 

   public static void Refresh(this UIElement uiElement)

   {
      uiElement.Dispatcher.Invoke(DispatcherPriority.Render, EmptyDelegate);
   }
}

private void LoopingMethod()

{
   for (int i = 0; i < 10; i++)
   {
      label1.Content = i.ToString();
      label1.Refresh();
      Thread.Sleep(500);
   }
}


The LoopingMethod is just the method I use in my Window class to update the label (updating the progress) and then the code does some heavy lifting (Sleep ).  The Refresh method is the extension method that takes any UI element and then calls that UIElement's Dispatcher's Invoke method.  The trick is to call the Invoke method with DispatcherPriority of Render or lower.  Since we don't want to do anything, I created an empty delegate.  So how come this achieves refresh functionality?

When the DispatcherPriority is set to Render (or lower), the code will then execute all operations that are of that priority or higher.  In the example, the code already sets label1.Content to something else, which will result in a render operation.  So by calling Dispatcher.Invoke, the code essentially asks the system to execute all operations that are Render or higher priority, thus the control will then render itself (drawing the new content).  Afterwards, it will then execute the provided delegate (which is our empty method).

Pretty weird; there was a post somewhere in my google search that led me this route, and I was surprised as to how it worked.  I couldn't find it anymore, but credit where credit is due, someone else figured out that Invoke-ing a Render or lower priority task will result in the UI being redrawn.

Update (January 20, 2009):

A Commenter asked for a full sample, so I've uploaded one here.  I don't speak Spanish, but Google translator was working great!

Update (February 26, 2009):

A Commenter asked for a VB.NET sample, so I've uploaded one here.
posted on Monday, August 25, 2008 10:22 AM Print
Comments
Gravatar
# re: Refresh / Update WPF controls
Dolores
1/19/2009 10:26 AM
Oye podrias proporcionarme un ejemplo completo porque no he podido implementar tu pedazo de codigo en mi proyecto
Gravatar
# re: Refresh / Update WPF controls
beginner-WPF
2/26/2009 5:12 PM
hello
im very happy to write to this mail to tell im a student and i love programming and i hope to learn more about wPF and im trying to use this code in vb.net but it doesnt work or im not able to do this can you help me with lesson or a code source in vb.net language to use refresh method and thanks u so much !!
Gravatar
# re: Refresh / Update WPF controls
Rex_NFX
5/28/2009 9:34 AM
Awesome! Works beautiful. I searched a half a dozen other posts before I found this and nothing else worked. Thanks!
Gravatar
# Refresh / Update WPF controls
x
6/10/2009 4:08 AM
it not working for when u press control tab continuosly
Gravatar
# re: Refresh / Update WPF controls
Robert
7/9/2009 1:57 AM
Perfect code-snippet
Thx a lot!
Gravatar
# re: Refresh / Update WPF controls
Ken Blackstein
7/24/2009 8:32 AM
elegant.
thank you.
Gravatar
# re: Refresh / Update WPF controls
Andre
8/11/2009 8:08 AM
Thank you very much!!!
Gravatar
# re: Refresh / Update WPF controls
JBBW
8/16/2009 6:36 AM
Wow - this is great. Thank you.
Gravatar
# Re: Refresh / Update WPF controls
MrK
9/24/2009 4:08 AM
Tried this approach when doing TabControl.Items.MoveCurrentTo... and it has no effect. The tab control is still not redrawn. Any ideas? Thanks.
Gravatar
# re: Refresh / Update WPF controls
Muljadi Budiman
9/24/2009 6:57 AM
@MrK:
Please leave an email next time; it's easier than corresponding via comments.

From my simple test, there are some possibilities as to why it doesn't work for you:
1. I created a TabControl and have the TabItems in the XAML; with this scenario, MoveCurrentTo does not change the selected tab; if I call TabControl1.SelectedItem = TabControl1.Items[1] (to set it to the second item) then do TabControl1.Refresh, it works.
2. If I created the tabitems in code and put them in a CollectionView, then MoveCurrentTo will also change the SelectedItem (tab) and .Refresh will also work.
3. If you're using Windows 7 (don't know about Vista), I have to change the DispatcherPriority to Input (or lower) before it'll work.
Gravatar
# re: Refresh / Update WPF controls
Bill
10/27/2009 8:10 AM
Cool. Kind of strange to hear MFC is better than WPF in a way:)
Gravatar
# re: Refresh / Update WPF controls
kv
11/8/2009 10:47 AM
This is a great tip, thanks. It does work, but only if you have one element in the loop. If you do, for example have two labels, it will update both of them even if only calling label1.refresh();
Any ideas?

Post Comment

Title *
Name *
Email
Url
Comment *  
 
News