I have a loop that reads plenty of data from an external source. The process takes about 20 seconds, and I want to show the progress to the user. I don't need any fancy progress bars, so I chose to plot my progress in a label that will say "Step 1/1000", then change to "Step 2/1000" etc.
My code looks something like this:
// "count" is the number of steps in the loop,
// I receive it in previous code
String countLabel = "/"+count.ToString();
for (i = 0; i < count; i++)
{
... do analysis ...
labelProgress.Content = "Step "+i.ToString()+countLabel
}
However, during that analysis the screen is "stuck" and the progress does not show as advancing. I understand this behavior from my past in C++, where I would probably have a separate thread showing a progress bar receiving notifications from the loop, or some form of repaint/refresh, or forcing the window/app to process its message queue.
What's the right way to do it in C#? I'm not tied to the label, so if there's a simple progress-bar popup screen I could use instead of this label it would also be great...
Thanks
Move the work to a BackgroundWorker and use the ReportProgress method.
for (i = 0; i < count; i++)
{
... do analysis ...
worker.ReportProgress((100 * i) / count);
}
private void MyWorker_ProgressChanged(object sender,
ProgressChangedEventArgs e)
{
taskProgressBar.Value = Math.Min(e.ProgressPercentage, 100);
}
//Create a Delegate to update your status button
delegate void StringParameterDelegate(string value);
String countLabel = "/" + count.ToString();
//When your button is clicked to process the loops, start a thread for process the loops
public void StartProcessingButtonClick(object sender, EventArgs e)
{
Thread queryRunningThread = new Thread(new ThreadStart(ProcessLoop));
queryRunningThread.Name = "ProcessLoop";
queryRunningThread.IsBackground = true;
queryRunningThread.Start();
}
private void ProcessLoop()
{
for (i = 0; i < count; i++)
{
... do analysis ...
UpdateProgressLabel("Step "+i.ToString()+countLabel);
}
}
void UpdateProgressLabel(string value)
{
if (InvokeRequired)
{
// We're not in the UI thread, so we need to call BeginInvoke
BeginInvoke(new StringParameterDelegate(UpdateProgressLabel), new object[] { value });
return;
}
// Must be on the UI thread if we've got this far
labelProgress.Content = value;
}
The UI is not updated due to the fact that your current thread has a higher priority than your UI thread which will ultimately set the label ;). So until your thread has finished to your stuff it will update your label in the end.
Lucky for us, there is a Dispatcher property on every WPF control that lets you fire up a new thread with another priority..
labelProgress.Dispatcher.Invoke(DispatcherPriority.Background,
() => labelProgress.Content = string.Format("Step {0}{1}", i, countLabel));
This fire up a thread in the background and would get the job done! You can also try other DispatcherPriority options
PS I also took the liberty to add an anonymous method and fix your string parsing somewhat.. hope you don't mind..
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