Introduction
This article demonstrates how to use a WPF ProgressBar
in a "tight code loop".
Background
For years, progress bars have been very useful and very easy to use in regular Windows Forms applications. All that was necessary was to set the Minimum
and Maximum
properties, then incrementally modify the Value
property to report the progress. When necessary, DoEvents()
was inserted to allow the form to refresh and update the progress bar.
WPF progress bars are conceptually the same as Windows progress bars; however, a very noticeable difference is that using standard coding techniques, the WPF Progress Bars do not update correctly while the application is processing. This creates a very undesirable effect, especially since the whole purpose of the progress bar is to... report the progress.
There are many situations where "tight loops" are required in code, such as when data is being read from a file. A standard coding approach is to open the file, then loop through the entire file, reading either lines, characters, or bytes in each pass. A progress bar may be used to report the progress of this operation.
Tight loops present a bit of a challenge for WPF progress bars, and the standard coding techniques do not produce the same results as they do in Windows Forms. Therefore, this article specifically addresses this issue, and demonstrates how to use a WPF ProgressBar
in a "tight code loop".
Using the code
The WPF ProgressBar
has a "SetValue
" method that can be used to update the progress of the ProgressBar
. However, this method will not cause the ProgresssBar
to refresh when there is a tight coding loop. Therefore, it is necessary to use the Invoke
method of the Dispatcher
class to update the progress of the ProgressBar
and cause it to refresh correctly on the form.
The Dispatcher
class provides services for managing the queue of work items for a thread.
One of the arguments of the Dispatcher.Invoke
method is a delegate. Since a delegate can be created and used to point to a specific method to invoke, we will create and use one that will point to the ProgressBar'
s SetValue
method, so it will have the exact same signature as well.
Here's the complete example in Visual Basic and C#:
Visual Basic:
Private Delegate Sub UpdateProgressBarDelegate(ByVal dp As _
System.Windows.DependencyProperty, _
ByVal value As Object)
Private Sub Process()
ProgressBar1.Minimum = 0
ProgressBar1.Maximum = Short.MaxValue
ProgressBar1.Value = 0
Dim value As Double = 0
Dim updatePbDelegate As New _
UpdateProgressBarDelegate(AddressOf ProgressBar1.SetValue)
Do Until ProgressBar1.Value = ProgressBar1.Maximum
value += 1
Dispatcher.Invoke(updatePbDelegate, _
System.Windows.Threading.DispatcherPriority.Background, _
New Object() {ProgressBar.ValueProperty, value})
Loop
End Sub
C#
private delegate void UpdateProgressBarDelegate(
System.Windows.DependencyProperty dp, Object value);
private void Process()
{
ProgressBar1.Minimum = 0;
ProgressBar1.Maximum = short.MaxValue;
ProgressBar1.Value = 0;
double value = 0;
UpdateProgressBarDelegate updatePbDelegate =
new UpdateProgressBarDelegate(ProgressBar1.SetValue);
do
{
value += 1;
Dispatcher.Invoke(updatePbDelegate,
System.Windows.Threading.DispatcherPriority.Background,
new object[] { ProgressBar.ValueProperty, value });
}
while (ProgressBar1.Value != ProgressBar1.Maximum);
}
Conclusion
This is a very brief, and hopefully clear and concise article on using a WPF ProgressBar
. The source code for both Visual Basic and C# is included for you as a reference.
I hope it's helpful to you!