NotifyIconから呼び出されたContextMenuの中のMenuItemはPopupイベントを発生しないという不具合があります。
MicorosoftのKBにはwork aroundとして「Formに関連付けて使う」、というのと「MenuItemのイベントの代わりにContextMenuのPopupイベントを使う」という2つの手段が記載されています。
ただし、1つ目の方法であるとFormを非表示にした際にコンテキストメニューを表示できなくなります。
2つ目の方法はサブメニューが表示される直前に処理したい場合には使いづらいものです。
ダミーのFormを作成し、ContextMenuプロパティに対象のメニューを設定し、Win32の TrackPopupMenu APIを利用し、表示させることでPopupイベントを発生する状態にできます。
これを実現するにはNotifyIconを継承してコンテキストメニューを表示させる部分をオーバーライドするか、MouseDownイベントでメニューを表示する方法があります。次のコードはイベントで処理する場合です。
このコードを利用した場合、ContextMenuのPopupイベントが発生しなくなることに注意してください。必要であればMouseDownイベント等で処理を行ってください。
private ContextMenu _contextMenu = new ContextMenu();
private NotifyIcon _notifyIcon = new NotifyIcon();
...
_notifyIcon.MouseDown += new MouseEventHandler(NotifyIcon_MouseDown);
...
// NotifyIcon の MouseDown イベントを処理する。
private void NotifyIcon_MouseDown(object sender, MouseEventArgs e)
{
// ContextMenu を持つダミーフォームを作る。
Form dummyForm = new Form();
//dummyForm.Visible = false;
dummyForm.ContextMenu = _contextMenu;
// できればメニューが消えなくなる問題の対策として Win32 API の SetForegroundWindow をやっておいたほうが良い。
// SetForegroundWindow(dummyForm.Handle);
// メニュー表示。
TrackPopupMenu(_contextMenu.Handle, 0, Cursor.Position.X, Cursor.Position.Y, 0, dummyForm.Handle, IntPtr.Zero);
dummyForm.Close();
}
[DllImport("user32.Dll")]
private static extern Int32 TrackPopupMenu(
IntPtr hMenu,
UInt32 uFlags,
Int32 x,
Int32 y,
Int32 nReserved,
IntPtr hWnd,
IntPtr prcRect
);