Click here to Skip to main content
Licence CPOL
First Posted 19 May 2006
Views 39,252
Bookmarked 46 times

ProgressDialog: for executing long-running code with some thread safety

By | 23 May 2006 | Article
A dialog for executing long-running code on a thread (written in C#).

Introduction

If your WinForms application needs to execute some long-running code, it's best to run it on a thread so the main thread of the form isn't hung up. It is also helpful if the form has a progress bar so the thread can let the user know how it's progressing. But this requires cross-thread access which needs to be done safely.

This brings up three points:

  1. The code for thread safety isn't that difficult, but why do have to write it for every form that needs a progress bar?
  2. The progress bar is only needed while the long-running code runs, so why have it on the form at all?
  3. What if the user wants to cancel the operation?

My solution is to use a dialog that encapsulates the thread-safe manipulation of the progress bar and allows any form to use it without having to add a progress bar and its code to the form itself.

The ability to cancel the operation depends on the operation, but is supported.

Using the code

The code for the ProgressDialog is in ProgressDialog.cs, the other files are for the example application.

Because I derived from the Form class, all the public methods and properties of Form are available, which is not really a good idea. I should have encapsulated the form inside my class, but I decided to be lazy. The result is that the user of the class can modify the appearance of the dialog, and maybe that's not such a bad thing, you have the source code anyway.

At any rate, the only parts of the class that I expect the user of the class to use are:

  • The constructors
  • The ShowDialog method
  • The Result property
  • The WasCancelled property
  • The RaiseUpdateProgress method
  • The ProgressDialogStart delegate

The example demonstrates all of these but the delegate:

// This example demonstrates the ProgressDialog
//
// The form for this example contains
// only a Button, a NumericUpDown, and a Label
// Set the NumericUpDown (to a number of seconds to sleep)
// Click the Button
// When the process completes (or is canceled)
// set the Label to show the elapsed time

namespace Progger
{
    public partial class Form1 : System.Windows.Forms.Form
    {
        // Declare one -- in this example it's important to initialize it
        PIEBALD.Dialogs.ProgressDialog dlg = null ;

        public Form1 ()
        {
            InitializeComponent() ;
        }
        
        private void button1_Click ( object sender , System.EventArgs e )
        {
            System.DateTime start = System.DateTime.Now ;

            // Instantiate it (this example uses an anonymous method)
            dlg = new PIEBALD.Dialogs.ProgressDialog
            (
                "Sleeping",
                this.Icon,
                System.Windows.Forms.ProgressBarStyle.Blocks
// or                System.Windows.Forms.ProgressBarStyle.Marquee,
                true
// or               false,
                delegate
                (
                    object[] Params
                )
                {
                    int howlong = (int) Params [ 0 ] * 10 ;

                    // This is a simple way of implementing the cancel handling
                    for ( int runner = 0 ; !dlg.WasCancelled && 
                        ( runner < howlong ) ; runner++ )
                    {
                        System.Threading.Thread.Sleep ( 100 ) ;

                        // Need to update the ProgressBar
                        // when it's Block or Continuous style
                        // Use a calculation that's appropriate for your usage
                        dlg.RaiseUpdateProgress ( runner * 100 / howlong ) ;
                    }

                    // Return what you want
                    return ( System.DateTime.Now ) ;
                },
                // This value will be passed to the method
                (int) this.numericUpDown1.Value
            ) ;

            // Then all you need to do is 
            dlg.ShowDialog() ;

            // Afterward you can access the WasCancelled
            // and Result properties as needed
            this.label1.Text = string.Format
            (
                "{0} {1:0.00} seconds",
                dlg.WasCancelled?"Woken after":"Slept for",
                ( (System.DateTime) dlg.Result - start ).TotalSeconds
            ) ;
        }
    }
}

Points of Interest

Things to learn from this: cross-thread safety, delegates, and anonymous methods.

History

  • First posted - 2006-05-18.

License

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

About the Author

PIEBALDconsult

Software Developer (Senior)

United States United States

Member

BSCS 1992 Wentworth Institute of Technology
 
Originally from the Boston (MA) area. Lived in SoCal for a while. Now in the Phoenix (AZ) area.
 
OpenVMS enthusiast, ISO 8601 evangelist, photographer, opinionated SOB
 
---------------
 
"Typing is no substitute for thinking." -- R.W. Hamming
 
"I find it appalling that you can become a programmer with less training than it takes to become a plumber." -- Bjarne Stroustrup
 
ZagNut’s Law: Arrogance is inversely proportional to ability.
 
"Well blow me sideways with a plastic marionette. I've just learned something new - and if I could award you a 100 for that post I would. Way to go you keyboard lovegod you." -- Pete O'Hanlon
 
"linq'ish" sounds like "inept" in German -- Andreas Gieriet
 

"Things would be different if I ran the zoo." -- Dr. Seuss
 
"Wrong is evil, and it must be defeated." – Jeff Ello
 
"A good designer must rely on experience, on precise, logical thinking, and on pedantic exactness." -- Nigel Shaw
 

"Omit needless local variables." -- Strunk... had he taught programming
 
"DON'T BE LIBERAL IN WHAT YOU ACCEPT!"
 
"Software Engineers don't have Trophy Wives; they have Presentation Layers."
 
"We learn more from our mistakes than we do from getting it right the first time."
 
"I'm an old dog and I like old tricks."
 
"Sometimes the envelope pushes back and sometimes you get a really nasty paper cut."
 
"A method shall have one and only one return statement."
 
My first rule of debugging: "If you get a different error message, you're making progress."
 
My golden rule of database management: "Do not unto others' databases as you would not have done unto yours."
 
My general rule of software development: "Design should be top-down, but implementation should be bottom-up."
 
"Today's heresy is tomorrow's dogma."
or
"Today's dogma is yesterday's heresy."
 
"The registry is evil."
 
"Every tool is a hammer."

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. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
Questionwhy i got a error like this? Pinmemberbailuotuo16:01 15 Nov '07  
AnswerRe: why i got a error like this? PinmemberPIEBALDconsult16:36 15 Nov '07  
Generalgetting errors Pinmembergayeeee9:30 4 Dec '06  
GeneralRe: getting errors PinmemberPIEBALDconsult14:49 4 Dec '06  
GeneralBetter way.. Pinmemberscanner7777:01 23 Oct '06  
GeneralRe: Better way.. PinmemberPIEBALDconsult7:27 24 Oct '06  
Questionslow? Pinmembera_takavci22:08 17 Sep '06  
AnswerRe: slow? PinmemberPIEBALDconsult7:59 18 Sep '06  
GeneralRe: slow? Pinmembera_takavci3:19 19 Sep '06  
GeneralRe: slow? PinmemberPIEBALDconsult11:51 21 Sep '06  
GeneralRe: slow? Pinmembera_takavci12:32 23 Sep '06  
General.Style only available in .NET 2.0 Pinmemberdrdre20056:38 19 Aug '06  
GeneralPIEBALD (unavailable) PinmemberTassosK5:11 20 May '06  
GeneralRe: PIEBALD (unavailable) PinmemberPIEBALDconsult6:01 20 May '06  
Yeah, I messed up. I meant to remove the PIEBALD project and simply add the ProgressDialog.cs file to the Progger project.
 
And I did... after I submitted. When I get back to the office on Monday, I'll see about uploading the fixed files.
 
So anyway, remove the PIEBALD project from the solution and add the ProgressDialog.cs as an existing item and the example should work fine, it did for me.
 
This is why I don't like to include projects and solutions, too dang much trouble, and of course they're VS-specific, which is nasty. Dead | X|

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

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web04 | 2.5.120529.1 | Last Updated 23 May 2006
Article Copyright 2006 by PIEBALDconsult
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid