This tutorial demonstrates one way to create an application that runs without
any Forms but still has a GUI presence via an Icon in the System Tray.
The magic lies in Inheriting from the ApplicationContext Class and passing that to Application.Run() instead of a Form instance. With this approach we automatically get a built-in message pump and do not
see any ugly Console windows. Having a message pump means that an infinite loop is not
necessary to keep the app "alive". It also means that we can freely create Controls and Forms at run-time and respond to their events as usual. We can even elegantly multi-thread the application by using a BackgroundWorker() Control from within the Inherited ApplicationContext Class.
Why would you want to do this? Perhaps you have a "background" operation that needs to run all the time and would like to give the user a way to interact with the application. The tray icon gives you the option to display menus or simply popup a configuration dialog if clicked. This is an easy approach compared to implementing a full blown service.
The ApplicationContext provides complete freedom in controlling when the program is closed. You are no longer constrained to just the two shutdown mode choices of "When startup form closes" or "When last form closes". With no "startup form" you can now freely switch between forms without worrying about the app closing on you. You can display a Login form and then actually completely close it before moving on to the Main form. No more need to show the Main form with ShowDialog() or keep the Login form hidden just to keep the app alive! Shared variables in the ApplicationContext class can be used to store information that the entire program needs access to (such as privilege levels). Since the app only shuts down when you explicitly call Application.Exit() you can build a program that only closes when the conditions are right for your particular scenario.
Note that this technique can also be used without any GUI elements at all! The app will happily run without any interface and will still have a message pump making it easier to work with than a Console app.
Let's get started:
1. Project Type
Start with a standard WinForms Application
2. Project Properties
Click on Project --> Properties
3. Change the Entry Point
Disable the Application Framework and set the "Startup Object"
4. Add Tray Icon
Switch to the Resources Tab and add your Icon File (.ico)
5. Embed the Icon
Change the Persistence Mode of the Icon to Embedded
6. Add Module
Add a Module to the Project. Leave the default name, Module1
7. ([b]Optional[/b]) Remove Form1
Delete the default Form if you don't need it
(Forms can still be used in the application if you desire!)
8. Add Code
Replace the code in the Module with the listing below.
Change "My.Resources.Happy" in line #17 so that it correctly reflects the name of your
Public Sub Main()
Public Class MyContext
Private WithEvents TrayIcon As New NotifyIcon
Private WithEvents CMS As New ContextMenuStrip
Private WithEvents ExitMenu As New ToolStripMenuItem("Exit")
Public Sub New()
TrayIcon.Icon = My.Resources.Happy
TrayIcon.Text = "ApplicationContext with a NotifyIcon" ' <-- Tooltip on the NotifyIcon
TrayIcon.Visible = True
TrayIcon.ContextMenuStrip = CMS
' You can add a BackgroundWorker control to the class and start a lengthy process from here...
Private Sub CMS_Opening(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles CMS.Opening
' From this event you can control which menu items appear (visibility or disabled) or
' even cancel the event and prevent the context menu from appearing at all
Private Sub ExitMenu_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles ExitMenu.Click
Private Sub MyContext_ThreadExit(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.ThreadExit
TrayIcon.Visible = False
9. Test it out!
Run the Project
Hopefully you'll get an Icon in the System Tray that has an "Exit" option when you Right Click it
In the images below, the Happy face is the icon being displayed by the application: