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.