WPF
Tray Icon
Windows Application
Minimal UI
Software Development

WPF Application that only has a tray icon

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

A WPF application can run entirely from the Windows notification area without showing a main window at startup. The usual implementation uses System.Windows.Forms.NotifyIcon for the tray icon and configures the WPF application so it does not shut down just because no normal window is open.

The Core Design

A tray-only WPF app usually needs three pieces:

  • no StartupUri in App.xaml
  • 'ShutdownMode="OnExplicitShutdown"'
  • a NotifyIcon with a context menu and an explicit exit path

If you leave WPF in its default shutdown mode, the app often exits immediately because there is no visible main window keeping it alive.

Configure App.xaml

Remove StartupUri and set the shutdown mode explicitly.

xml
1<Application x:Class="TrayOnlyApp.App"
2             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4             ShutdownMode="OnExplicitShutdown">
5</Application>

This tells WPF that the application lifetime will be managed in code.

Create the Tray Icon in App.xaml.cs

The tray icon comes from Windows Forms, not native WPF controls.

csharp
1using System;
2using System.Windows;
3using System.Windows.Forms;
4
5namespace TrayOnlyApp
6{
7    public partial class App : Application
8    {
9        private NotifyIcon? _notifyIcon;
10
11        protected override void OnStartup(StartupEventArgs e)
12        {
13            base.OnStartup(e);
14
15            var menu = new ContextMenuStrip();
16            menu.Items.Add("Open", null, (_, _) => ShowMainWindow());
17            menu.Items.Add("Exit", null, (_, _) => ExitApplication());
18
19            _notifyIcon = new NotifyIcon
20            {
21                Icon = new System.Drawing.Icon("app.ico"),
22                Visible = true,
23                Text = "TrayOnlyApp",
24                ContextMenuStrip = menu
25            };
26
27            _notifyIcon.DoubleClick += (_, _) => ShowMainWindow();
28        }
29
30        private void ShowMainWindow()
31        {
32            if (Current.MainWindow == null)
33            {
34                Current.MainWindow = new MainWindow();
35            }
36
37            Current.MainWindow.Show();
38            Current.MainWindow.WindowState = WindowState.Normal;
39            Current.MainWindow.Activate();
40        }
41
42        private void ExitApplication()
43        {
44            if (_notifyIcon != null)
45            {
46                _notifyIcon.Visible = false;
47                _notifyIcon.Dispose();
48                _notifyIcon = null;
49            }
50
51            Shutdown();
52        }
53    }
54}

This pattern starts the app without showing a main window, but still gives the user a tray icon to interact with.

Hide Instead of Closing

If the app has a normal window that users can reopen from the tray, it is common to hide the window instead of destroying the whole application when they click the close button.

csharp
1using System.ComponentModel;
2using System.Windows;
3
4namespace TrayOnlyApp
5{
6    public partial class MainWindow : Window
7    {
8        protected override void OnClosing(CancelEventArgs e)
9        {
10            e.Cancel = true;
11            Hide();
12        }
13    }
14}

This keeps the process alive and lets the tray icon reopen the window later.

Important Cleanup

Always dispose the NotifyIcon before shutting down. If you do not, Windows can leave a ghost tray icon behind until the user hovers over it or Explorer refreshes the tray.

That is one of the most common "it mostly works" bugs in tray-only desktop apps.

Alternative Libraries

Some teams prefer wrapper libraries such as Hardcodet's taskbar-notification helpers because they integrate more naturally with WPF patterns. The underlying idea is still the same: WPF itself does not provide a first-class tray icon control, so you either wrap NotifyIcon yourself or use a helper library.

For a small app, the direct NotifyIcon approach is often enough.

Common Pitfalls

The biggest mistake is forgetting to change ShutdownMode. Without OnExplicitShutdown, a tray-only app may terminate as soon as there is no open WPF window.

Another issue is leaving StartupUri set, which causes a window to appear even though the app is supposed to live only in the tray.

Developers also forget to dispose the tray icon on exit, which leaves stale icons in the notification area.

Finally, if you hide the main window on close, make sure the user still has an obvious way to exit the application from the tray menu.

Summary

  • A tray-only WPF app usually uses NotifyIcon from System.Windows.Forms.
  • Set ShutdownMode="OnExplicitShutdown" and remove StartupUri.
  • Create the tray icon in App.xaml.cs and provide a context menu with an exit command.
  • Hide the main window instead of closing it if the app should keep running in the tray.
  • Dispose the tray icon cleanly before calling Shutdown().

Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.