Tutorial :Label does not change value inside a while loop



Question:

private void button1_Click(object sender, RoutedEventArgs e)  {          int i = 0;            while (i < 500)          {              label1.Content = i.ToString();          //  System.Threading.Thread.Sleep(2000);              ++i;          }   }  

I am trying to update the content of a Label each time a variable is incremented, but what happens is label1's Content is changed only once and only after the while loop terminates. I thought that the incrementation of the counter variable was so fast that the UI thread could not catch up with it, so I wanted to make the thread idle for 2 seconds, hoping to see label1 change value 500 times. It did not work either. Why?


Solution:1

As others have said, the problem is that you're blocking the UI thread.

Rather than use the suggestions with Application.DoEvents, I would suggest that you use a DispatcherTimer to schedule the update. Sample code:

DispatcherTimer timer = new DispatcherTimer();  timer.Tick += delegate  {      label.Content = counter.ToString();      counter++;      if (counter == 500)      {          timer.Stop();      }  };  timer.Interval = TimeSpan.FromMilliseconds(2000);  timer.Start();  

(I'm not sure whether Application.DoEvents even works in WPF, and it's generally regarded as bad practice anyway. If it does work, I doubt that it's guaranteed to work in future versions. Mixing the two UIs in the same application just for the sake of this sounds like a really bad idea to me.)

You could use a Timer (either System.Threading.Timer or System.Timers.Timer) but in both cases you'd then need to marshal back to the dispatcher thread anyway. DispatcherTimer makes this simpler - the Tick event is always fired within the Dispatcher thread anyway.

EDIT: If you really want an equivalent of DoEvents, here's code which I've verified does work, and is based on the MSDN docs for Dispatcher.PushFrame explaining how to do the equivalent of Application.DoEvents but from WPF:

public void DoEvents()  {      DispatcherFrame frame = new DispatcherFrame();      Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background,          new DispatcherOperationCallback(ExitFrames), frame);      Dispatcher.PushFrame(frame);  }    public object ExitFrames(object f)  {      ((DispatcherFrame)f).Continue = false;        return null;  }    private void ButtonClick(object sender, RoutedEventArgs e)  {      for (int i = 0; i < 500; i++)      {          label.Content = i.ToString();          DoEvents();      }  }  

I still wouldn't recommend this though - WPF (like Windows Forms) is designed on an event-driven way of working.


Solution:2

The handler is hogging the event loop.

One option is to use Application.DoEvents method to allow the painting operations to execute. Note that this is considered bad practice, as is the Thread.Sleep which will make the UI unresponsive.

private void button1_Click(object sender, RoutedEventArgs e)  {          int i = 0;            while (i < 500)          {              label1.Content = i.ToString();              System.Threading.Thread.Sleep(2000);              Application.DoEvents();              ++i;          }   }  

Another option is to use Control.BeginInvoke for each label1.Content = .. operation.


Solution:3

Update your method like this:

private void button1_Click(object sender, RoutedEventArgs e)  {          int i = 0;            while (i < 500)          {              label1.Content = i.ToString();              //Update the UI              Application.DoEvents();          //  System.Threading.Thread.Sleep(2000);              ++i;          }   }  

This is the easiest method to do this. But not a preferred one. The preferred one will be using the backgroundworker for such need.


Solution:4

"If we handled the entire search inside of the click event handler of the button, we would never give the UI thread a chance to handle other events. The UI would be unable to respond to input or process messages. It would never repaint and never respond to button clicks." - Source.

Anyway, what you'll want to do is create a worker thread that performs your for-loop and just update the UI using Dispatcher.BeginInvoke.


Solution:5

I think what you need is

Label.Update();  

Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »