In Console Applications, you don't have an event message loop like in a Windows Application project, hence, so you can't use the
System.Windows.Forms.Timer
object since it depends on Windows Message loop to fire its tick events.
Instead, you will need to write your own timer object using multi-threading in C#. In this article I describe just how to write your own Timer for your Console Application.
First you need to build your own timer class object. To start, we can do something like this:
class
Timer
{
// Delegates
public
delegate
void
Tick();
// Properties
public
int Interval;
public
Tick OnTimerTick;
// Private Data
Thread _timerThread;
volatile
bool _bStop;
}
Next you want to implement an event loop for the timer. This code will run on the timer's thread, not the main thread. Here is how you'd write one:
public
void Run()
{
while (!_bStop)
{
// Sleep for the timer interval
Thread.Sleep(Interval);
// Then fire the tick event
OnTimerTick();
}
}
A Timer has a Start & Stop methods. These methods run on the main thread, and control the timer's operation. The above timer event loop however runs on a separate worker thread, which is created in the Start method implementation as follows:
public
Thread Start()
{
_bStop = false;
_timerThread = newThread(newThreadStart(Run));
_timerThread.IsBackground = true;
_timerThread.Start();
return _timerThread;
}
Now to stop the Timer, we'll need to set the volatile boolean in the Timer data members to false. The Stop Method is invoked from the main thread. The value of the volatile member is then checked each time in the event loop of the worker thread (as seen above). Here is how to implement the Stop method for the timer:
public
void Stop()
{
// Request the loop to stop
_bStop=true;
}
Notice that the stop method would only put a request to stop the timer, but won't kill the thread. If the timer interval is short, that isn't much of a problem, but if the timer interval is long, say 5 minutes, it might take the whole 5 minutes before the timer checks the above volatile member and decides to stop the event loop. To fix this, there are 2 options, first is to simply kill the worker thread in the Stop implementation (remember the Stop method is invoked on the main thread), as follows:
public
void Stop()
{
// Request the loop to stop
_bStop=true;
_timerThread.Join(1000);
_timerThread.Abort();
}
A better way however is to sleep intermittently in the event loop and check the volatile member more frequently:
public
void Run()
{
while (true)
{
// Sleep for the timer interval
SleepIntermittently(Interval);
// Then fire the tick event
OnTimerTick();
}
}
Now you can just implement the Stop method as before. Here is the implementation of the SleepIntermittently method:
public
void SleepIntermittently(int totalTime)
{
int sleptTime = 0;
int intermittentSleepIncrement = 10;
while (!_bStop && sleptTime < totalTime)
{
Thread.Sleep(intermittentSleepIncrement);
sleptTime += intermittentSleepIncrement;
}
}
Finally here is a test application for our Console timer:
using
System;
using
System.Collections.Generic;
using
System.Text;
using
System.Threading;
namespace
TimerConsoleApp
{
class
Program
{
public
static
void timerTick()
{
Console.WriteLine("[W] Timer Ticked!");
}
static
void
Main
(string[] args)
{
Timer timer = newTimer();
timer.Interval=500;
timer.OnTimerTick += timerTick;
Thread timerThread = timer.Start();
for (int i = 0; i < 10; i++)
{
if (i > 5)
{
Console.WriteLine("[M] Timer is Stopped! " + DateTime.Now.ToLongTimeString());
}
else
{
Console.WriteLine("[M] Timer is Active! " + DateTime.Now.ToLongTimeString());
}
if (i == 5)
{
Console.WriteLine("[M] Stopping the timer...");
timer.Stop();
}
// Do lengthy main thread processing here
///
Thread.Sleep(5000);
}
}
}
}
And now the timer is ready for use.
Happy Programming!
Demo (You will need .NET 2.0 installed run this app)