我有一个C#WPF .NET 4应用程序,它在系统托盘中有一个图标。我目前正在使用深入讨论的WPF NotifyIcon,但我遇到的问题不依赖于此控件。问题在于,.NET 4根本不允许(大部分)WPF ContextMenu对象出现在Windows 7任务栏的顶部。这个例子完美地说明了问题。WPF应用程序中的托盘图标上下文菜单定位
XAML:
<Window x:Class="TrayIconTesting.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="100" Width="400">
<Window.Resources>
<ContextMenu x:Key="TrayContextMenu" Placement="MousePoint">
<MenuItem Header="First Menu Item" />
<MenuItem Header="Second Menu Item" />
</ContextMenu>
<Popup x:Key="TrayPopup" Placement="MousePoint">
<Border Width="100" Height="100" Background="White" BorderBrush="Orange" BorderThickness="4">
<Button Content="Close" Click="ButtonClick"></Button>
</Border>
</Popup>
</Window.Resources>
<StackPanel Orientation="Horizontal">
<Label Target="{Binding ElementName=UseWinFormsMenu}" VerticalAlignment="Center">
<AccessText>Use WinForms context menu for tray menu:</AccessText>
</Label>
<CheckBox Name="UseWinFormsMenu" IsChecked="False" Click="UseWinFormsMenuClicked" VerticalAlignment="Center" />
</StackPanel>
</Window>
代码:
using System.Drawing;
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Forms;
using ContextMenu = System.Windows.Controls.ContextMenu;
namespace TrayIconTesting
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private ContextMenuStrip winFormsContextMenu;
public MainWindow()
{
InitializeComponent();
this.TrayIcon = new NotifyIcon
{
Icon = new Icon("Bulb.ico"),
Visible = true
};
this.TrayIcon.MouseClick += (sender, args) =>
{
switch (args.Button)
{
case MouseButtons.Left:
this.TrayPopup.IsOpen = true;
break;
case MouseButtons.Right:
if (!this.UseWinFormsMenu.IsChecked.GetValueOrDefault())
{
this.TrayContextMenu.IsOpen = true;
}
break;
}
};
}
private void ButtonClick(object sender, RoutedEventArgs e)
{
this.TrayPopup.IsOpen = false;
}
private void UseWinFormsMenuClicked(object sender, RoutedEventArgs e)
{
this.TrayIcon.ContextMenuStrip = this.UseWinFormsMenu.IsChecked.GetValueOrDefault() ? this.WinFormsContextMenu : null;
}
private ContextMenu TrayContextMenu
{
get
{
return (ContextMenu)this.FindResource("TrayContextMenu");
}
}
private Popup TrayPopup
{
get
{
return (Popup)this.FindResource("TrayPopup");
}
}
private NotifyIcon TrayIcon
{
get;
set;
}
private ContextMenuStrip WinFormsContextMenu
{
get
{
if (this.winFormsContextMenu == null)
{
this.winFormsContextMenu = new ContextMenuStrip();
this.winFormsContextMenu.Items.AddRange(new[] { new ToolStripMenuItem("Item 1"), new ToolStripMenuItem("Item 2") });
}
return this.winFormsContextMenu;
}
}
}
}
要看到问题,确保托盘图标始终可见,而不是那Win7的任务栏图标,弹出的事情的一部分。右键单击托盘图标时,上下文菜单将在任务栏上方打开。现在右键单击其旁边的标准Windows托盘图标之一,看看其中的差异。
现在,左键单击图标并注意它允许自定义弹出窗口在鼠标光标所在的位置打开。
检查“使用WinForms ...”复选框将切换应用程序以使用Windows.Forms程序集中的旧ContextMenuStrip上下文菜单。这显然会在正确的位置打开菜单,但其外观与默认的Windows 7菜单不匹配。具体来说,行突出显示是不同的。
我玩过Horizontal和VerticalOffset属性,使用“右”值可以使上下文菜单一直弹出屏幕右下角,但这同样糟糕。它仍然不会打开你的光标所在的位置。
真正的启发是,如果你构建这个针对.NET 3.5的相同样本,它的工作方式和预期的一样。不幸的是,我真正的应用程序使用了很多.NET 4的特性,所以回复不是一种选择。
任何人都有任何想法如何使上下文菜单实际打开光标所在?
你不能把一个单独的程序集中的所有通知图标逻辑放到目标.NET 3.5中,然后在你的实际项目中使用它吗? – SwissCoder 2012-02-13 00:38:26
不幸的是,这不起作用。即使通知图标和上下文菜单存在于以3.5为目标的单独程序集中,问题仍然会发生。似乎只要可执行目标4.0存在问题。 – EricTheRed 2012-02-13 02:39:17
不是问题的解决方案,但我会使用WinForms菜单。最终在一个单独的大会中,为了在WinForms和WPF之间进行彻底的剪切。这样NotifyIcon的上下文菜单看起来应该像普通应用程序一样。 – SwissCoder 2012-02-14 17:00:42