I've been searching and found that a good way to perform background work and update the GUI is using background workers. However, doing this (stupid) little task (counting from 1 to 10000) it doesn't update the label content but prints to the debug! (This is just a spike solution for another project of course...)
Here's the code:
public partial class MainWindow : Window
{
BackgroundWorker bw = new BackgroundWorker();
public MainWindow()
{
InitializeComponent();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
bw.WorkerReportsProgress = true;
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
bw.RunWorkerAsync();
}
void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
MessageBox.Show("DONE");
}
void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
label1.Content = "going here: "+e.ProgressPercentage;
Debug.WriteLine(e.ProgressPercentage);
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
for (int i=0; i < 10000; i++)
{
bw.ReportProgress((i*100)/10000);
}
}
}
The ProgressChanged
event is raised on the UI thread, not the worker thread. In your code, the worker thread is doing almost nothing (just loop from 0 to 10000 and call ReportProgress
), most of the work is done on the UI thread. Basically, you're sending too many progress notifications. Because of this, the UI thread is almost always busy and has no time to render the new content of the label.
Rendering in WPF is not performed immediately when you change a property of a control, it is done on a separate dispatcher frame, which is processed when the dispatcher has nothing more urgent to do, based on the priority of the task. The priority used for rendering has a value of 7 (DispatcherPriority.Render
); the ProgressChanged
event is marshalled to the UI thread with a priority of 9 (DispatcherPriority.Normal
), as specified on MSDN. So the ProgressChanged
notifications always have a higher priority than rendering, and since they keep coming, the dispatcher never has time to process the rendering tasks.
If you just decrease the frequency of the notifications, your app should work fine (currently you're sending 100 notifications for each percentage value, which is useless):
void bw_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 0; i < 10000; i++)
{
if (i % 100 == 0)
bw.ReportProgress(i / 100);
}
}
this.Dispatcher.BeginInvoke( (Action) delegate(){
label1.Content = "going here: "+e.ProgressPercentage;
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With