Click here to Skip to main content
15,885,032 members
Please Sign up or sign in to vote.
1.00/5 (1 vote)
See more: , +
I have create a small class CountDown , that contains a timer.

Class is very simple : receive time target, and start a CountDown with a timer.

When target is reached, my personal event fire


C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CountDownWithEvent
{
    public delegate void countDownFinishEventHandler(Object sender, EventArgs e);
    class CountDown
    {
        private DateTime _target;
        private System.Windows.Forms.Timer _timer;
        System.TimeSpan _timeMissing;


        public event countDownFinishEventHandler CountDownFinish;

        public CountDown(DateTime targetTime)
        {
            this._target = targetTime;
            this._timer = new System.Windows.Forms.Timer();
            this._timeMissing = new TimeSpan();
        }

        public DateTime TargetTime
        {
            get;
        }

        public TimeSpan timeMissing
        {
            get;
        }

        public void CountDownStart()
        {
            _timer.Interval = 1000;
            _timer.Tick += new EventHandler(timer_tick);
            _timer.Start();
        }

        protected virtual void timer_tick(Object sender, EventArgs e)
        {
            //if (_timer.Tick != null)
            //{
            //}
            System.DateTime now = System.DateTime.Now;
            _timeMissing = _target.Subtract(now);
            if (!(timeMissing.TotalSeconds > 0))
            {
                _timer.Stop();
                if(CountDownFinish != null)
                {
                    EventArgs b = new EventArgs();
                    CountDownFinish(this, b);
                }
            }
        }


    }
}


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace CountDownWithEvent
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            CountDown CountDown = new CountDown(new DateTime(2016, 05, 27, 14, 48, 00));
            CountDown.CountDownFinish += new countDownFinishEventHandler(onCountDown);
            CountDown.CountDownStart();
        }

        private void onCountDown(Object sender, EventArgs e)
        {
            MessageBox.Show("time expired! ");
        }
    }
}



I use EventArgs, rather than write a derived class , because I don't need any special information of the event ( to understand, parameter e)

now I'm in a situation a bit unusual :

C#
protected virtual void timer_tick(Object sender, EventArgs e)
    {
        //if (_timer.Tick != null)
        //{
        //}
        System.DateTime now = System.DateTime.Now;
        _timeMissing = _target.Subtract(now);
        if (!(timeMissing.TotalSeconds > 0))
        {
            _timer.Stop();
            if(CountDownFinish != null)
            {
                EventArgs b = new EventArgs();
                CountDownFinish(this, b);
            }
        }
    }


When i call
C#
CountdownFinish(this,e);
the
C#
e
parameter refer an timer_tick It isn t consistent pass EventArgs timer so I don t know how to behave ???

In fact I have instantiated
C#
new EventArgs b


C#
EventArgs b = new EventArgs();
CountDownFinish(this, b);


but I don t know if this is the right path

Now im another problem :

I want to see in label the time left to goal. And refresh it to any timer_tick. whereas I want to keep separated the timer logic of the program graphic.. how I can do it?

Many thanks in advance for the understanding and the help! (sorry for bad english, isn t my language :) )

What I have tried:

my efforts and my tests are just above .. thanks
Posted
Updated 30-May-16 10:52am

1 solution

Main wrong thing here is using
System.Windows.Forms<br />
. You cannot expect anything good from this kind of a timer. As far as I can see, you need more or less periodic behavior, to see how the label shows count down time. With this timer, don't even dream about it, even if sometimes you got an impression of such behavior. Its accuracy is prohibitively poor. It has only one benefit: the event handler will be called in the same UI thread. Paying by poor timing for this questionable benefit would be a wrong choice.

Instead, you can use System.Timers.Timer:
Timer Class (System.Timers)[^].

There is another option, which will be the most reliable one: use a separate thread for count down; execute a loop with the delay insider, somewhat smaller then the expected period. It won't give you exactly periodic execution, but you can inquire a real time value from the system right before showing the time on screen. Most accurate way to get the time is System.Diagnostics.Stopwatch:
Stopwatch Class (System.Diagnostics)[^].

By the way, you can do this time correction in all cases. To make it more accurate, you can do it immediately before modifying the on-screen text, right in the UI thread. Let's talk about working with this thread now.

Both methods I suggest will require notification of the UI thread from a different thread. This is the remaining problem you have to solve. You cannot call anything related to UI from non-UI thread. Instead, you need to use the method Invoke or BeginInvoke of System.Windows.Threading.Dispatcher (for both Forms or WPF) or System.Windows.Forms.Control (Forms only).

You will find detailed explanation of how it works and code samples in my past answers:
Control.Invoke() vs. Control.BeginInvoke(),
Problem with Treeview Scanner And MD5.

See also more references on threading:
.NET event on main thread,
How to get a keydown event to operate on a different thread in vb.net,
Control events not firing after enable disable + multithreading.

—SA
 
Share this answer
 

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



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900