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.

Timer component in Visual Studio .NET

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

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.

Timer demo

Figure 16-7. Timer demo

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

image with no caption

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 time—in 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.

Countdown timer

Figure 16-8. Countdown timer

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)

image with no caption

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)

image with no caption

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.

image with no caption

 FormBorderStyle = F

image with no caption

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:

image with no caption

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

image with no caption

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.

image with no caption

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:

image with no caption

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

image with no caption

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.

image with no caption

lblTimesUp.Text = ""

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

image with no caption

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:

image with no caption

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

image with no caption

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.

Note

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

image with no caption

TimeSpan ts = dtpTotalTime.TimeOfDay;

image with no caption

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.

Tip

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:

image with no caption

base.OnPaint(e);

image with no caption

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 language—see 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:

image with no caption

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") + "

";

image with no caption

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 tick—i.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.

image with no caption

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:

image with no caption

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);

image with no caption

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:

image with no caption

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

image with no caption

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 simple—it 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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset