System tray application basics for .NET 2.0

[ Comment: This code was originally written for .NET 1.1 and ported as is. As such, it should not refer to .NET 2.0 at all. Please refer to the comments of Stefan Els below for a 'real' and more elegant .NET 2.0 implementation ]

Providing a basic 'system tray application' using VS2005/C#/.NET 2.0 is very simple.

The functionality is this:

  • .NET Windows Forms application.
  • When the main window is closed, the application is not terminated - instead the main window is not visible and an icon appears in the system tray (Win XP/XP Server 2003). This can also be extended to provide the same functionality when the window is minimized.
  • The system tray icon provides a context menu with at least a Restore and Exit option.
  • The Restore option reverses the process by making the main window appear again, and removing the system tray icon.
  • The Exit option provides for standard and proper program termination.

The sample code (see below) makes no attempt to restrict the application to a single instance.  That aspect is handled here:

The code below is commented and largely self-explanatory. The following form controls are required:

  • A NotifyIcon control to display and manage the application in the system tray.
  • A ContextMenuStrip control which has to be referenced by the NotifyIcon control, and contains the Restore and Exit menu items.

// NotifyIcon control added to the form. private System.Windows.Forms.NotifyIcon niApp;

.. ..

// Flags actual application termination. private bool _exitApplication = false; // Response method called when form is requested to close. protected override void OnClosing(CancelEventArgs e) { // If actual termination is flagged, do it! if (_exitApplication == true) { e.Cancel = false; } else { // Not exiting - cancel. e.Cancel = true; // Instead of exiting - hide form. Visible = false; } } // Windows message constant for system shutdown request. private const int WM_QUERYENDSESSION = 0x11; protected override void WndProc(ref Message msg) { if (msg.Msg == WM_QUERYENDSESSION) { // If system is shutting down, allow exit. _exitApplication = true; } base.WndProc(ref msg); } // Response method called when form visibility changes. protected override void OnVisibleChanged(EventArgs e) { base.OnVisibleChanged(e); // Change visibility of tray icon - opposite to forms visibility. niApp.Visible = Visible ? false : true; } // Context menu Restore option response method. private void tsmRestore_Click(object sender, EventArgs e) { // Show form. Visible = true; } // context menu Exit option response method. private void tsmExit_Click(object sender, EventArgs e) { // Ensure window close. _exitApplication = true; // Exit the application. Application.Exit(); }

This article is part of the GWB Archives. Original Author: Willem Fourie

New on Geeks with Blogs

  • We Won The One Award I Actually Care About

    Full Scale made the Inc. 5000 for the fifth year straight, the 12th listing across my three companies. Here is why the one award you cannot buy is worth stopping for.

  • Your Customers Build the Features Now

    I let a tool I liked sit dead for a year rather than build the features I wanted. An MCP server meant I never had to, and your customers can do the same to your product.

  • Get the Size of a Directory in Linux the Easy Way

    du -sh for the quick answer, ncdu for the cleanup, df for the disk itself: every command for checking directory size in Linux, plus why du and df never agree.

  • Vim Search and Replace: The Ultimate Guide

    One :%s command replaces every match in a file before a find dialog would even open. The Vim substitute patterns worth the muscle memory: flags, ranges, capture groups, and multi-file edits.