Entries:
Comments:
Posts:

Loading User Information from Channel 9

Something went wrong getting user information from Channel 9

Latest Achievement:

Loading User Information from MSDN

Something went wrong getting user information from MSDN

Visual Studio Achievements

Latest Achievement:

Loading Visual Studio Achievements

Something went wrong getting the Visual Studio Achievements

Countdown to...

  This application starts with a fairly simple premise—counting down to a date—then starts adding interesting features.
Arian Kulp's Blog

Difficulty: Intermediate
Time Required: Less than 1 hour
Cost: Free
Software: Visual Basic or Visual C# Express Editions,
Hardware:
Download:

Well, the year's winding down to an end, and the holiday season is upon us. Whether you are looking forward to Christmas (December 25), Hanukkah (December 26-January 1), Winter Solstice (December 21), or my birthday (December 29), you are probably counting down the days. Perhaps even the hours, minutes, and seconds until that great event (better get my presents sent a few days early so they arrive in time!). Looking at a calendar each day isn't really good enough. What you really need is a real-time countdown timer so you never lose your focus. What better way to do this than with a countdown utility application built using the .NET Framework! In this In the Box (Holiday Guide) installment, I decided to create a System Tray utility to display a countdown as a tooltip, and optionally as an overlay on the screen.

Code for the sample is available as a download at the top of the page, and is offered in both C# and Visual Basic. You will need either the C# or Visual Basic version (or both) of Visual Studio 2005 Express Edition. These have just been released out of beta, and are available for free for one year! Take advantage of this while you can. What better way to get started writing great .NET code?

In writing this application, I wanted to display a countdown, but also glitz it up a bit. Just showing a battleship-grey dialog with a standard title, minimize/close buttons and borders didn't sound very appealing. Instead, I decided to explore some methods of creating non-traditional windows. Though the effect is still somewhat simplistic, it was a great introduction to "windows without borders" (sounds like a political organization!). As with typical System Tray applications, hovering over the icon displays the application name. Of course it also displays the countdown itself. Right-clicking the icon displays a context menu, and you have the option of changing the settings, or exiting (but why would you do that?).

The fun part started with customizing the window. You can get rid of the Minimize/Maximize/Close button in the upper right by setting the form's ControlBox property to false. Eliminating the title bar entirely is accomplished by setting the form's Text property to an empty string. The borders go away when you set FormBorderStyle to None. Once you've done that, you are left with a grey rectangle floating on the screen. Two problems emerge. First of all, you can't close it, and second, you can't move it. You can alleviate the first issue by setting the form's visibility using a context menu attached to the icon in the System Tray. The second problem is more challenging.

It turns out that moving a form isn't especially difficult, but if you need to do it yourself, it does take a little work. It requires the capture of two events: MouseDown and MouseMove. The basic gist of it is, upon the MouseDown event, you need to capture the coordinates of the mouse. Then, for each MouseMove event, invoke the form's Move method taking into account the delta movement of the mouse. In other words, if the mouse click was detected at coordinates (0, 0), then a move event was triggered at coordinates (10,10), move the form from its original position, +10 on the x-axis, and +10 on the y-axis. It's clearer looking at some code:

Visual C#

// Class-level declaration
private Point mouseOffset; 

...

private void countdownLabel_MouseDown(object sender, MouseEventArgs e)
{
    mouseOffset = new Point(-e.X, -e.Y);
}

private void countdownLabel_MouseMove(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Left)
    {
        Point mousePos = Control.MousePosition;

        if (constrainToRight)
        {
            this.Top = Control.MousePosition.Y + mouseOffset.Y;
        }
        else

        {
            mousePos.Offset(mouseOffset.X, mouseOffset.Y);
            this.Location = mousePos;
        }
    }
} 

Visual Basic

 
'Class-level declaration 
Dim mouseOffset As PointPrivate 
Sub countdownLabel_MouseDown(ByVal sender As Object, ByVal e As MouseEventArgs) _
        Handles countdownLabel.MouseDown
    mouseOffset = New Point((e.X * -1), (e.Y * -1))
End Sub 

Private Sub countdownLabel_MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs) _
        Handles countdownLabel.MouseMove
    If (e.Button = Windows.Forms.MouseButtons.Left) Then
        Dim mousePos As Point = Control.MousePosition 

        If constrainToRight Then
            Me.Top = (Control.MousePosition.Y + mouseOffset.Y)
        Else
            mousePos.Offset(mouseOffset.X, mouseOffset.Y)
            Me.Location = mousePos
        End If
    End If
End Sub 

You can monitor these mouse events from the form itself, or from any control. In this case, the form will contain one visual control: a label. It's the label that will display the current countdown string. In order to get rid of the plain rectangular window shape surrounding it, you can actually turn it invisible. Set the form's TransparencyKey property to Control, and any grey regions will disappear. It's a great effect, it's easy, and it can lead to some interesting effects. Imagine if you used a bitmap as the background of the form. It would be easy to add rounded edges, or other irregular effects this way.

Figure 1. The Settings Dialog

Once it was possible to move the frame, I decided to add a feature to constrain the countdown to the right side of the screen. This involves a slight change to the code in the MouseMove event handler. Using the width of the screen and the width of the countdown label, you can calculate how far the form's coordinates should be. The label control's AutoSize propery was set to true, so it makes it very easy to determine the width of the text. Once you've done all of this, just use the length information to calculate the left edge of the form and force it to that value, regardless of the mouse movement. Of course, you could constrain to the left side even easier—just force the X coordinate to always be zero.

Two more visual effects are to allow you to set the countdown as the topmost form, and to alter the overall transparency. Setting the TopMost property to true keeps the form on top of all other non-topmost windows. As it turns out, this is especially useful when trying to click on the form to move it! Because of the way opacity works, getting rid of the form background makes it necessary to click exactly on black pixels (in the countdown itself) to actually move anything. This is harder than it seems. Changing the transparency allows you see other forms behind the countdown. As this information isn't something you need to fully focus on at all times, this is a nice feature. Just set the Opacity property to a value from 0 to 100.

Figure 2. Specifying a low Opacity value

Finally, the countdown itself: a timer ticks each second. On the Tick event, the current date is compared to the configured date. If the date has been reached, an alert is displayed in the countdown form and as a System Tray tooltip. Otherwise, a string is built up to display the number of days, hours, minutes, and seconds until the event. This is pretty easy string composition using the Append method of a StringBuilder object. The StringBuilder class is a more efficient way of concatenating strings than the "plus" operation. This is because of the way memory is allocated when the string value changes.

Next Steps

The application works as-is, but can certainly stand some enhancements. For one thing, playing a sound or a song when the event is reached would be fun! A festive holiday tune, birthday song, or maybe a voice recording would make sense. Using a nice bitmap for the background of the form could provide an easier place to click for dragging it, and would be visually appealing. See what else you can come up with.

Conclusion

This application starts with a fairly simple premise—counting down to a date—then starts adding interesting features. See what you can do to spice up your applications. Go to the Visual Studio Express Web site at http://msdn.microsoft.com/vstudio/express/default.aspx. Remember that all editions are now free for one year, and you can download as many versions as you'd like. Download one or more today, and get started writing great applications!

Follow the Discussion

  • DonDon

    Am I missing something?  The article says that the code for the app is available as a download at the top of the page.  When I download it, it comes as a .msi file which tries to install the program on my computer, not give me that code.  Am I such a newbie that I'm missing something totally obvious?

    Thanks!

  • Clint RutkasClint I'm a "developer"

    @Don

    If you did a default install, should be something like:

    C:\Users\crutkas\Documents\MSDN\Holiday Countdown - CS\

    This is with my user account and running Vista, XP's path may be different.

    Then open up the Countdown.sln file.  The solution will require a conversion if you have Visual Studio 2008.  Just click through the conversion wizard.

  • ShaneShane

    The code is no longer available for download.  Can you point me to where to get it or put it back in place, please?  Thanks.

  • Clint RutkasClint I'm a "developer"

    @Shane, I just tried both links and they work.

Remove this comment

Remove this thread

close

Comments Closed

Comments have been closed since this content was published more than 30 days ago, but if you'd like to continue the conversation, please create a new thread in our Forums,
or Contact Us and let us know.