2011-12-19 70 views
0

我正在使用一个插件(使用System.ComponentModel.Composition)为应用程序在Windows UI的通知区域中放置图标。在附加到NotifyIcon的ContextMenu中延迟的Click事件

trayMenu.MenuItems.Clear(); 

// Create context menu items 
foreach(IJob job in jobs) { 
    MenuItem menuItem = new MenuItem(job.Name) {Tag = job}; 
    menuItem.Click += MenuItemClick; 
    trayMenu.MenuItems.Add(menuItem); 
} 

private void MenuItemClick(object sender, EventArgs e) { 
    // ... 
} 

现在,当我点击该图标的右键菜单项,在Click处理程序没有被调用。
有趣的是,当我再次右键单击图标时(单击菜单项后),先前单击的MenuItem的处理程序被调用。左键单击或悬停在图标上不会触发此步骤。

这是怎么回事?

更新:我有一种强烈的感觉,我的问题与this question有关。但我仍然在想如何将它应用到我的插件/应用程序。

+0

你是否做过任何不寻常的事情,比如自己显示上下文菜单?点击菜单外部是否会导致它消失? –

+0

@Hans Passant:不,我认为我没有做任何不寻常的事情。菜单打开由NotifyIcon处理。点击菜单外部会导致它消失(如预期的那样)。 –

回答

0

我的理解是,NotifyIcon没有处理任何窗口消息(或者至少没有我喜欢/需要的那么多的消息)。

我通过继承Form并为我的插件运行另一个消息泵来解决此问题。

using System; 
using ... 

namespace JobTracker.Tray { 
    [Export(typeof(IJobTrackerPlugin))] 
    public class TrayPlugin : Form, IJobTrackerPlugin { 

    #region Plugin Interface 
    [Import(typeof(IJobTracker))] 
#pragma warning disable 649 
     private IJobTracker _host; 
#pragma warning restore 649 
    private IJobTracker Host { 
     get { return _host; } 
    } 

    public void Initialize() { 
     trayMenu = new ContextMenu(); 
     trayMenu.MenuItems.Add("Exit", OnExit); 

     trayIcon = new NotifyIcon(); 
     trayIcon.Icon = new Icon(SystemIcons.Application, 32, 32); 

     trayIcon.ContextMenu = trayMenu; 

     // Show the proxy form to pump messages 
     Load += TrayPluginLoad; 
     Thread t = new Thread(
     () => { 
      ShowInTaskbar = false; 
      FormBorderStyle = FormBorderStyle.None; 
      trayIcon.Visible = true; 
      ShowDialog(); 
     }); 
     t.Start(); 
    } 

    private void TrayPluginLoad(object sender, EventArgs e) { 
     // Hide the form 
     Size = new Size(0, 0); 
    } 
    #endregion 

    private NotifyIcon trayIcon;  
    private ContextMenu trayMenu; 

    private void OnExit(object sender, EventArgs e) { 
     Application.Exit(); 
    } 

    #region Implementation of IDisposable 

    // ... 

    private void DisposeObject(bool disposing) { 
     if(_disposed) { 
     return; 
     } 
     if(disposing) { 
     // Dispose managed resources. 
     if(InvokeRequired) { 
      EndInvoke(BeginInvoke(new MethodInvoker(Close))); 
     } else { 
      Close(); 
     } 
     trayIcon.Dispose(); 
     trayMenu.Dispose(); 
     } 
     // Dispose unmanaged resources. 
     _disposed = true; 
    } 
    #endregion 
    } 
} 

似乎很好。