views:

348

answers:

2

Hi, I'm trying to get my application to display a popup context menu when a user right-clicks on my notify icon in the system tray... but there's a twist.

I'm aware that the NotifyIcon class I'm using to get the icon in the system tray has a ContextMenu property. I don't want to use that to get a right-click popup menu, because it ALWAYS displays a right-click popup menu, and never does anything else. When my main form is displaying a modal dialog, I want right-click to activate the main form, NOT display a popup menu.

So, I'm guessing I need to use the NotifyIcon.MouseClick event, and manually pop up the menu in that event? Here's where I've got to so far:

private NotifyIcon trayIcon;
private ContextMenu iconMenu;

private void frmMain_Load(object sender, EventArgs e) {
    // [...]
    this.trayIcon.MouseClick += new MouseEventHandler(trayIcon_MouseClick);
    iconMenu = new ContextMenu();
    // [...]
}

private void trayIcon_MouseClick(object sender, MouseEventArgs ea) {
    this.iconMenu.Show(Program.instanceFrmMain, new Point(System.Windows.Forms.Cursor.Position.X - Program.instanceFrmMain.Left, System.Windows.Forms.Cursor.Position.Y - Program.instanceFrmMain.Top));
}

Notice how in iconMenu.Show, because it takes popup co-ordinates relative to the parent control (my main form here), I'm annoyingly having to subtract the parent control's co-ordinates from popup co-ordinates, something I already don't want to have to do.

Apart from that, here are the problems I'm having:

  • Although the menu does popup on right-click, it doesn't close if I click somewhere else on the screen outside the menu - and it should.
  • The menu doesn't quite popup in the right location; for other system tray apps, it pops up so its bottom-right or bottom-left corner are at the tip of the mouse cursor. For mine, the popup menu is at the base of the screen, to the side of the mouse cursor.

Any ideas how I can get this to work better? I know it's possible, plenty of other apps manually handle the displaying of a popup menu manually instead of using some NotifyIcon.ContextMenu property.

+2  A: 

Use the ContextMenuStrip property rather than ContextMenu. The ContextMenuStrip class has an Opening event, which you can cancel by setting e.Cancel = true. That way you don't have to worry about the location of the menu, since it is automatically handled

Thomas Levesque
I purposely avoided using this because it renders a popup menu that looks different from the default style of popup menu used by all the other system tray programs.
Jez
Well, on Windows 7 (and probably Vista as well) the default ContextMenuStrip rendering looks very similar to other context menus... Anyway, you can set the RenderMode for the menu to System, it should make it look more like other menus.
Thomas Levesque
No, it still looks different. There's obviously some way to do this with a normal ContextMenu as all the other apps in my system tray do it.
Jez
A: 

OK, well I didn't manage to get the functionality I wanted as I described in the original question, but I have managed to find a way to achieve the desired effect using a different method.

I DO attach a ContextMenu to the trayIcon.ContextMenu property, but I attach event handler code to the Popup property of the context menu itself. If, in that handler, I .Clear the ContextMenu, it actually doesn't appear at all, allowing my code to elect to effectively stop the trayicon's popup menu from showing if it wants to. This was the effect I was looking to achieve. If I populate the ContextMenu in the Popup event handler code instead, the menu pops up as usual containing what I populated it with.

Sooo, I managed to solve the problem a different way. :-)

Jez