使用C#控制台应用程序的系统托盘图标无法显示菜单

10

我有一个小的C# (.NET 4.0)控制台应用程序,我希望用户在右键单击系统托盘图标时能够通过显示菜单与之交互。我可以毫无问题地向托盘添加图标,但是我就是无法让菜单出现。我正在使用以下代码:

NotifyIcon trayIcon = new NotifyIcon();
trayIcon.Text = "TestApp";
trayIcon.Icon = new Icon(SystemIcons.Application, 40, 40);

ContextMenu trayMenu = new ContextMenu();

trayMenu.MenuItems.Add("Blah", item1_Click);
trayMenu.MenuItems.Add("Blah2", item1_Click);
trayMenu.MenuItems.Add("Blah3", item1_Click);

trayIcon.ContextMenu = trayMenu;
trayIcon.Visible = true;

这段代码将图标放入托盘中,但右键单击图标没有任何反应。我已经尝试过各种排列组合的MenuItems.Add,但都不能使菜单出现。我确定我错过了一些简单的东西 - 你有什么想法吗?

4个回答

21
尝试在创建图标后添加以下内容:
Application.Run()

请注意,此方法不会返回结果,因此在调用此方法后你无法执行任何操作。这意味着你必须在一个单独的线程中完成所有其他工作。

发生的情况是操作系统向应用程序发送一条消息,告诉它托盘图标已被右键单击,但托盘图标代码从未看到它(因为这些消息由 Application.Run 处理),因此无法通过打开菜单来做出响应。


1
排好序了!将实际代码移动到另一个线程应该很容易。谢谢! - KenD
1
澄清一下,这是 System.Windows.Forms.Application(而不是 System.Windows.Application)。 - skst

9
关于Application.Run(),另一种方法是在主线程之外的线程上创建NotifyIconmenuevents等。这应该包括Application.Run(),因为这允许标准的应用程序消息循环在当前线程上工作。然后,由于事件是在同一线程上创建的,所以可以使用Application.Exit()来关闭通知消息,但仍允许主线程继续。以下是一个控制台应用程序的小例子...
class Program 
{
    public static ContextMenu menu;
    public static MenuItem mnuExit;
    public static NotifyIcon notificationIcon;

    static void Main(string[] args)
    {
        Thread notifyThread = new Thread(
            delegate()
            {
                menu = new ContextMenu();
                mnuExit = new MenuItem("Exit");
                menu.MenuItems.Add(0, mnuExit);

                notificationIcon = new NotifyIcon()
                {
                    Icon = Properties.Resources.Services,
                    ContextMenu = menu,
                    Text = "Main"
                };
                mnuExit.Click += new EventHandler(mnuExit_Click);

                notificationIcon.Visible = true;
                Application.Run();
            }
        );

        notifyThread.Start();

        Console.ReadLine();          
    }

    static void mnuExit_Click(object sender, EventArgs e)
    {
        notificationIcon.Dispose();
        Application.Exit();
    }

}

3
谢谢 @bjhuffine 的帮助。如果有人只想通过复制粘贴来快速测试代码,我想在这里添加三件事情。1)添加对 System.Windows.Forms dll 和 System.Drawing dll 的引用。2)将上面的图标设置行更改为 Icon = new Icon(SystemIcons.Application, 40, 40)。3)更新您的控制台解决方案属性并将其编译为 Windows Forms,它将直接出现在通知区域中。 - sunder
有可能获取最小化事件,使控制台进入系统托盘吗? - Nicke Manarin
MediaTypeNames.Application.Run() 未定义,为什么? - Basheer AL-MOMANI

1
这里是解决方案: 你需要使用 Application.Run(),因为在控制台模式下 GUI 的事件不起作用。 但你可以使用这个解决方案:
var task = System.Threading.Tasks.Task.Factory.StartNew(() => ShowTrayIcon());

void ShowTrayIcon()
{
    some code with tray icon ...
}

这将在新线程中启动您的尝试图标设置...

0
你是否添加了托盘图标鼠标单击的事件处理程序?
trayIcon .MouseDown += new MouseEventHandler(trayIcon_MouseDown);

在 trayIcon_MouseDown 函数内创建上下文菜单并执行以下操作
private void trayIcon_MouseDown (object sender,MouseEventArgs e)
{
  //add you menu items to context menu
  contextMenu.Items.Add(item);
  contextMenu.IsOpen = true;  
}

试试这个。我想这会对你有所帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接