繁体   English   中英

WPF应用程序中的托盘图标上下文菜单定位

[英]Tray icon context menu positioning in WPF application

我有一个C#WPF .NET 4应用程序,该应用程序在系统任务栏中有一个图标。 我目前正在使用讨论充分的WPF NotifyIcon ,但是我遇到的问题并不取决于此控件。 问题在于,.NET 4完全不允许(大多数情况下)WPF ContextMenu对象出现在Windows 7任务栏的顶部。 这个例子很好地说明了这个问题。

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菜单不匹配。 具体而言,行突出显示是不同的。

我已经使用了Horizo​​ntal和VerticalOffset属性,并使用“ right”值可以使上下文菜单一直弹出到屏幕的右下角,但这同样很糟糕。 它仍然永远不会在光标所在的位置打开。

真正的好处是,如果您针对.NET 3.5构建相同的示例,则它可以按预期运行。 不幸的是,我的实际应用程序使用了许多.NET 4功能,因此不可以选择还原。

任何人都不知道如何使上下文菜单实际上在光标所在的位置打开吗?

经过更多搜索后,我偶然发现了这个问题和答案 我从没想过要在NotifyIcon上尝试ContextMenu属性! 尽管不是很理想,但在WPF解决了系统托盘是应用程序有用部分这一事实之前,它已经足够好了。 但是,如果丢失WPF ContextMenu提供的所有绑定和命令路由功能,那真是可耻的。

但是,接受我自己的答案是错误的,因此我将再开放几天。

好吧,我很高兴没有将此标记为已回答,因为我为我找到了一个更好的选择。 我发现本文详细介绍了如何向System.Windows.Forms.MenuItem对象添加图标。 现在,仅需少量代码,我便有了一个与系统上下文菜单完全匹配的菜单!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM