notifyicon 不引发点击事件和 contextmenustrip 不显示
notifyicon not raising click event and contextmenustrip not showing
我遇到一个问题,notifyicon 可以正常显示并显示其气泡,但在单击时不会引发其单击事件。
它应该显示其上下文菜单条,但如果我将 contextmenustrip.show();
添加到代码中,它只会显示菜单的阴影而不是菜单本身。
该函数是 WPF 应用程序的一部分,通过 WCF 服务应用程序的命名管道调用。
代码,以备不时之需:
在服务应用中:
public partial class Service1 : ServiceBase
{
ChannelFactory<ILicenseWatchingServiceUIHost> pipeFactory;
ILicenseWatchingServiceUIHost LWSProxy;
public Service1()
{
InitializeComponent();
}
#region service states
protected override void OnStart(string[] args)
{
pipeFactory = new ChannelFactory<ILicenseWatchingServiceUIHost>(
new NetNamedPipeBinding(),
new EndpointAddress("net.pipe://localhost/LWSPipe"));
LWSProxy = pipeFactory.CreateChannel();
Run();
}
//...
private void Run()
{
//...
LWSProxy.Execute();
}
}
在 WPF 应用程序中创建服务器:
public partial class App : Application
{
ServiceHost host = new ServiceHost(typeof(LicenseWatchingServiceUserInterface), new Uri[] { new Uri("net.pipe://localhost") });
public App()
{
StartServer();
}
private void StartServer()
{
host.AddServiceEndpoint(typeof(ILicenseWatchingServiceUIHost), new NetNamedPipeBinding(), "LWSPipe");
host.Open();
BackgroundWorker worker = new BackgroundWorker();
System.Windows.Threading.Dispatcher dispatcher = this.Dispatcher;
}
}
最后:
public class LicenseWatchingServiceUserInterface : ILicenseWatchingServiceUIHost
{
private System.ComponentModel.IContainer components = null;
private System.Windows.Forms.NotifyIcon notifyIcon;
private System.Windows.Forms.ContextMenuStrip contextMenuStrip;
void Execute(){
//...
contextmenustrip.show(); //does not work
}
//does not get raised
private void notifyIcon_Click(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
contextMenuStrip.Show(Cursor.Position.X, Cursor.Position.Y);
}
else if (e.Button == MouseButtons.Left)
{
Execute();
}
}
}
void Init()
{
this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(LicenseWatchingServiceUserInterface));
this.notifyIcon = new System.Windows.Forms.NotifyIcon();
this.contextMenuStrip = new System.Windows.Forms.ContextMenuStrip();
//
// notifyIcon
//
this.notifyIcon.BalloonTipIcon = System.Windows.Forms.ToolTipIcon.Info;
this.notifyIcon.ContextMenuStrip = this.contextMenuStrip;
this.notifyIcon.Icon = iconLoading;
this.notifyIcon.Visible = true;
//clickhandler is in fact wired up
this.notifyIcon.MouseClick += new System.Windows.Forms.MouseEventHandler(this.notifyIcon_Click);
//
// contextMenuStrip
//
this.contextMenuStrip.ImageScalingSize = new System.Drawing.Size(20, 20);
this.contextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.settingsToolStripMenuItem,
this.openLicenseManagerToolStripMenuItem,
this.closeToolStripMenuItem});
this.contextMenuStrip.Name = "contextMenuStrip";
this.contextMenuStrip.Size = new System.Drawing.Size(234, 128);
//
// contextmenustrip items...
//
}
//...
}
想通了:
LWSProxy.Execute();
在后台线程中创建 LicenseWatchingServiceUserInterface
class 的实例,这导致了问题。 notifyicon 必须在主线程中创建,否则事件处理程序将无法工作。我的解决方案是一个助手 class(只需将其放在 class App
下方):
public class LicenseWatchingServiceUICreator : ILicenseWatchingServiceUIHost
{
public void Execute(List<LicenseInfoContainerExpiring> elcs, List<LicenseInfoContainerUntrusted> ulcs)
{
System.Windows.Application.Current.Dispatcher.Invoke(new Action(() =>
{
LicenseWatchingServiceUserInterface LWSUI = new LicenseWatchingServiceUserInterface(elcs, ulcs);
}));
}
}
稍作调整,这个 classes 执行方法将通过管道调用,它会在主线程中创建我的 class 的一个实例。现在我的 UI 照常工作了。
我遇到一个问题,notifyicon 可以正常显示并显示其气泡,但在单击时不会引发其单击事件。
它应该显示其上下文菜单条,但如果我将 contextmenustrip.show();
添加到代码中,它只会显示菜单的阴影而不是菜单本身。
该函数是 WPF 应用程序的一部分,通过 WCF 服务应用程序的命名管道调用。
代码,以备不时之需:
在服务应用中:
public partial class Service1 : ServiceBase
{
ChannelFactory<ILicenseWatchingServiceUIHost> pipeFactory;
ILicenseWatchingServiceUIHost LWSProxy;
public Service1()
{
InitializeComponent();
}
#region service states
protected override void OnStart(string[] args)
{
pipeFactory = new ChannelFactory<ILicenseWatchingServiceUIHost>(
new NetNamedPipeBinding(),
new EndpointAddress("net.pipe://localhost/LWSPipe"));
LWSProxy = pipeFactory.CreateChannel();
Run();
}
//...
private void Run()
{
//...
LWSProxy.Execute();
}
}
在 WPF 应用程序中创建服务器:
public partial class App : Application
{
ServiceHost host = new ServiceHost(typeof(LicenseWatchingServiceUserInterface), new Uri[] { new Uri("net.pipe://localhost") });
public App()
{
StartServer();
}
private void StartServer()
{
host.AddServiceEndpoint(typeof(ILicenseWatchingServiceUIHost), new NetNamedPipeBinding(), "LWSPipe");
host.Open();
BackgroundWorker worker = new BackgroundWorker();
System.Windows.Threading.Dispatcher dispatcher = this.Dispatcher;
}
}
最后:
public class LicenseWatchingServiceUserInterface : ILicenseWatchingServiceUIHost
{
private System.ComponentModel.IContainer components = null;
private System.Windows.Forms.NotifyIcon notifyIcon;
private System.Windows.Forms.ContextMenuStrip contextMenuStrip;
void Execute(){
//...
contextmenustrip.show(); //does not work
}
//does not get raised
private void notifyIcon_Click(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
contextMenuStrip.Show(Cursor.Position.X, Cursor.Position.Y);
}
else if (e.Button == MouseButtons.Left)
{
Execute();
}
}
}
void Init()
{
this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(LicenseWatchingServiceUserInterface));
this.notifyIcon = new System.Windows.Forms.NotifyIcon();
this.contextMenuStrip = new System.Windows.Forms.ContextMenuStrip();
//
// notifyIcon
//
this.notifyIcon.BalloonTipIcon = System.Windows.Forms.ToolTipIcon.Info;
this.notifyIcon.ContextMenuStrip = this.contextMenuStrip;
this.notifyIcon.Icon = iconLoading;
this.notifyIcon.Visible = true;
//clickhandler is in fact wired up
this.notifyIcon.MouseClick += new System.Windows.Forms.MouseEventHandler(this.notifyIcon_Click);
//
// contextMenuStrip
//
this.contextMenuStrip.ImageScalingSize = new System.Drawing.Size(20, 20);
this.contextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.settingsToolStripMenuItem,
this.openLicenseManagerToolStripMenuItem,
this.closeToolStripMenuItem});
this.contextMenuStrip.Name = "contextMenuStrip";
this.contextMenuStrip.Size = new System.Drawing.Size(234, 128);
//
// contextmenustrip items...
//
}
//...
}
想通了:
LWSProxy.Execute();
在后台线程中创建 LicenseWatchingServiceUserInterface
class 的实例,这导致了问题。 notifyicon 必须在主线程中创建,否则事件处理程序将无法工作。我的解决方案是一个助手 class(只需将其放在 class App
下方):
public class LicenseWatchingServiceUICreator : ILicenseWatchingServiceUIHost
{
public void Execute(List<LicenseInfoContainerExpiring> elcs, List<LicenseInfoContainerUntrusted> ulcs)
{
System.Windows.Application.Current.Dispatcher.Invoke(new Action(() =>
{
LicenseWatchingServiceUserInterface LWSUI = new LicenseWatchingServiceUserInterface(elcs, ulcs);
}));
}
}
稍作调整,这个 classes 执行方法将通过管道调用,它会在主线程中创建我的 class 的一个实例。现在我的 UI 照常工作了。