Tuesday, August 30, 2011

How to show current elapsed time on a WinForm using background workers and stopwatch

Problem:
I wanted to show the time elapsed for time-consuming SQL command. This is so the user could see that something is actually happening.

Solution:
I accomplished this by using two BackgroundWorkers, a status strip, two status strip labels, and a stopwatch. This will update the time label every half second and stop when the data thread is done.


 //Make sure to add these two
using System.Diagnostics;
using System.Threading;
        private void btnSQLCommand_Click(object sender, EventArgs e)
        {
                lblDataStatus.Text = lblStatus.ToolTipText = lblDataStatus.ToolTipText = "";
                lblStatus.Text = "00:00:00";
                button1.Enabled = false; //So user cant click button while operation is running
                bgWorkerTime.RunWorkerAsync();
                bgWorkerData.RunWorkerAsync();

            }           
          
        }

        private void bgWorkerTime_DoWork(object sender, DoWorkEventArgs e)
        {
            Stopwatch sw = Stopwatch.StartNew();
            while (!bgWorkerTime.CancellationPending)
            {
                TimeSpan ts = sw.Elapsed;
                bgWorkerTime.ReportProgress(0, String.Format("{0:00}:{1:00}:{2:00}",
                    ts.Hours, ts.Minutes, ts.Seconds));
                Thread.Sleep(500);
            }
            sw.Stop();
        }

        private void bgWorkerTime_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            lblStatus.Text = e.UserState.ToString();
        }

        private void bgWorkerData_DoWork(object sender, DoWorkEventArgs e)
        {
            string status = "";
                        /*
                        ...Execute SQL Command...
                              Update lblDataStatus.Text to show what's going on
                        */
                if (status != "Success")
                {
                    lblDataStatus.ToolTipText = status;
                    lblDataStatus.Text = "Error occurred";
                    break;
                }
            }
            if (status == "Success")
                lblDataStatus.Text = "Operation completed successfully";
           
        }

        private void frmDemo_FormClosing(object sender, FormClosingEventArgs e)
        {
          //Only attempt to close the form if both bg workers are not working 
            if (bgWorkerTime.IsBusy || bgWorkerData.IsBusy)
                e.Cancel = true;
            if(bgWorkerTime.IsBusy)
                bgWorkerTime.CancelAsync();
            if(bgWorkerData.IsBusy)
                bgWorkerData.CancelAsync();
        }

        private void bgWorkerData_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
                     //When the background worker executing the SQL command is completed,
                     //it will shutdown the timer bg worker, and enable the button
            bgWorkerTime.CancelAsync();
            btnSQLCommand.Enabled = true;

        }
References
1. Mainly this http://stackoverflow.com/questions/2067919/objectdisposedexception-running-stopwatch-in-gui-thread

No comments:

Post a Comment

There was an error in this gadget