无窗体系统托盘应用程序






4.96/5 (51投票s)
创建一个无窗体系统托盘应用程序。

引言
本文旨在向您展示如何创建一个无窗体系统托盘应用程序。如果您使用窗体,可以从工具箱中附加一个 NotifyIcon
和 ContextMenu
对象,但您可能发现需要创建一个无窗体版本,或者可能只是想知道如何实现。本文旨在说明如何做到这一点。
入门
在正常情况下,您会启动 Visual Studio,创建一个新的 WinForms 项目,将一些控件拖放到 Form1.cs 上,编译并运行。但是,您可能会发现您想知道如何只用代码创建系统托盘应用程序,并且没有窗体(例如,一个从菜单调用的“关于”对话框)。
初始步骤
- 创建一个新的 Windows 窗体应用程序。
- 从项目中删除 Form1.cs。
- 打开 Program.cs - 删除
Application.Run(new Form1());
这一行。 - 现在您将添加如下所示的类和对象 - 包含一个完整的可运行示例应用程序供您剖析。
如果您想查看所有代码并运行应用程序,请下载示例 - 在 bin/debug 中有一个可执行文件可以运行。
然而,重要的部分是以下内容
核心机制
首先,我们需要一个类来创建我们的系统托盘图标。如果您是从头开始,您现在就会创建它:我将我的命名为 ProcessIcon.cs。我还想继承自 IDisposable
:这使我们有机会处理自己的清理工作,并确保程序关闭时干净利落。
为此,我们需要在代码中创建一个 NotifyIcon
对象。由于我们将在类中的多个位置访问该对象,因此我们将其声明为私有成员,以便我们可以在稍后的代码中实例化和使用它。
这就像在类中添加以下内容一样简单
NotifyIcon ni;
我们在类构造函数中实例化对象,如下所示
ni = new NotifyIcon();
我们现在有一个可以使用的 NotifyIcon
对象。
我这样做第一个原因是我想自己处理 Dispose
方法,以确保当应用程序关闭时,图标会立即从系统托盘中移除。您不需要这样做,但如果您不这样做,图标会一直停留在系统托盘中,直到您将鼠标光标移到它上面才会消失。
这样做的另一个原因是我们可以利用 using
模式,这样您就可以用以下代码替换 Program.cs Main
中的代码
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
// Show the system tray icon.
using (ProcessIcon pi = new ProcessIcon())
{
pi.Display();
// Make sure the application runs!
Application.Run();
}
这确保应用程序将优雅地启动和退出:如果您以前没有见过 using
模式,请点击此处获取更多信息:using 语句 (C# 参考)。
正如您所看到的,我还使用了 pi.Display();
。此方法负责在系统托盘上显示图标并添加菜单,您可以从中创建或插入适当的选项(我将根据您的具体要求进行处理)。
其中最重要的部分之一是提供一个处理程序,用于处理对图标的鼠标单击。出于此演示的目的,我只关注鼠标左键单击,但您也可以截取右键和中键。然而,请注意 ContextMenuStrip
通常是在鼠标右键单击时调用的,因此您通常不需要对它做任何事情。
还需要注意的是,您打算使用的图标是嵌入的。您可以通过打开 Resources.resx(位于项目的 Properties 文件夹中)并将您选择的图标(已包含在项目中)拖放到该文件上。它会自动将其设置为图标资源。我提供了一个来自 VS 2010 图标集的图标 - 欢迎您替换为自己的图标。
现在我们需要添加一个类来处理我们需要的上下文菜单,以赋予应用程序所需的功能。请注意,您可能不需要任何这些功能,并且您的应用程序具有不需要任何交互的其他目的。在此假设下,让我们看看如何用代码创建上下文菜单并将其附加到应用程序。
您会注意到 ProcessIcon.Display
中的以下行用于将菜单附加到 NotifyIcon
对象
ni.ContextMenuStrip = new ContextMenus().Create();
菜单是在 ContextMenus.cs 中构建的。基本过程是创建 ToolStripMenuItem
或 ToolStripSeparator
,然后将其附加到 ContextMenuStrip
。从代码中可以看出,您需要向项目中添加一些东西才能使其做任何有意义的事情。
它应该有一个显示名称和一个事件处理程序(用于响应鼠标单击)。图像是可选的,尽管我为每个选项添加了一个(而且,不,我不知道我从哪里获得了示例中提供的图像)。与图标的规则相同 - 拖放到 Resources.resx 并使用
item.Image = Resources.About;
同样,每个项目都需要一个事件处理程序(如果您需要响应鼠标单击或执行其他操作)。这些可以添加为
item.Click += new EventHandler(Explorer_Click);
一个快速的方法是输入 item.Click +=
并按两次 Tab 键。VS 会为您创建一个适当的处理程序。
在这个例子中,我只是依次添加了每个项目。您可以使用以下方式精确放置它们
menu.Items.Insert(index, item);
其中 index
是一个整数,表示该项目在列表中的位置。
谜题的最后一部分是每个菜单选项的事件处理程序。正如您在代码中看到的,每个选项都执行一个特定任务,例如退出应用程序(非常重要的选项!)或显示一个窗体——在本例中是一个通用的“关于”对话框。还要注意实例化和显示“关于”对话框的构造。这样做是为了解决您无法将“关于”对话框绑定到父窗体(因为没有父窗体)的问题,否则您可能会一直点击菜单选项,屏幕上就会充满“关于”对话框!这没什么帮助!这段代码解决了这个问题。
if (!isAboutLoaded)
{
isAboutLoaded = true;
new AboutBox().ShowDialog();
isAboutLoaded = false;
}
所有这一切都是说,如果“关于”窗体没有加载,则将一个变量(boolean
)设置为 true
,然后加载窗体。当它关闭(并将控制权返回给此方法)时,取消设置该变量并重新开始。
如果您正在显示外部应用程序(如记事本、Windows 资源管理器或 Firefox),则不需要这样做,但对于属于应用程序的任何窗体,都应该这样做;即,如果窗体是应用程序的一部分,此功能可确保它只能加载和显示一次。
请注意,您需要为每个窗体设置一个布尔变量,否则只会打开您点击的第一个窗体!
示例中的其余代码应该相当清楚——您可以随意剖析、丢弃或窃取。我有空的时候会尽力回复任何疑问等。
结论
该代码包含打开窗体(“关于”对话框)、启动和显示 Windows 资源管理器以及退出应用程序的示例。用于打开 Windows 资源管理器的代码使用非常简单,可以调用它来打开几乎任何其他应用程序。该示例非常简单——请阅读本文以更深入地了解此非常有用的功能:Process
类。
就是这样:您现在拥有一个应用程序,它将在系统托盘区域加载一个图标,并允许用户选择菜单选项并提供默认的鼠标左键操作。
警告!
请注意,所提供的代码力求简洁明了。您应确保提供适当的异常处理,并进行反复测试,以确保其按预期运行。
此应用程序是使用 Visual Studio 2010 和 .NET 4.0 在 Windows 7 中创建的。它尚未在任何其他环境中进行测试,虽然它应该可以在 Windows XP 和 Vista 中运行,但您有责任在使用前进行彻底测试。
历史
这是此代码的第一个也是最后一个版本,除非有人提供必须添加的更改,因为它们会大幅改进——您将获得感谢和引用。