我正在创建一个托盘图标应用程序,其中包含一个包含 3 个项目的上下文菜单。托盘图标用于控制某个服务的运行,以便用户可以快速启动或停止它。根据服务状态,如果服务已在运行,我想禁用
Start
按钮。
我面临的问题是它正在更新 ContextMenu,但仅在第二次打开菜单后才更新。
例如:服务正在运行,因此应禁用“启动”按钮。单击
Stop
后,我需要打开 ContextMenu 两次才能更新并启用 Start
按钮。
有没有比我在这里创建的更好的方法来更新 ContextMenu?
class TrayApp : ApplicationContext
{
private NotifyIcon trayIcon;
private ServiceController sc;
public TrayApp()
{
sc = new ServiceController("RamLogger");
trayIcon = new NotifyIcon()
{
Icon = Properties.Resources.icon1,
Text = "RamLogger",
ContextMenu = GetContextMenu(),
Visible = true
};
trayIcon.MouseClick += new MouseEventHandler(OnClick);
}
void OnClick(object sender, MouseEventArgs e)
{
if(e.Button == MouseButtons.Right)
{
trayIcon.ContextMenu = GetContextMenu();
}
}
private ContextMenu GetContextMenu()
{
sc.Refresh();
ContextMenu cm = new ContextMenu();
cm.MenuItems.Clear();
if (sc.Status == ServiceControllerStatus.Running || sc.Status == ServiceControllerStatus.StartPending)
{
cm.MenuItems.Add(new MenuItem("Status: Running"));
cm.MenuItems.Add(new MenuItem("-"));
cm.MenuItems.Add(new MenuItem("Start", Start) { Enabled = false });
cm.MenuItems.Add(new MenuItem("Stop", Stop) { Enabled = true });
}
else
{
cm.MenuItems.Add(new MenuItem("Status: Stopped"));
cm.MenuItems.Add(new MenuItem("-"));
cm.MenuItems.Add(new MenuItem("Start", Start) { Enabled = true });
cm.MenuItems.Add(new MenuItem("Stop", Stop) { Enabled = false });
}
return cm;
}
}
这里的主要问题是,当菜单本身即将显示时,您要替换上下文菜单,单击托盘图标。菜单的实例已经初始化为旧的。
您只需创建一次菜单,然后根据您正在查询的服务的状态启用/禁用项目。
我将用 ContextMenuStrip 替换 ContextMenu,因为前者在 .NET 中已被“弃用”。它还将简化从 .NET Framework 到 .NET 6+ 的过渡 我还添加了一个
Close
菜单项,用于终止进程。
这也将处理 ContextMenuStrip 和 NotifyIcon,因此它会从托盘中删除
using System.ServiceProcess;
using System.Windows.Forms;
class TrayAppContext : ApplicationContext {
private readonly NotifyIcon trayIcon;
private readonly ServiceController sc;
private readonly ContextMenuStrip cms = null;
public TrayAppContext() {
sc = new ServiceController("RamLogger");
cms = GetContextMenu();
trayIcon = new NotifyIcon() {
Icon = Properties.Resources.icon1,
Text = "RamLogger",
ContextMenuStrip = cms,
Visible = true
};
trayIcon.MouseClick += OnClick;
}
void OnClick(object sender, MouseEventArgs e) {
if (e.Button != MouseButtons.Right) return;
bool serviceAvailable = sc.Status.HasFlag(ServiceControllerStatus.Running) ||
sc.Status.HasFlag(ServiceControllerStatus.StartPending);
cms!.Items["Start"].Enabled = !serviceAvailable;
cms!.Items["Stop"].Enabled = serviceAvailable;
}
private ContextMenuStrip GetContextMenu() {
var cms = new ContextMenuStrip();
cms.Items.Add("Status", null, null);
cms.Items.Add("-");
cms.Items.Add(new ToolStripMenuItem("Start", null, Start, "Start") { Enabled = false });
cms.Items.Add(new ToolStripMenuItem("Stop", null, Stop, "Stop") { Enabled = false });
cms.Items.Add("-");
cms.Items.Add(new ToolStripMenuItem("Close", null, Close, "Close") { Enabled = true });
return cms;
}
void Start(object sender, EventArgs e) => sc.Start();
void Stop(object sender, EventArgs e) => sc.Stop();
void Close(object sender, EventArgs e) {
cms?.Dispose();
trayIcon.Dispose();
ExitThreadCore();
}
}
如果有人想测试这个但不知道如何做,请在Program.cs
中替换默认值
:
Application.Run(new Form1());
与:
Application.Run(new TrayAppContext());