前言

经常看到其它程序在最小化或者窗口隐藏后依旧会在通知栏显示一个托盘图标,像微信、QQ之类的,即使主窗口不显示,程序并不会退出,依旧可以通过托盘图标进行操作。 那么怎样为自己的程序添加一个托盘图标呢?这次就来讲一讲。

实现(C#)

首先,为项目添加引用System.Windows.Forms

这里以WPF为例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
// 主窗口的后台代码
// MainWindow.xaml.cs
using System.Windows;
using System.Windows.Forms;

public partial class MainWindow : Window
{
    private NotifyIcon notifyIcon;  // 托盘图标
    // 托盘菜单
    private System.Windows.Controls.ContextMenu trayIconContextMenu;

    public MainWindow()
    {
        InitializeComponent();
        InitializeTrayIcon();
    }

    private void InitializeTrayIcon()
    {
        notifyIcon = new NotifyIcon()
        {
            Visible = true,
            Text = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name,
            // 使用嵌入的资源
            Icon = new System.Drawing.Icon(
                System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("AppNamespace.icon.ico"),
                System.Windows.Forms.SystemInformation.SmallIconSize)
        };

        notifyIcon.MouseClick += TrayIconMouseClick;
        // notifyIcon.MouseDoubleClick += TrayIconMouseDoubleClick;

        trayIconContextMenu = (System.Windows.Controls.ContextMenu)FindResource("TrayIconContextMenu");
    }

    private void Window_Deactivated(object s, System.EventArgs e)
    {
        trayIconContextMenu.IsOpen = false;
    }

    private void TrayIconMouseClick(object s, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Right)
        {
            // Open the Notify icon context menu
            trayIconContextMenu.IsOpen = true;

            // Required to close the Tray icon when Deactivated is called
            // See: http://copycodetheory.blogspot.be/2012/07/notify-icon-in-wpf-applications.html
            Activate();
        }
    }
}

需要注意的是NotifyIconIcon属性必须设置,否则就不能显示托盘图标。而且图标必须是.ico格式,其它格式pngjpg等都是不行的。 我这里是使用的嵌入的资源,也可以使用文件路径的方式:

1
Icon = new System.Drawing.Icon("icon.ico");

上面代码也没有使用NotifyIconContextMenu属性,而是使用的WPF中的ContextMenu,直接在鼠标右键单击托盘图标的时候将trayIconContextMenu显示出来。

下面是trayIconContextMenu的定义:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<!-- MainWindow.xaml -->
<Window.Resources>
    <ContextMenu x:Key="TrayIconContextMenu" Placement="MousePoint">
        <MenuItem Header="Show Window" ToolTip="show main window" Click="MenuItemShowClick">
            <MenuItem.Icon>
                <Image Source="pack://application:,,,/Icons/window.png" />
            </MenuItem.Icon>
        </MenuItem>
        <Separator />
        <MenuItem Header="Exit" ToolTip="exit" Click="MenuItemExitClick">
            <MenuItem.Icon>
                <Image Source="pack://application:,,,/Icons/exit.png" />
            </MenuItem.Icon>
        </MenuItem>
    </ContextMenu>
</Window.Resources>

通过上面的代码就可以为应用程序添加一个系统托盘图标了。

系统托盘图标还有一个功能就是可以在通知栏显示通知。

1
notifyIcon.ShowBalloonTip(0, "消息", "程序正在运行", ToolTipIcon.Info);

第一个参数是显示超时,不过现在已经没用了。

timeout: 气球状提示应显示的时间段,以毫秒为单位。从 Windows Vista 开始,此参数已被否决。 通知显示时间现在基于系统的辅助功能设置。

BalloonTipWin7上显示为气球状提示,在Win10上显示为Toast通知。

其它

经过本人测试,NotifyIcon在控制台程序上也是可以使用的,遗憾的是一部分功能不能正常使用。 BalloonTip可以正常显示。但菜单是无法使用的,因为不能触发鼠标事件。