Timer Component

The Timer component raises a Tick event at specified time intervals. The Tick event handler can then process a regularly occurring event, such as repainting the screen for animation or a clock display, updating a status report, or terminating a program based on elapsed time.

The interval between Tick events, specified by the Interval property, is measured in milliseconds, with valid values between 1 and 2,147,483,647, inclusive. The maximum value corresponds to approximately 597 hours, or a little over 24 days.

If there are heavy demands on the system running the application, either from the current or other applications, the Tick events may not be raised as often as specified by the Interval property, especially if the Interval is very short. Under any circumstances, the interval is not guaranteed to be accurate. If accuracy is required, the system clock should be checked as needed, especially for long intervals.

Although the Interval property is in milliseconds, the system clock generates only 18 ticks per second. Therefore, the true precision of the Timer is no better than one-eighteenth of a second, which is about 55 milliseconds.

Three types of timers are provided in the .NET Framework. The first is a member of the System.Threading namespace. It is used primarily for multi-threaded applications and will not be covered in this book. It is not represented in any Visual Studio .NET Toolbox.

The second is a member of the System.Timers namespace. It is primarily intended for server applications and also is designed for multithreaded applications. It is found on the Components tab of the Visual Studio .NET Toolbox. It too will not be covered in this book.

The third type of timer component, described in this book, is a member of the System.Windows.Form namespace. It is designed for the single-threaded environment of Windows Forms, where the UI thread controls processing. This single-threaded timer is available from the Windows Forms tab of the Visual Studio .NET Toolbox.

The Timer component is not a control, since it does not have a visual aspect. Because it is not a control, it does not have a Parent property and is not part of the Controls collection.

In Visual Studio .NET, a Timer component is added to the form by dragging it from the Toolbox onto the form. However, it doesn't stay or appear on the form, but displays in the component tray at the bottom of the design window, as shown in Figure 16-6.

Figure 16-6. Timer component in Visual Studio .NET

figs/pnwa_1606.gif

The Timer component has only two properties, listed in Table 16-18. The Enabled property must be set to true in order to turn the timer function on. This can be done in the Properties window of Visual Studio .NET, in the code in the constructor (which is effectively the same), or in some other part of the program, in the event handler for a button Click. Setting the Enabled property false turns the timer off.

Table 16-18. Timer properties

Property

Value type

Description

Enabled

Boolean

Read/write. If true, the time is enabled. The default is false.

Interval

Integer

Read/write. The number of milliseconds between timer ticks.

The Timer component has two methods. The Start method starts the timer; it is equivalent to setting the Enabled property to true. The Stop method turns the timer off; it is equivalent to setting the Enabled property to false.

The Timer component has a single event, Tick. It is raised every time the number of milliseconds in the Interval property has passed. The Tick event has an event argument of type EventArgs, which means that no additional properties are associated with the event.

If the Enabled property is set to false in the Tick event handler, then the timer will be a one-shot deal: once the event is raised and handled, it will not be raised again until the Enabled property is toggled. If the Enabled property is not changed in the Tick event handler, then the timer will keep recurring until the property is set to false.

The first timer example, listed in Example 16-5 (in VB.NET only; the C# version is very similar) is a simple demonstration of a label control being used as a clock. The text value of the label is updated every 10 seconds. The result is shown in Figure 16-7.

Figure 16-7. Timer demo

figs/pnwa_1607.gif

Example 16-5. Timer example in VB.NET (Timers.vb)

figs/vbicon.gif

Option Strict On
imports System
imports System.Drawing
imports System.Windows.Forms
 
namespace ProgrammingWinApps
 public class Timers : inherits Form
 
 dim lblTime as Label
 dim strFormat as String
 
 public sub New( )
 Text = "Timer Demo"
 Size = new Size(300,100)
 
 strFormat = "dddd, MMMM d, yyyy h:mm:ss tt"
 
 lblTime = new Label( )
 lblTime.Parent = me
 lblTime.Size = new Size(CInt(ClientSize.Width * .8), 25)
 lblTime.Location = new Point(CInt(ClientSize.Width * .1), _ 
 CInt(ClientSize.Height * .4))
 lblTime.BorderStyle = BorderStyle.FixedSingle
 lblTime.Text = DateTime.Now.ToString(strFormat)
 lblTime.TextAlign = ContentAlignment.MiddleCenter
 
 dim t as new Timer( )
 t.Interval = 10000 ' 10 seconds
 t.Start( )
 AddHandler t.Tick, AddressOf t_Tick
 end sub ' close for constructor
 
 public shared sub Main( ) 
 Application.Run(new Timers( ))
 end sub
 
 private sub t_Tick(ByVal sender as object, _
 ByVal e as EventArgs)
 lblTime.Text = DateTime.Now.ToString(strFormat)
 end sub
 end class
end namespace

In this example, the Timer is instantiated in the constructor with an Interval property of 10,000 milliseconds, which is equivalent to 10 seconds. The Timer Start method is called so the timer will run as soon as the form is loaded.

In the Tick event handler, t_Tick, the Text property of the label is updated to display the current time, DateTime.Now, using the ToString method. The format of the label is controlled by an argument to the ToString method, a formatting string instantiated back in the constructor.

The next example is a countdown timer. It is similar to the previous example in that it displays a text string with the timein this case, updated every second. It also provides a DateTimePicker control for the user to enter a time interval to count down. The countdown begins when the user clicks the Start button, with the remaining time displayed. When the specified time elapses, a message is displayed in a label control. The resulting application looks like Figure 16-8 during countdown.

Figure 16-8. Countdown timer

figs/pnwa_1608.gif

In addition to using a different technique for displaying updated text strings, this example also demonstrates the use of TimeSpan objects, described earlier in this chapter.

The C# version of the CountDownTimer application is listed in Example 16-6, and the VB.NET version is listed in Example 16-7. As you will see in the analysis that follows the code listings, it was necessary to jump through some DateTime and TimeSpan hoops to get the times to display properly.

Example 16-6. CountDownTimer in C# (CountDownTimer.cs)

figs/csharpicon.gif

using System;
using System.Drawing;
using System.Windows.Forms;
 
namespace ProgrammingWinApps
{
 public class CountDownTimer : Form
 {
 DateTimePicker dtpTotalTime;
 Button btnStart;
 Button btnStop;
 bool boolStart = false;
 DateTime dtEndTime;
 Label lblTimesUp;
 Label lblTitle;
 
 public CountDownTimer( )
 {
 Text = "CountDown Timer";
 Size = new Size(500,400);
 FormBorderStyle = FormBorderStyle.FixedDialog;
 Font = new Font("Arial", 12);
 
 Timer t = new Timer( );
 t.Interval = 1000;
 t.Start( );
 t.Tick += new EventHandler(t_Tick);
 
 lblTitle = new Label( );
 lblTitle.Parent = this;
 lblTitle.Font = new Font("Arial Black", 24);
 lblTitle.Text = "CountDown Timer";
 lblTitle.TextAlign = ContentAlignment.MiddleCenter;
 lblTitle.Size = new Size((int)(lblTitle.Font.Height * .7) * 
 lblTitle.Text.Length, 35);
 lblTitle.Location = new Point(ClientSize.Width / 2 - 
 lblTitle.Width / 2, 25);
 
 Label lblTotalTime = new Label( );
 lblTotalTime.Parent = this;
 lblTotalTime.Text = "Total Time (h:m:s):";
 lblTotalTime.Size = new Size((int)(Font.Height * .5) * 
 lblTotalTime.Text.Length, 25);
 lblTotalTime.Location = new Point(ClientSize.Width / 10, 100);
 
 dtpTotalTime = new DateTimePicker( );
 dtpTotalTime.Parent = this;
 dtpTotalTime.Format = DateTimePickerFormat.Custom;
 dtpTotalTime.CustomFormat = "H:mm:ss";
 dtpTotalTime.Value = DateTime.Parse("00:00:00");
 dtpTotalTime.ShowUpDown = true;
 dtpTotalTime.Size = new Size((int)(Font.Height * .6) * 
 dtpTotalTime.Value.ToString("t").Length,
 dtpTotalTime.PreferredHeight);
 dtpTotalTime.Location = new Point(lblTotalTime.Right, 100);
 
 btnStart = new Button( );
 btnStart.Parent = this;
 btnStart.Text = "Start";
 btnStart.Location = new Point(ClientSize.Width / 4, 300);
 btnStart.Click += new EventHandler(btnStart_Click);
 
 btnStop = new Button( );
 btnStop.Parent = this;
 btnStop.Text = "Stop";
 btnStop.Location = new Point(btnStart.Right + 10, 300);
 btnStop.Click += new EventHandler(btnStop_Click);
 
 lblTimesUp = new Label( );
 lblTimesUp.Parent = this;
 lblTimesUp.Size = new Size(200, 35);
 lblTimesUp.Location = new Point(btnStart.Left, 
 btnStart.Top - 75);
 lblTimesUp.Text = "";
 lblTimesUp.Font = new Font("Times New Roman Bold", 20);
 } // close for constructor
 
 static void Main( ) 
 {
 Application.Run(new CountDownTimer( ));
 }
 
 private void t_Tick(object sender, EventArgs e)
 {
 Invalidate( );
 } 
 
 protected override void OnPaint(PaintEventArgs e)
 {
 base.OnPaint(e);
 Graphics g = e.Graphics;
 Brush b = new SolidBrush(ForeColor);
 StringFormat fmt = new StringFormat( );
 fmt.Alignment = StringAlignment.Near;
 PointF pt = new PointF(ClientSize.Width / 10, 150);
 Font fnt = new Font("Arial", 12);
 String str = "Current Time: " + 
 DateTime.Now.ToString("F") + "

";
 
 if (boolStart)
 {
 TimeSpan ts = new TimeSpan( );
 ts = dtEndTime - DateTime.Now;
 DateTime dt = new DateTime( );
 dt = DateTime.Parse(ts.ToString( ));
 str += "Remaining Time: " + dt.ToString("HH:mm:ss");
 }
 else
 {
 str += "Remaining Time:";
 }
 g.DrawString(str, fnt, b, pt, fmt);
 
 if (boolStart && (dtEndTime - DateTime.Now) <= TimeSpan.Zero)
 {
 TimesUp( );
 }
 }
 
 private void btnStart_Click(object sender, EventArgs e)
 {
 lblTimesUp.Text = "";
 boolStart = true;
 TimeSpan ts = new TimeSpan( );
 ts = TimeSpan.Parse(dtpTotalTime.Value.Hour.ToString( ) + ":" + 
 dtpTotalTime.Value.Minute.ToString( ) + ":" + 
 dtpTotalTime.Value.Second.ToString( ));
 dtEndTime = DateTime.Now + ts;
 } 
 
 private void btnStop_Click(object sender, EventArgs e)
 {
 boolStart = false;
 } 
 
 private void TimesUp( )
 {
 lblTimesUp.Text = "Times Up!";
 boolStart = false;
 } 
 } // close for form class
} // close form namespace

Example 16-7. CountDownTimer in VB.NET (CountDownTimer.vb)

figs/vbicon.gif

Option Strict On
imports System
imports System.Drawing
imports System.Windows.Forms
 
namespace ProgrammingWinApps
 public class CountDownTimer : inherits Form
 
 dim dtpTotalTime as DateTimePicker
 dim btnStart as Button
 dim btnStop as Button 
 dim boolStart as Boolean = false
 dim dtEndTime as DateTime
 dim lblTimesUp as Label
 dim lblTitle as Label
 
 public sub New( )
 Text = "CountDown Timer"
 Size = new Size(500,400)
 
 FormBorderStyle = FormBorderStyle.FixedDialog
 Font = new Font("Arial", 12)
 
 dim t as new Timer( )
 t.Interval = 1000
 t.Start( )
 AddHandler t.Tick, AddressOf t_Tick
 
 lblTitle = new Label( )
 lblTitle.Parent = me
 lblTitle.Font = new Font("Arial Black", 24)
 lblTitle.Text = "CountDown Timer"
 lblTitle.TextAlign = ContentAlignment.MiddleCenter
 lblTitle.Size = new Size(CInt(lblTitle.Font.Height * .7) * _ 
 lblTitle.Text.Length, 35)
 lblTitle.Location = new Point(CInt(ClientSize.Width / 2 - _
 lblTitle.Width / 2), 25)
 
 dim lblTotalTime as new Label( )
 lblTotalTime.Parent = me
 lblTotalTime.Text = "Total Time (h:m:s):"
 lblTotalTime.Size = new Size(CInt(Font.Height * .5) * _
 lblTotalTime.Text.Length, 25)
 lblTotalTime.Location = new Point( _
 CInt(ClientSize.Width / 10), 100)
 
 dtpTotalTime = new DateTimePicker( )
 dtpTotalTime.Parent = me
 dtpTotalTime.Format = DateTimePickerFormat.Custom
 dtpTotalTime.CustomFormat = "H:mm:ss"
 dtpTotalTime.Value = DateTime.Parse("00:00:00")
 dtpTotalTime.ShowUpDown = true
 dtpTotalTime.Size = new Size(CInt(Font.Height * .6) * _
 dtpTotalTime.Value.ToString("t").Length, _
 dtpTotalTime.PreferredHeight)
 dtpTotalTime.Location = new Point(lblTotalTime.Right, 100)
 
 btnStart = new Button( )
 btnStart.Parent = me
 btnStart.Text = "Start"
 btnStart.Location = new Point(CInt(ClientSize.Width / 4), 300)
 AddHandler btnStart.Click, AddressOf btnStart_Click
 
 btnStop = new Button( )
 btnStop.Parent = me
 btnStop.Text = "Stop"
 btnStop.Location = new Point(btnStart.Right + 10, 300)
 AddHandler btnStop.Click, AddressOf btnStop_Click
 
 lblTimesUp = new Label( )
 lblTimesUp.Parent = me
 lblTimesUp.Size = new Size(200, 35)
 lblTimesUp.Location = new Point(btnStart.Left, _
 btnStart.Top - 75)
 lblTimesUp.Text = ""
 lblTimesUp.Font = new Font("Times New Roman Bold", 20)
 end sub ' close for constructor
 
 public shared sub Main( ) 
 Application.Run(new CountDownTimer( ))
 end sub
 
 private sub t_Tick(ByVal sender as object, _
 ByVal e as EventArgs)
 Invalidate( )
 end sub
 
 protected overrides sub OnPaint(ByVal e as PaintEventArgs)
 myBase.OnPaint(e)
 dim g as Graphics = e.Graphics
 dim b as new SolidBrush(ForeColor)
 dim fmt as new StringFormat( )
 fmt.Alignment = StringAlignment.Near
 dim pt as new PointF(CInt(ClientSize.Width / 10), 150)
 dim fnt as new Font("Arial", 12)
 dim str as string = "Current Time: " + _
 DateTime.Now.ToString("F") + vbCrLf + vbCrLf
 
 if boolStart then
 dim ts as new TimeSpan( )
 ts = DateTime.op_Subtraction(dtEndTime, DateTime.Now)
 dim dt as new DateTime( )
 dt = DateTime.Parse(ts.ToString( ))
 str += "Remaining Time: " + dt.ToString("HH:mm:ss")
 else
 str += "Remaining Time:"
 end if
 g.DrawString(str, fnt, b, pt, fmt)
 
 if (boolStart and _
 (TimeSpan.op_LessThanOrEqual(DateTime.op_Subtraction( _
 dtEndTime, DateTime.Now), TimeSpan.Zero))) then
 TimesUp( )
 end if
 end sub
 
 private sub btnStart_Click(ByVal sender as object, _
 ByVal e as EventArgs)
 lblTimesUp.Text = ""
 boolStart = true
 dim ts as new TimeSpan( )
 ts = TimeSpan.Parse(dtpTotalTime.Value.Hour.ToString( ) + ":" + _
 dtpTotalTime.Value.Minute.ToString( ) + ":" + _
 dtpTotalTime.Value.Second.ToString( ))
 dtEndTime = DateTime.op_Addition(DateTime.Now, ts)
 end sub
 
 private sub btnStop_Click(ByVal sender as object, _
 ByVal e as EventArgs)
 boolStart = false
 end sub
 
 private sub TimesUp( )
 lblTimesUp.Text = "Times Up!"
 boolStart = false
 end sub
 
 end class
end namespace

The FormBorderStyle is set in the constructor to FormBorderStyle.FixedDialog, which prevents the user from resizing the form. By doing so, there is no need to anchor any of the controls or otherwise worry about how the look of the form will be affected by user interaction. Also in the constructor, the default font for the form is set to 12-point Arial.

figs/vbicon.gif

 FormBorderStyle = F

figs/vbicon.gif

ormBorderStyle.FixedDialog
Font = new Font("Arial", 12)

The Timer is declared and instantiated in the constructor, with the Interval property set to one second (1,000 milliseconds) and the Start method called to enable the timer. An event handler is added for the Tick event:

figs/csharpicon.gif

Timer t = new Timer( );
t.Interval = 1000;
t.Start( );
t.Tick += new EventHandler(t_Tick);
dim t as new Ti

figs/vbicon.gif

mer( )
t.Interval = 1000
t.Start( )
AddHandler t.Tick, AddressOf t_Tick

The DateTimePicker control is used here as a convenient way for the user to enter the time to count down in hours, minutes, and seconds. This use requires that the value initially be set to "00:00:00" (which is cast from a string to a DateTime object using the static DateTime.Parse method) and displayed using a custom format, "H:mm:ss." As you recall from Table 16-9, the leading uppercase H in that format string specifies a one- or two-digit hour in a 24-hour format.

figs/vbicon.gif

dtpTotalTime.Format = DateTimePickerFormat.Custom
dtpTotalTime.CustomFormat = "H:mm:ss"
dtpTotalTime.Value = DateTime.Parse("00:00:00")

At first, this custom formatting may seem unnecessary, since the DateTimePickerFormat.Time format should provide what you are looking for. However, if the Time format is used, the DateTimePicker control displays 12:00:00, rather than the desired 00:00:00.

Notice that the horizontal component of the Size property of the DateTimePicker control is calculated using the Value property of the control in conjunction with the ToString method, taking a formatting argument to retrieve the number of characters. From Table 16-10, you saw that the "t" formatting string corresponds to a short time display, which is effectively how the custom format used by the control appears. As with all the Size calculations based on the Font.Height property, the ".6" factor is arrived at empirically:

figs/csharpicon.gif

dtpTotalTime.Size = new Size((int)(Font.Height * .6) *
 dtpTotalTime.Value.ToString("t").Length,
 dtpTotalTime.PreferredHeight);

figs/vbicon.gif

dtpTotalTime.Size = new Size(CInt(Font.Height * .6) * _
 dtpTotalTime.Value.ToString("t").Length, _
 dtpTotalTime.PreferredHeight)

The TimesUp label is positioned, sized, and given a nice bold 20-point font, but the Text property is initially set to an empty string. The Text property will be set appropriately as necessary, as you will see in a moment.

Now turn your attention to the Start button. The Click event handler for the Start button first clears the TimesUp label.

figs/vbicon.gif

lblTimesUp.Text = ""

Next it sets a flag, boolStart, to true. This flag was initialized to false as a class member variable.

figs/vbicon.gif

boolStart = true

Now comes a tricky part. The value in the DateTimePicker control is a DateTime object. It must be converted to a TimeSpan object so that the ending time, dtEndTime, which is a DateTime object, can be calculated. This is necessary because the DateTime Addition operator (and the DateTime Add method, as well) can only add a TimeSpan to a DateTime, not add together two DateTimes.

The conversion of the DateTimePicker value to a TimeSpan is accomplished by using the static TimeSpan.Parse method, which takes a string argument. That string argument is built up by calling the ToString method against the Hour, Minute, and Second components of the DateTimePicker control's Value property.

Then the ending time can be calculated by adding the resulting TimeSpan object to the current time:

figs/csharpicon.gif

TimeSpan ts = new TimeSpan( );
ts = TimeSpan.Parse(dtpTotalTime.Value.Hour.ToString( ) + ":" + 
 dtpTotalTime.Value.Minute.ToString( ) + ":" + 
 dtpTotalTime.Value.Second.ToString( ));
dtEndTime = DateTime.Now + ts;

figs/vbicon.gif

dim ts as new TimeSpan( )
ts = TimeSpan.Parse(dtpTotalTime.Value.Hour.ToString( ) + ":" + _
 dtpTotalTime.Value.Minute.ToString( ) + ":" + _
 dtpTotalTime.Value.Second.ToString( ))
dtEndTime = DateTime.op_Addition(DateTime.Now, ts)

Notice that the C# version allows the use of the + DateTime operator, and the VB.NET version does not. Instead, it uses the shared DateTime method DateTime.op_Addition.

You could get the correct value for ts, the TimeSpan object with the following line of code:

figs/csharpicon.gif

TimeSpan ts = dtpTotalTime.TimeOfDay;

figs/vbicon.gif

dim ts as new TimeSpan( ) = _
 dtpTotalTime.TimeOfDay

However, doing so this way would not allow a demonstration of the TimeSpan.Parse method.

Now that you have the boolStart flag and the ending time, dtEndTime, you can handle the Tick event.

The Tick event handler consists of a single line of code, which invalidates the form and causes the OnPaint method to be invoked. This OnPaint method has been overridden, so it draws the text strings containing the current time of day and the remaining time being counted down.

Chapter 10 covers the technique of using the Invalidate method to repaint the form or part of the form.

The overridden OnPaint method first chains up to the base class:

figs/csharpicon.gif

base.OnPaint(e);

figs/vbicon.gif

myBase.OnPaint(e)

Next it declares and instantiates several objects, which will be used shortly in the Graphics DrawString method:

  • A Graphics object.
  • A Brush object with the foreground color (which defaults to black on most systems).
  • A StringFormat object used to set the Alignment property. (StringAlignment.Near corresponds to Left in a Left-to-Right languagesee Tables 9-8 and 9-9 for a description of the StringAlignment enumeration.)
  • A PointF object.
  • A Font object specifying 12-point Arial.
  • A string object containing the current time, formatted with the "F" formatting string:

figs/csharpicon.gif

Graphics g = e.Graphics;
Brush b = new SolidBrush(ForeColor);
StringFormat fmt = new StringFormat( );
fmt.Alignment = StringAlignment.Near;
PointF pt = new PointF(ClientSize.Width / 10, 150);
Font fnt = new Font("Arial", 12);
String str = "Current Time: " + 
 DateTime.Now.ToString("F") + "

";

figs/vbicon.gif

dim g as Graphics = e.Graphics
dim b as new SolidBrush(ForeColor)
dim fmt as new StringFormat( )
fmt.Alignment = StringAlignment.Near
dim pt as new PointF(CInt(ClientSize.Width / 10), 150)
Font fnt = new Font("Arial", 12)
dim str as string = "Current Time: " + _
 DateTime.Now.ToString("F") + vbCrLf + vbCrLf

The specified string will be drawn with every timer ticki.e., every second. The contents of the next string, however, depend on whether the application is counting down. For this, it tests the boolStart flag, which was set in the Start button Click event handler.

If the boolStart flag is true, then another string is built up by subtracting the current time, DateTime.Now, from the ending time, dtEndTime, which was calculated in the Start Button event handler. This process is surprisingly tricky. You might think you could use the following code to display the remaining time, where the TimeSpan is calculated and then displayed using the TimeSpan ToString method.

figs/csharpicon.gif

TimeSpan ts = new TimeSpan( );
ts = dtEndTime - DateTime.Now;
str += "Remaining Time: " + ts.ToString( );

This works, but it displays the time with hours, minutes, and fractional seconds, as in 01:01:01.1234567, with the seconds displaying seven decimal digits. You should, however, display only hours, minutes, and whole seconds, as in 01:01:01.

No problem, you think: I'll just add a formatting argument to the ToString method. However, this causes a compiler error. The DateTime.ToString method accepts a formatting argument, but the TimeSpan.ToString does not. So you need to convert the TimeSpan to a DateTime, using the static DateTime.Parse method. This method takes a string argument, so you give it the TimeSpan object converted to a string with ToString. Then the string for display can be built up using the DateTime ToString, which accepts the formatting argument.

The complete code section for testing the boolStart flag, constructing the line that displays the remaining time and drawing the two lines of text, is reproduced here:

figs/csharpicon.gif

if (boolStart)
{
 TimeSpan ts = new TimeSpan( );
 ts = dtEndTime - DateTime.Now;
 DateTime dt = new DateTime( );
 dt = DateTime.Parse(ts.ToString( ));
 str += "Remaining Time: " + dt.ToString("HH:mm:ss");
}
else
{
 str += "Remaining Time:";
}
g.DrawString(str, fnt, b, pt, fmt);

figs/vbicon.gif

if boolStart then
 dim ts as new TimeSpan( )
 ts = DateTime.op_Subtraction(dtEndTime, DateTime.Now)
 dim dt as new DateTime( )
 dt = DateTime.Parse(ts.ToString( ))
 str += "Remaining Time: " + dt.ToString("HH:mm:ss")
else
 str += "Remaining Time:"
end if
g.DrawString(str, fnt, b, pt, fmt)

The final piece of the OnPaint method tests to see if time has expired. If so, it calls the TimesUp helper method:

figs/csharpicon.gif

if (boolStart && (dtEndTime - DateTime.Now) <= TimeSpan.Zero)
{
 TimesUp( );
}

figs/vbicon.gif

if (boolStart and _
 (TimeSpan.op_LessThanOrEqual(DateTime.op_Subtraction( _
 dtEndTime, DateTime.Now), TimeSpan.Zero))) then
 TimesUp( )
end if

Again, as with the TimeSpan and DateTime operators used previously, the C# version uses the <= operator, while the VB.NET version must use the shared TimeSpan.op_LessThanOrEqual method.

The TimesUp method is simple. It sets the Text property of the lblTimesUp label and resets the boolStart flag to false.

The Stop button Click event handler is also simpleit just sets the boolStart flag to false. The next time the Tick event fires and the OnPaint method is called, the form will correctly display with the count down stopped.

Windows Forms and the .NET Framework

Getting Started

Visual Studio .NET

Events

Windows Forms

Dialog Boxes

Controls: The Base Class

Mouse Interaction

Text and Fonts

Drawing and GDI+

Labels and Buttons

Text Controls

Other Basic Controls

TreeView and ListView

List Controls

Date and Time Controls

Custom Controls

Menus and Bars

ADO.NET

Updating ADO.NET

Exceptions and Debugging

Configuration and Deployment



Programming. NET Windows Applications
Programming .Net Windows Applications
ISBN: 0596003218
EAN: 2147483647
Year: 2003
Pages: 148

Flylib.com © 2008-2020.
If you may any questions please contact us: flylib@qtcs.net