【问题标题】:Context menu does not open in first right click after tray notification is clicked in C# WPF?在 C# WPF 中单击托盘通知后,第一次右键单击不会打开上下文菜单?
【发布时间】:2023-02-25 09:15:54
【问题描述】:

我正在使用 Visual Studio 2022 开发一个 .NET WPF 项目,并向我的应用程序添加了托盘图标功能。每当我的应用程序最小化到 Windows 托盘时,我也会显示 toast 通知。我还添加了一个上下文菜单,以在用户右键单击托盘图标时显示。当出现 toast 通知并且用户单击通知气球时,上下文菜单不会在第一次右键单击事件时打开。

我试图调试并解决问题。我观察到第一次右键单击不会触发 Notifier_MouseDown 事件。我想这是一个焦点问题,当用户点击通知气球时,焦点会移动到其他地方,这就是为什么它不会在第一次点击时触发。但是,我不知道如何解决这个问题。任何帮助,将不胜感激。

到目前为止的工作:

public MainWindow()
{
    InitializeComponent();

    notifyIcon = new NotifyIcon();
    ShowNotifications = true;
    notifyIcon.BalloonTipText = TextRes.Get("TrayNotifyBalloonText");
    notifyIcon.BalloonTipTitle = TextRes.Get("TrayAppTitle");
    notifyIcon.Text = TextRes.Get("TrayAppTitle");
    notifyIcon.DoubleClick += new EventHandler(NotifyIcon_Click);
    notifyIcon.MouseDown += new MouseEventHandler(Notifier_MouseDown);
    notifyIcon.BalloonTipClicked += new EventHandler(NotifyIcon_BalloonTipClicked);

    Hide();
    menu = (ContextMenu)this.FindResource("NotifierContextMenu");
    
    if (notifyIcon != null)
    {
        notifyIcon.ShowBalloonTip(60000);
    }
}

private void NotifyIcon_BalloonTipClicked(object sender, EventArgs e)
{
    Show();
    WindowState = m_storedWindowState;
}

private void Window_Closing(object sender, CancelEventArgs e)
{
    notifyIcon.BalloonTipText = ResourceHelper.GetResourceText("TrayNotifyBalloonText");

    e.Cancel = true;
    WindowState = WindowState.Minimized;
    Hide();
}

void OnClose(object sender, CancelEventArgs args)
{
    notifyIcon.Dispose();
    notifyIcon = null;
}

private WindowState m_storedWindowState = WindowState.Normal;
void OnStateChanged(object sender, EventArgs args)
{
    if (WindowState == WindowState.Minimized)
    {
        notifyIcon.BalloonTipText = ResourceHelper.TextRes.Get("TrayNotifyBalloonText");
    }
    else
        m_storedWindowState = WindowState;
}

void OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs args)
{
    CheckTrayIcon();
}

void NotifyIcon_Click(object sender, EventArgs e)
{
    Show();
    WindowState = m_storedWindowState;
}

void CheckTrayIcon()
{
    ShowTrayIcon(true);
}

void ShowTrayIcon(bool show)
{
    if (notifyIcon != null)
        notifyIcon.Visible = show;
}

void Notifier_MouseDown(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Right)
    { 
        menu.IsOpen = true;
        IntPtr handle = ((HwndSource)PresentationSource.FromVisual(menu)).Handle;
        ApiHelper.SetForegroundWindow(handle);
    }
}

private void Menu_Open(object sender, RoutedEventArgs e)
{
    Show();
    WindowState = m_storedWindowState;
    IntPtr handle = ((HwndSource)PresentationSource.FromVisual(this)).Handle;
    ApiHelper.SetForegroundWindow(handle);
}

private void Menu_Close(object sender, RoutedEventArgs e)
{
    Application.Current.Shutdown();
}
<Window.Resources>
  <ContextMenu
    Focusable="{Binding FocusMenu}"
    x:Key="NotifierContextMenu"
    StaysOpen="False"
    Placement="MousePoint">
    <MenuItem Header="Open" Click="Menu_Open"/>
    <MenuItem Header="Close" Click="Menu_Close"/>
  </ContextMenu>
</Window.Resources>

【问题讨论】:

  • 是 .NET Framework 还是 .NET Core/6?
  • 它由.Net Framework 4.6.2开发

标签: c# .net wpf contextmenu trayicon


【解决方案1】:

尝试使用 ContextMenuStrip 而不是 ContextMenu 并将其分配给 NotifyIcon 实例的 ContextMenuStrip 属性。

这是适用于每个右键单击事件的示例代码。

private NotifyIcon trayIcon;

// Called in the constructor after calling InitializeComponent() method.
private void ConfigureTrayIcon()
{
    var contextMenuStrip = new ContextMenuStrip();

    contextMenuStrip.Items.AddRange(
        new[]
        {
            new ToolStripMenuItem("Toggle", null, OnToggleRequested),
            new ToolStripMenuItem("Exit", null, OnExitRequested)
        }
    );

    trayIcon = new NotifyIcon()
    {
        Icon = Resources.Resources.ApplicationIcon,
        ContextMenuStrip = contextMenuStrip,
        Text = "Initial text",
        Visible = true
    };
}

private void OnExitRequested(object? sender, EventArgs e)
{
    trayIcon.Visible = false;
    Application.Exit();
}

请注意,trayIcon.ContextMenuStrip 属性已设置为菜单,因此无需调用 Win32 API 方法,例如SetForegroundWindow()

菜单将自动显示。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-02-15
    • 1970-01-01
    • 1970-01-01
    • 2014-09-29
    • 1970-01-01
    • 1970-01-01
    • 2016-12-31
    相关资源
    最近更新 更多