October 28, 2006

Lightweight System Tray Application (NotifyIcon Based)

Many developers have wanted to create an application that runs fully out of the system tray, maybe an application to help you automatically sort files, or something to monitor the clipboard. Many people have implemented these applications and many textbooks provide instruction on how to create an application such as this, however, none of the books I have found show you the most effective way to create the application.

Typically creating a system tray application in .NET involves using a main form to control the application and setting the ShowInTaskbar property to false, to avoid having the application appear in the taskbar. This method is not the best for a few reasons; first with this method you have to listen for the close method of the form and prevent the form from actually closing because if the form closes the application will exit. You also have to manage the display to the user to ensure that they have an effective way to actually exit the application fully as the previous point makes the standard method ineffective.

The method I have found involves creating a new ApplicationContext object and declaring the NotifyIcon and ContextMenu in the code for the application context. An application context object can be used by the "Application.Run()" method to actually run the application. In your standard Windows applications you will see something like the following to start your application.

[STAThread]
static void Main()
{
    Application.EnableVisualStyles()
;
    
Application.SetCompatibleTextRenderingDefault(false);
    
Application.Run(new Form1());
}

With this model the application is driven by the actions of "form1", once form one is closed the application exits. In the Application Context model we will create an object that will serve as the application context, but we must explicitly close it and it does not require a user interface form to be the center of the application.

To create this application we will perform the following tasks

  • Create a new class inheriting from "ApplicationContext" to serve as the driver of our application
  • Define the user interface elements within our "ApplicationContext"
  • Provide a method to safely exit the application

Creating a custom ApplicationContext Object

Using Microsoft Visual Studio 2005, create a new windows application and delete the automatically generated "Form1" windows form. Now, add a new class to your project and name it __ApplicationContext where __ is a descriptive name. For the example code the class I have created is DemoApplicationContext. In your class file add a reference to the System.Windows.Forms namespace if it is not already existing.

using System.Windows.Forms;

Now modify the class declaration to derive from the ApplicationContext base class. After doing this you should have a file with the following: (NOTE: using statements and namespace declarations removed for space)

public class DemoApplicationContext : ApplicationContext
{

}

Now we will setup our application to run this new application context object instead of the now missing "Form1" object. You will need to open the "program.cs" file and change the "Main" method to the following, this will update the application to use the newly created application context and load it when the application starts.

[STAThread]
static void Main()
{
    Application.EnableVisualStyles()
;
    
Application.SetCompatibleTextRenderingDefault(false);
    
DemoApplicationContext oContext = new DemoApplicationContext();
    
Application.Run(oContext);
}

This completes the first step of the process, we simply declare a new instance of our application context, then pass it to our "Application.Run" method to indicate that it is the focus of the application.

Defining the User Interface

Now that we have our application context created and the application starting, we need to create the user interface and set it up for display. For this sample we will be adding the notify icon to run in the system tray, and a context menu with two items. One to open our "Form" and one to exit the application. The first step to creating the user interface is to define all of our needed elements as private members of our DemoApplicationContext class. Below are the definitions for our demonstration application:

#region Private Members
private System.ComponentModel.IContainer mComponents
private NotifyIcon mNotifyIcon;
private 
ContextMenuStrip mContextMenu;
private 
ToolStripMenuItem mDisplayForm;
private 
ToolStripMenuItem mExitApplication;
#endregion

We have declared objects for our notify icon, as well as our context menu and the two items that will displayed on the menu. The next step is to create a default constructor for the DemoApplicationContext class which will initialize our private members and setup the user interface. Below is the code needed to setup the user interface for our demonstration, please view the inline comments for additional information along the way.

public DemoApplicationContext()
{
    
//Instantiate the component Module to hold everything
    
mComponents = new System.ComponentModel.Container();
    
    
    
//Instantiate the NotifyIcon attaching it to the components container and 
    //provide it an icon, note, you can imbed this resource 
    
mNotifyIcon = new NotifyIcon(this.mComponents);
    
mNotifyIcon.Icon = new System.Drawing.Icon("folder.ico");
    
mNotifyIcon.Text "System Tray Application Demo";
    
mNotifyIcon.Visible = true;

    
//Instantiate the context menu and items
    
mContextMenu = new ContextMenuStrip();
    
mDisplayForm = new ToolStripMenuItem();
    
mExitApplication = new ToolStripMenuItem();

    
//Attach the menu to the notify icon
    
mNotifyIcon.ContextMenuStrip mContextMenu;

    
//Setup the items and add them to the menu strip, adding handlers to be created later
    
mDisplayForm.Text "Display Form";
    
mDisplayForm.Click += new EventHandler(mDisplayForm_Click);
    
mContextMenu.Items.Add(mDisplayForm);

    
mExitApplication.Text "Exit";
    
mExitApplication.Click += new EventHandler(mExitApplication_Click);
    
mContextMenu.Items.Add(mExitApplication);
}

void mExitApplication_Click(object sender, EventArgs e)
{
    
throw new Exception("The method or operation is not implemented.");
}

void mDisplayForm_Click(object sender, EventArgs e)
{
    
throw new Exception("The method or operation is not implemented.");
}

At this point you can run the application in debug mode and you should see the Icon in the system tray and when right clicking you should be able to see your context menu. If you notice as of right now you do not have any method to exit the application. This will be discussed later in this article!

Exiting the Application

We will implement our code to exit the application in the "mExitApplication_Click" event that was created earlier in this article. To successfully implement an exit routine we need to ensure that all objects are disposed of prior to exiting the application. Therefore we will override the ApplicationContext base method "ExitThreadCore", in our overridden method we will dispose of any needed objects, then call the base method to actually exit our application. Below is the code needed to exit the application.

void mExitApplication_Click(object sender, EventArgs e)
{
    
//Call our overridden exit thread core method!
    
ExitThreadCore();
}

protected override void ExitThreadCore()
{
    
//Clean up any references needed
    //At this time we do not have any
    //

    //Call the base method to exit the application
    
base.ExitThreadCore();
}

You should now be able to run the application and select the "Exit Application" menu option and the application should exit.

Final Thoughts

This has provided a quick overview to the power of the ApplicationContext object and creating System Tray applications. I will leave it as a further lesson or future article to implement the methods to display and manage the display of windows forms from the application. To download the sample code used to create this article, please click the link below.

Demonstration Code

tags: Tutorials, Windows Applications, .NET 2.0
comments powered by Disqus

Content provided in this blog is provided "AS-IS" and the information should be used at your own discretion.  The thoughts and opinions expressed are the personal thoughts of Mitchel Sellers and do not reflect the opinions of his employer.

Content Copyright

Content in this blog is copyright protected.  Re-publishing on other websites is allowed as long as proper credit and backlink to the article is provided.  Any other re-publishing or distribution of this content is prohibited without written permission from Mitchel Sellers.