none
Refresh the GUI in a WPF application

    Question

  • Hi,

    I am looking for a solution for refreshing the GUI in a WPF application which is running in a loop that writes information to the GUI (let's say into a Label):

    Code Snippet

    for (int i = 0; i < 100; i++)
    {
       this.lblInfo.Content = i.ToString();

       // How to refereh the GUI?
    }


    In Windows.Forms one can use the Refresh method of the updated control or Application.DoEvents.

    I know that I can run the code in an thread to ensure GUI updating (i.e. using the BackgroundWorker). Is this the only way to ge an responding GUI in WPF?

    Thanks in advance

    Jurgen




    Tuesday, February 05, 2008 2:00 PM

Answers

  • This works and was found on some other blog.


    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);
       }
    }

    Javaman
    • Marked as answer by Jürgen Bayer Friday, September 03, 2010 9:07 PM
    Saturday, February 14, 2009 1:57 AM
  • You can use the InvalidateVisual method on the element or parent element.

     

    Tom

     

    Tuesday, February 05, 2008 2:29 PM
  • Using a worker thread is probably the best way, but if you want another option you can take a look here - seems that you can update the UI using the Dispatcher.PushFrame() API. Unfortunetly nobody seems to know how safe is this method.

    Another idea is to use the OnIdle() function and do one iteration per call. OnIdle() is called
    when no Windows messages are being processed. Here is a little sample:

    void Init()
    {
       ComponentDispatcher.ThreadIdle += new EventHandler(OnIdle);
       int i = 0;
    }

    private void OnIdle(object sender, EventArgs e)
    {
       if(i == 100)
       {
          // stop processing OnIdle()
          ComponentDispatcher.ThreadIdle -= OnIdle;
       }
       else
       {
          // do iteration
          this.lblInfo.Content = i.ToString();
          i++;
       }

    }


    Tuesday, February 05, 2008 2:44 PM

All replies

  • You can use the InvalidateVisual method on the element or parent element.

     

    Tom

     

    Tuesday, February 05, 2008 2:29 PM
  • Using a worker thread is probably the best way, but if you want another option you can take a look here - seems that you can update the UI using the Dispatcher.PushFrame() API. Unfortunetly nobody seems to know how safe is this method.

    Another idea is to use the OnIdle() function and do one iteration per call. OnIdle() is called
    when no Windows messages are being processed. Here is a little sample:

    void Init()
    {
       ComponentDispatcher.ThreadIdle += new EventHandler(OnIdle);
       int i = 0;
    }

    private void OnIdle(object sender, EventArgs e)
    {
       if(i == 100)
       {
          // stop processing OnIdle()
          ComponentDispatcher.ThreadIdle -= OnIdle;
       }
       else
       {
          // do iteration
          this.lblInfo.Content = i.ToString();
          i++;
       }

    }


    Tuesday, February 05, 2008 2:44 PM
  • Thanks for your answer.

    InvalidateVisual is not what I was looking for. As documented it only invalidates the part of the GUI which contains the element. This does not cause a refresh since the program is running in a loop which gives Windows no time to repaint the GUI. It seems that WPF does not have an equivalent to the Refresh method of Windows.Forms controls.

    Jurgen


    Tuesday, February 05, 2008 8:39 PM
  • update:

    found an interesting alternative using a background thread and inline delegates:
    http://staceyw.spaces.live.com/?_c11_BlogPart_BlogPart=blogview&_c=BlogPart&partqs=amonth%3d2%26ayear%3d2006

    The idea behind is to create a thread that will do a beginInvoke back to the ui thread. The main advantage is that inline delegates allow doing all these changes inside only one function.

    Monday, March 10, 2008 3:30 PM
  • Agreed, anonymous delegates are really really nice for wiring up activity to any event. You can add them immediately at the click event like this...

    button_buttonName.Click += delegate(object obj, EventArgs e){

       //do something here

    }

     

    But what I don't understand is that in 2008 Express edition when you create a WPF application.  A shell "Window" pops up with nothing in it.  Now lets say I want to create XAML expressions that change color or size but I want the code behind to do it in a iterative loop.  In the past, on a Forms application one just simply made the change desired (in the loop) and called the ubiquitous Control.Refresh() method.  What is the equivalent in a WPF "Window" where buttons and rectangles et. al. are contained in the "Window"?  I don't understand why this would be omitted?  How can you refresh XAML controls from Code behind?

    Also, is WPF more of a browser solution or just a new form or Windows forms?  It seems to by a hybrid browser type solution in a Windows frame, but it doesn't have the characteristics of a Windows Form and it doesn't have the characteristics of a WebBrowser...

    P.S. Can XAML be utilized in a Windows Form?


    Javaman
    Monday, January 26, 2009 9:23 PM
  • Juergen Bayer said:

    Hi,

    I am looking for a solution for refreshing the GUI in a WPF application which is running in a loop that writes information to the GUI (let's say into a Label):

    Code Snippet

    for (int i = 0; i < 100; i++)
    {
       this.lblInfo.Content = i.ToString();

       // How to refereh the GUI?
    }


    In Windows.Forms one can use the Refresh method of the updated control or Application.DoEvents.

    I know that I can run the code in an thread to ensure GUI updating (i.e. using the BackgroundWorker). Is this the only way to ge an responding GUI in WPF?

    Thanks in advance

    Jurgen






    If you change Label.Content UI will update. Just run you code in VS and watch the numbers increment (I'd recommend to insert Thread.Sleep).

    Keep in mind: If you call this on UI thread you will just block it and UI will have no chance to udate itself unless you code returns. So call it on other thread (for example on ThreadPool.QueueUserWorkItem) and update UI through Dispatcher. For example like this:

    for (int i = 0; i < 100; i++)

    {

    this.Dispatcher.BeginInvoke(new Action(() => this.label.Content = i.ToString()), null);

    Thread.Sleep(500);

    }

    Hope this helps. Sorry about that fancy lambda thing. I like it :)

    PS. IMHO WPF is about getting rid of the stuff like this where you directly manipulate element properties. It's about databinding. I think so.

    Monday, January 26, 2009 11:03 PM
  • Oops.. Seems the thread was started a year ago.
    Monday, January 26, 2009 11:07 PM
  • Yes, but I didn't see it as a clear answer... let me try your suggestion and thanks...

     


    Javaman
    Monday, January 26, 2009 11:08 PM
  • for (int i = 0;i<100;i++){  
     
    System.Threading.Thread.Sleep(200);  
     
    this.Dispatcher.BeginInvoke(new Action(() => rectangle2.Width = (double)i), null);  
     
    }  
     

    This did not work....the new value showed up only after the loop was completed.  The refresh only happened once this event was done.


    Javaman
    Monday, January 26, 2009 11:54 PM
  • This works and was found on some other blog.


    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);
       }
    }

    Javaman
    • Marked as answer by Jürgen Bayer Friday, September 03, 2010 9:07 PM
    Saturday, February 14, 2009 1:57 AM
  • Thanks for the persistence Javaman - this one was stumping me too and your last entry did solve it for me.
    Although I will have to stare at it for a while to understand how and why Art_Sh example would not ; )



    //poulh
    Monday, September 28, 2009 9:15 PM
  • The good news about a worker thread is its ability to keep the Interface Thread open for input. The worker can report its progress back to the Interface layer through its thread relationship. However its not always the best course of action, in theroy a worker should be used when processing data and displaying changes to the interface. However when that change occurs far to frequently the worker process runs into issues with the WPF Queue's (I'm assuming for the sake of this argument that the interface control layer is a fine system of queue's.).

    WPF attempts to prevent the interface from rendering itself if another render action is "inQueue"  (or about to be performed). It tries (in a certain number of milliseconds) to wait for all the rendering changes to be made. For instance when you are scrolling through a database and adding an object for qualifying rows the WPF Interface Layer will wait for all objects to be added. This becomes a pain. In traditional windows forms the programmer could force a redraw of the screen to let the user know something is happening. In WPF the safest way is to send Interface requests from a worker which if the process is sending interface commands to fast (as compared by the CPU power and speed... etc.) the items will not render till the end of the operation. Only the last set of non-conflicting interface actions will be performed. For instances changing a label text 3 times during the process will only display the 3rd and last change.

    I like the idea of pushing a frame out to the dispatcher. Of course you might run into issues if you perform the dispatcher to frequently, or if you have pending high level interface changes (such as a drop of an object). The other solution of creating the "Refresh()" extension for WPF does help. In best practice, refrsh the object your changing and refrsh its owner. This gives WPF enough time to "breathe" and allow the interface changes to be rendered.

    Rendering is, and has always been, a computer intensive operation. Your talking about mathematical calculations that you're better off leaving to the operating system. Of course WPF (as to prevent the issues with its predecessors) will try to lower the amount of rendering actions being performed during a processes life cycle. Your better off telling WPF to push the actions out to the screen from the worker, refesh method, or better yet (if someone could verify how safe the action is to the threads) push out the frame to the dispatcher. WPF was designed to utilize a very interesting time line of events. Pushing the frame out to the dispatcher is probably a good place to start.

    Hope it helps, those that may not know why WPF does what it... well does.


    ~Justin
    Tuesday, December 28, 2010 8:02 PM
  • The MVVM pattern solves 90% of the needs for a Refresh statement, via implementation of the INotifyPropertyChanged interface.  WPF controls (DataContext) are bound to a different class (View Model) than the code-behind class.  Manipulation is done in the ViewModel class using Property GETTER SETTERs,   WPF has registered a PROPERCHANGED event handler against the GUI WINDOW and all the other class has to do is send the event.  When this happens the GUI changes immediately.
    Javaman
    Wednesday, December 29, 2010 2:29 PM
  • Sorry, but how I have to include this solution in the code below?

    Thank you!

    <Window x:Class="WpfApplication4.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
        <Grid Margin="0,0,237,84">
            <Button Content="Button" HorizontalAlignment="Left" Height="52" Margin="38,35,0,0" VerticalAlignment="Top" Width="148" Click="Button_Click"/>
            <TextBox x:Name="text1" HorizontalAlignment="Left" Height="33" Margin="38,128,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="148"/>
    
        </Grid>
    </Window>

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    
    namespace WpfApplication4
    {
       
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
    
            private void Button_Click(object sender, RoutedEventArgs e)
            {
                for (int i = 1; i <=10; i++)
                {
                    text1.Text = (i.ToString());
                    System.Threading.Thread.Sleep(200);
                }
            }
        }
    }

    • Edited by hth26 Sunday, May 25, 2014 8:44 AM
    Sunday, May 25, 2014 8:36 AM