Creating a simple Stopwatch/Timer application with C# / Windows Forms

Friday, 4 February 2011 09:26

Working on a project today, I came across the need for a simple stopwatch/timer which would keep track of the total elapsed time until it was reset. It turned out to be a little trickier than I first assumed, so I've posted my code here for the convenience of anyone else who needs to do the same thing.

using System;
using System.Windows.Forms;

namespace StopwatchSpike
{
    public partial class StopwatchSpikeForm : Form
    {
        // Because we have not specified a namespace, this
        // will be a System.Windows.Forms.Timer instance
        private Timer _timer;

        // The last time the timer was started
        private DateTime _startTime = DateTime.MinValue;

        // Time between now and when the timer was started last
        private TimeSpan _currentElapsedTime = TimeSpan.Zero;

        // Time between now and the first time the timer was started after a reset
        private TimeSpan _totalElapsedTime = TimeSpan.Zero;

        // Whether or not the timer is currently running
        private bool _timerRunning = false;

        public StopwatchSpikeForm()
        {
            InitializeComponent();

            // Set up a timer and fire the Tick event once per second (1000 ms)
            _timer = new Timer();
            _timer.Interval = 1000; 
            _timer.Tick += new EventHandler(_timer_Tick);
        }

        /// <summary>
        /// Handle the Timer's Tick event
        /// </summary>
        /// <param name="sender">System.Windows.Forms.Timer instance</param>
        /// <param name="e">EventArgs object</param>
        void _timer_Tick(object sender, EventArgs e)
        {
            // We do this to chop off any stray milliseconds resulting from 
            // the Timer's inherent inaccuracy, with the bonus that the 
            // TimeSpan.ToString() method will now show correct HH:MM:SS format
            var timeSinceStartTime = DateTime.Now - _startTime;
            timeSinceStartTime = new TimeSpan(timeSinceStartTime.Hours, 
                                              timeSinceStartTime.Minutes, 
                                              timeSinceStartTime.Seconds);

            // The current elapsed time is the time since the start button was
            // clicked, plus the total time elapsed since the last reset
            _currentElapsedTime = timeSinceStartTime + _totalElapsedTime;

            // These are just two Label controls which display the current 
            // elapsed time and total elapsed time
            _totalElapsedTimeDisplay.Text = _currentElapsedTime.ToString();
            _currentElapsedTimeDisplay.Text = timeSinceStartTime.ToString();
        }

        /// <summary>
        /// Handle Start/Stop button click
        /// </summary>
        /// <param name="sender">The Button control</param>
        /// <param name="e">EventArgs object</param>
        private void startButton_Click(object sender, EventArgs e)
        {
            // If the timer isn't already running
            if (!_timerRunning)
            {
                // Set the start time to Now
                _startTime = DateTime.Now;

                // Store the total elapsed time so far
                _totalElapsedTime = _currentElapsedTime;

                _timer.Start();
                _timerRunning = true;
            }
            else // If the timer is already running
            {
                _timer.Stop();
                _timerRunning = false;
            }
        }

        /// <summary>
        /// Handle Reset button click
        /// </summary>
        /// <param name="sender">The Button control</param>
        /// <param name="e">EventArgs object</param>
        private void resetButton_Click(object sender, EventArgs e)
        {
            // Stop and reset the timer if it was running
            _timer.Stop();
            _timerRunning = false;

            // Reset the elapsed time TimeSpan objects
            _totalElapsedTime = TimeSpan.Zero;
            _currentElapsedTime = TimeSpan.Zero;
        }
    }
}

Because I wasn't interested in sub-second accuracy, I've used the System.Windows.Forms.Timer for simplicity, but the principle is the same whichever timer class you use.

If you want to find out more about the differences between System.Threading.Timer, System.Windows.Forms.Timer and System.Timers.Timer, it's definitely worth reading this article comparing the Timer classes in the .NET Framework class library.

You can download my source code here (Visual Studio 2008 Solution).

Comments

Frederick 16/02/2011 07:57

I am using your code above to try to update a label (ultimately the text attribute of a checkbox button), however for some reason I can't get the count to update the label. The code executes correctly and provides the correct count into the variables, but doesn't display in the label. I have compared our apps, and I really dont' see anything different about your labels other than size, any thoughts where I am going wrong?

Frederick 16/02/2011 07:59

Nice commenting by the way!

Karen 17/07/2011 07:25

Thanks a lot for posting this! I was looking for some easy to use (and understand!) timer code to implement in a Tamagotchi "game" and this is just perfect for what I'm making. Thanks again!

Lee 09/08/2011 01:31

Nice code mate, bit if you're using .NET 2.0 and above, you can use the System.Diagnostics.Stopwatch class.

Kind regards,

Lee

Mark Bell 11/08/2011 02:10

@Lee: System.Diagnostics.Stopwatch is a high-resolution timer normally used for execution timings; it doesn't have any events you can subscribe to, nor does it have a configurable timing interval.

The Timer classes are much simpler and more practical for this particular application.

GoDaddy Promo Code 20/11/2011 07:13

clear and concise and thanks for the codes.

Add your comment