Today something different. The problem I’ll write about is: how
to make a Windows Forms (C#) app minimize to tray when cliked on „X”
and prevent it from displaying in the taskbar.
In other words – how to make a „typical tray app”.
To be honest – I was quite sure there would be some component
(control) for it.
And there is (NotifyIcon) but… It’s not enough just to drag it to
our app designer form in Visual Studio to make it work as we would
like to.
Let’s begin with
opening Visual Studio and creating a new Windows Forms App:
File -> New ->
Project -> Windows Forms Apps -> Ok
First, wee drag
NotifyIcon component from Toolbox to our form (it will appear below
it, as it’s not visible in the form area, but outside it)
And here is the first strange behaviour: if we run (F5 or Ctrl+F5,
but i’d suggest F5 as it allows it to kill the app if something
goes wrong, and it can in
this case) our app, the
NotifyIcon component doesn’t seem to work. The tray icon
doesn’t show up, and neither minimization nor clicking the „X”
button causes our app to minimize to tray.
That’s because our
tray icon is not set and we haven't implemented minimization by clicking "X". First the icon: in order to set it, we need the tray icon
itself :)
We can just use
Paint to create it – set the canvas size to 16x16 (this is the
standard tray icon size in Windows), draw something beautiful and
save it as .jpg file. Now rename it to something.ico – simply
change the extension! The ico files are simply graphics files with a
particular extension.
Now you can copy it
to project – you can just drag it to project name in Solution
Explorer view in VS.
It should show up below (myicon.ico) in the image above.
Now if you hit F5,
the icon should show in the tray :)
The problem is it
doesn’t do anything. The app still minimizes to the taskbar.
So let’s edit the
code. Double click on the form project appearing in VS. The form code
should appear, and it should be similar to this:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
}
}
First of all, let’s make our icon actually do something: it should
show form if clicked twice, and hide it if clicked twice again. In
order to do it, select our NotifyIcon component in the designer
(Form1.cs [ Design] tab):
Now select the lightning icon in Properties windows (F4 if the window
is not visible), click the empty area on the right of
„MouseDoubleClick” and then double click on it again :)
An empty method should appear in the editor:
private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e)
{
}
Let's implement it:
private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e)
{
if (this.Visible == true)
{
this.Hide();
}
else
{
this.Show();
}
}
Now when you run the app and double click on the tray icon, the
window should disappear. Double click on the icon again, and the
window should appear. Now close the window – let’s get back to
the code: we’ll add a context (right click) menu to the tray icon.
The remaining
problems are as follows: the application exits, when we click „X”
in the top bar. This is correct behaviour for most apps, but those
enabled on tray should keep working even if „X” is clicked (the
typical way of closing them is to right click on the tray icon and
choosing „Close” or something similar from the context menu). The
second problem is: the application still appears on the „normal”
taskbar, and we want it to be minimized only to tray.
To fix the first
issue, modify the Form1 constructor in this way:
public Form1()
{
InitializeComponent();
this.FormClosing += this.Form1_FormClosing;
}
… and add the callback for FormClosing event below:
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing)
{
this.Hide();
e.Cancel = true;
}
}
If you want to run the app now, do it using F5 (not Ctrl+F5) –
you’ll need to terminate it using „Stop Debugging” (red square
button or Shift+F5 in Visual Studio). If you forget about it, you’ll
have to close it via the task manager :)
Now let’s add a
possibility of closing the app via the context menu for the tray
icon. In order to do that, switch to the Form1.cs [Design] view and
drag ContextMenuStrip component to your designer view (window).
Now click on the "Type Here” area, type "Exit” and double
click on it. It should take you to the editor, with generated code
stub:
private void exitToolStripMenuItem_Click(object sender, EventArgs e)
{
}
We want to close app when choosing ‘Exit’ option, so implement
like this:
private void exitToolStripMenuItem_Click(object sender, EventArgs e)
{
Application.Exit();
}
Of course, you can add more items to the menu (and add whatever code you want to it).
The last thing to do is to attach this menu to our tray icon. In
order to do that, choose notifyIcon1 from the area below the designer:
...and choose our ContextMenuStrip in the Properties window on the
right:
When you run the app now and right-click on the tray icon, "Exit”
option should appear (and should work).
To last thing to do
is to prevent the app from showing on the "normal” taskbar. To do
this, add one last line to Form1 constructor:
public Form1()
{
InitializeComponent();
this.FormClosing += this.Form1_FormClosing;
ShowInTaskbar = false;
}
That's all for today - I think I was able to show you a simple stub of Windows app using tray in C#. If you have any questions about this - ask them in comments :)