10

I've got a small C# (.NET 4.0) Console Application that I'd like the user to be able to interact by showing a menu when they right-click the System Tray icon. I can add an icon to the Tray with no problems, but I just cannot get the menu to appear. I'm using the following code:

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;

... which puts the icon in the tray. However, right-clicking the icon does nothing. I've tried various permutations of MenuItems.Add, but nothing will make the menu appear. I'm sure I'm missing something simple - any ideas what?

ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122
KenD
  • 5,280
  • 7
  • 48
  • 85

4 Answers4

21

Try adding this after you create the icon:

Application.Run()

Note that this method will not return, so you can't do anything after calling it. This means that you'll have to do all your other work in a separate thread.

What happens is that the OS sends your application a message telling it that the tray icon has been right-clicked, but the tray icon code never sees it (because these messages are processed by Application.Run) and so can't respond by opening the menu.

Roman Starkov
  • 59,298
  • 38
  • 251
  • 324
  • 1
    Sorted! Moving the actual code to another thread should be easy enough. Thank you! – KenD Oct 10 '12 at 10:53
  • 1
    To clarify, this is `System.Windows.Forms.Application` (not `System.Windows.Application`). – skst Mar 18 '19 at 21:45
9

Concerning Application.Run(), this is an alternative to placing all the other code in another thread would be to create the NotifyIcon, menu, events, etc on a thread other than the main thread.

This should include Application.Run() as this allows the standard application message loop to work on the current thread. Then since the events were created on the same thread, the Application.Exit() can be used to close out the notification messaging but still allow the main thread to continue. Here's a small example for a console app...

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();
    }

}
ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122
bjhuffine
  • 924
  • 1
  • 11
  • 23
  • 3
    Thanks @bjhuffine that helped. I wanted to add three things here if anyone just want to quickly test code by copy pasting. 1) Add reference to System.Windows.Forms dll and System.Drawing dll. 2) Change the above icon setting line to Icon = new Icon(SystemIcons.Application, 40, 40), 3) Update your console solution properties and compile it as Windows Forms, it will directly comes in notification area. – sunder Sep 12 '13 at 07:00
  • It's possible to get the minimize event, so the console goes to the system tray? – Nicke Manarin Sep 12 '13 at 19:50
  • `MediaTypeNames.Application.Run()` is undefined, why? – Basheer AL-MOMANI Jun 26 '16 at 07:22
1

Here is the solution: You have to use Application.Run() because events of gui in console mode not working. But you can use this solution:

var task = System.Threading.Tasks.Task.Factory.StartNew(() => ShowTrayIcon());

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

This will start your setup of try icon in new thread ...

ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122
0

Did you add the event-handler for tray Icon mouse click?

trayIcon .MouseDown += new MouseEventHandler(trayIcon_MouseDown);

create context menu and do as following inside the trayIcon_MouseDown function

private void trayIcon_MouseDown (object sender,MouseEventArgs e)
{
  //add you menu items to context menu
  contextMenu.Items.Add(item);
  contextMenu.IsOpen = true;  
}

Try this. Think this will help you.

LarsTech
  • 80,625
  • 14
  • 153
  • 225
New Developer
  • 3,245
  • 10
  • 41
  • 78