Welcome to WindowsClient.net | Sign in | Join

Creating Applications with NotifyIcon in Windows Forms

by Jessica Fosler

Download the sample

Overview

 

This article explains how to implement the common features required of a notification-based application in Windows Forms: starting up a Windows Forms application without showing a Form, using the NotifyIcon, bringing an existing Form to the front of the desktop, and closing the Form on minimize.

 

The accompanying sample is a Calendar application. By double clicking on the notify icon, a simple form containing a month calendar appears. There is a context menu with “Show Calendar” and “Exit” menu items. This article walks through the implementation of the sample.




Creating the NotifyIcon UI

Classes we’ll need

-          System.Windows.Forms.NotifyIcon

-          System.Windows.Forms.ContextMenu

-          System.Windows.Forms.MenuItem

 

For this application, we’ll need to create a new NotifyIcon, ContextMenu, and a few MenuItems for the ContextMenu. The icon is set, and the NotifyIcon is set to Visible = true. The NotifyIcon.Text property is used in order to display a ToolTip on mouse hover.

 

// add context menu with “Show Calendar” and “Exit”

this.calendarNotifyIcon.ContextMenu = calendarNotifyIconContextMenu;

 

// subscribe to the double click event so we can show the calendar

this.calendarNotifyIcon.DoubleClick += new

EventHandler(this.calendarNotifyIcon_DoubleClick);

 

// add a custom icon for the notify icon to display

this.calendarNotifyIcon.Icon = new Icon(…);

 

// set the tooltip for the notify icon

this.calendarNotifyIcon.Text = DateTime.Now.ToLongDateString();

 

// tell the notify icon to make itself visible

this.calendarNotifyIcon.Visible = true;

Creating the CalendarForm

 

The CalendarForm is a simple Form with a MonthCalendar filled inside of it. The MaximizeBox has been turned off for the form (as it is as large as the calendar likes to be) and Minimimum and Maximum sizes have been set for the form.

 

Starting the application without showing a form

So far, so great, but we haven’t yet solved the Main challenge: starting the application without showing a form.

Let’s take a step back and look at how the first line of code in our program actually works: Application.Run.

Dissecting Application.Run

If you have created a Windows Forms application, you may have happened across this line in Main:

 

Application.Run(new Form1());

 

Magically, after calling this, the Form appears and events start firing left and right. Here’s what is actually happening, not quite so magically:

 

//Taking a microscope to Application.Run –

//create the form, and call initialize component

Form1 form1 = new Form1();

 

// create an application context

ApplicationContext applicationContext = new ApplicationContext();

 

// Set applicationContext.MainForm so that

// when form1 closes, exit the application context

applicationContext.MainForm = form1;

 

// Call Application.Run which will

// - call applicationContext.MainForm.Show()

// - begin processing events

Application.Run(applicationContext);

 

From this code, we can intuit that the ApplicationContext defines when the Application should exit. For regular windows applications, this model works well, but for notification-based applications, we’ll need to do something else. The solution: a custom ApplicationContext.

Creating a custom ApplicationContext

Creating a custom application context is super simple.

 

ApplicationContext applicationContext = new ApplicationContext();

Application.Run(applicationContext);

 

The only problem with the above two lines of code is that it shows nothing (we haven’t created a form or anything) and runs forever (we haven’t defined when the application should end). It’s likely this is not desired behavior.

 

  • To exit the application, we’ll need to figure out when to call applicationContext.ExitThread.
  • To bring up some sort of UI, we’ll need to do something interesting before calling Application.Run.

The simplest approach is to create the UI, hold onto the ApplicationContext and call ExitThread on it as a result of UI interaction. For our notification-based application, this will not work well, as we will want to keep the NotifyIcon UI separate (which will stick around all the time) from the form that we want to create and show (whenever the user clicks on the icon.)



In order to maintain this separation, let’s associate the NotifyIcon UI with the ApplicationContext, and create the Form on demand. In order to do this, we will create a class that inherits from ApplicationContext, create the notify icon UI and exit the application when the user selects the exit option from the notify icon’s context menu.

The CalendarApplicationContext Class

 

Here is an overview of the methods we’ll need to create in our custom CalendarApplication class.

 

 

 

Showing the Form

In order to show the calendar when the context menu item is clicked or the notify icon is double clicked; we will create a single method called ShowForm and call it from both places.

Creating the form

If there is no form currently displayed, the function creates a new Form and calls Show().

There are a few bookkeeping details to take into account: we want to show one form at a time, so we’ll save the Form off into a mainForm member variable. When the Form closes, we’ll go ahead and clear off this member so we remember to create a fresh new form the next time we’re asked.

 

Bringing existing forms to front

 

If the user selects “Show Calendar” again, it’s likely that the window is lost behind other windows, and they would like to make it visible again. If there is currently a mainForm, we call mainForm.Activate to bring it to the front of the Z-Order.

 

 

ShowForm implementation

 

/// <summary>

/// This function will either create a new CalendarForm or activate the /// existing one, bringing the window to front.

/// </summary>

private void ShowForm()

{

if (mainForm == null)

{

// create a fresh new CalendarForm and show it.

mainForm = new CalendarForm();

mainForm.Show();

// hook onto the closed event so we can null out the

// main form... this avoids reshowing

// a disposed form.

mainForm.Closed +=new EventHandler(mainForm_Closed);

}

else

{

// the form is currently visible, go ahead and bring it to

// the front so the user can interact

mainForm.Activate();

}

}

private void mainForm_Closed (object sender, EventArgs e)

{

// null out the main form so we know to create a new one.

this.mainForm = null;

}

 

Handling Exit

When the user selects the Exit context menu item, the click event handler for Exit calls ExitThread. If there is a mainForm currently being displayed, we override ExitThreadCore to clean it up by calling dispose on it.

 

CalendarApplicationContext Exit implementation

 

/// <summary>

/// When the exit menu item is clicked, make a call to terminate the /// ApplicationContext.

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

private void exitContextMenuItem_Click(object sender, EventArgs e)

{

ExitThread(); // this will call ExitThreadCore

}

 

/// <summary>

/// If we are presently showing a mainForm, clean it up.

/// </summary>

protected override void ExitThreadCore()

{

if (mainForm != null)

{

// before we exit, give the main form a chance

//to clean itself up.

mainForm.Close();

}

base.ExitThreadCore ();

}

Implementing Close on Minimize

 

Another common feature of notification-based applications is closing the form on Minimize. Thankfully the WindowState property off of Form tells us the current Min/Max state of the form, so in the CalendarForm class we can just go ahead and sync the SizeChanged event and call close.

 

private void CalendarForm_SizeChanged(object sender, EventArgs e)

{

if (this.WindowState == FormWindowState.Minimized)

{

this.Close();

}

}

Putting it all together

 

Create a class called CalendarForm that contains MonthCalendar. In Main, replace the Application.Run(new CalendarForm()) with our new ApplicationContext:

 

CalendarApplicationContext applicationContext =

new CalendarApplicationContext();

Application.Run(applicationContext);

 

The constructor creates the notify icon, and the CalendarForm is created on demand.

 

A final note

Obviously, a calendar application should strive to keep current with the date. A System.Windows.Forms.Timer can be used to update the date/time on the tooltip for the NotifyIcon and the CalendarForm.