Click here to Skip to main content
Click here to Skip to main content

WPF ProgressBar

By , 28 Jul 2009
 

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:

'Create a Delegate that matches
'the Signature of the ProgressBar's SetValue method
Private Delegate Sub UpdateProgressBarDelegate(ByVal dp As _
                 System.Windows.DependencyProperty, _
                 ByVal value As Object)

Private Sub Process()

    'Configure the ProgressBar
    ProgressBar1.Minimum = 0
    ProgressBar1.Maximum = Short.MaxValue
    ProgressBar1.Value = 0

    'Stores the value of the ProgressBar
    Dim value As Double = 0

    'Create a new instance of our ProgressBar Delegate that points
    ' to the ProgressBar's SetValue method.
    Dim updatePbDelegate As New _
        UpdateProgressBarDelegate(AddressOf ProgressBar1.SetValue)

    'Tight Loop: Loop until the ProgressBar.Value reaches the max
    Do Until ProgressBar1.Value = ProgressBar1.Maximum

         value += 1

        'Update the Value of the ProgressBar:
        ' 1) Pass the "updatePbDelegate" delegate
        '    that points to the ProgressBar1.SetValue method
        ' 2) Set the DispatcherPriority to "Background"
        ' 3) Pass an Object() Array containing the property
        '    to update (ProgressBar.ValueProperty) and the new value
        Dispatcher.Invoke(updatePbDelegate, _
            System.Windows.Threading.DispatcherPriority.Background, _
            New Object() {ProgressBar.ValueProperty, value})

    Loop

End Sub

C#

//Create a Delegate that matches 
//the Signature of the ProgressBar's SetValue method
private delegate void UpdateProgressBarDelegate(
        System.Windows.DependencyProperty dp, Object value);


private void Process()
{
    //Configure the ProgressBar
    ProgressBar1.Minimum = 0;
    ProgressBar1.Maximum = short.MaxValue;
    ProgressBar1.Value = 0;

    //Stores the value of the ProgressBar
    double value = 0;

    //Create a new instance of our ProgressBar Delegate that points
    // to the ProgressBar's SetValue method.
    UpdateProgressBarDelegate updatePbDelegate = 
        new UpdateProgressBarDelegate(ProgressBar1.SetValue);

    //Tight Loop: Loop until the ProgressBar.Value reaches the max
    do
    {
        value += 1;

        /*Update the Value of the ProgressBar:
            1) Pass the "updatePbDelegate" delegate
               that points to the ProgressBar1.SetValue method
            2) Set the DispatcherPriority to "Background"
            3) Pass an Object() Array containing the property
               to update (ProgressBar.ValueProperty) and the new value */
        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!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

VB Rocks
Software Developer DataPrint, LLC
United States United States
Member

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionMy Vote of 5membertcm121115 Jun '12 - 1:01 
This works great, thx;
GeneralMy vote of 5memberpenguindude30 Jan '12 - 6:53 
It's strange how many things were easy to do in WinForms were made much less intuitive in WPF
QuestionA good articlememberBorisL200025 Dec '11 - 14:44 
A good article for WPF beginers. Thank you
QuestionA BackgroundWorker is the the way to gomemberrhyous26 Aug '11 - 13:44 
I agree with previous posts, a BackgroundWorker is the the way to go.
 
I have a post on my blog that shows how to do this:
A Progress Bar using WPF’s Progress Bar Control, BackgroundWorker, and MVVM
GeneralMy vote of 1memberIan Shlasko5 Jul '11 - 9:57 
Sorry, but as others have said, this is bad practice. The proper method is to use a System.Threading.BackgroundWorker and hook the progress event to update the GUI.
 
If you wanted to really do things the "WPF way", you would take it even further, and instead of editing the ProgressBar through the code-behind, you'd create a model that would include a PercentComplete property, bind the bar to that, and update that property in the worker's progress handler.
 
EDIT: Didn't notice how old this article is... Guess that's what happens when they pop up as the "Featured" article.
GeneralMy vote of 5memberstrogos14 Feb '11 - 12:17 
...thanks.
Generalgreat applicatinmemberdcakmak28 Sep '10 - 9:20 
thanks for the article
 
http://www.ankarakervannakliyat.com
dCakmak...

GeneralThanksmemberall2neat_12 Aug '10 - 10:49 
I wasted six hours to figure this simple thing out, there really isn't a lot out their, especially for vb.net.. I'm new to my company and they require vb.net.. I'm a C# guy so I found this very useful.
GeneralRe: ThanksmemberVB Rocks12 Aug '10 - 11:57 
Ha! How funny... I'm a VB.NET guy, but doing C# work. I'm glad it was helpful to you. I haven't worked with WPF ProgressBars since I wrote the article, but I know how frustrating some things can be in WPF. Good Luck!
GeneralMy vote of 5memberDaniel Schopf4 Aug '10 - 1:44 
Exactly the thing I was looking for.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130523.1 | Last Updated 28 Jul 2009
Article Copyright 2009 by VB Rocks
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid