Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/277.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 是什么导致我的NotifyIcon在Alt+F4之后隐藏?_C#_Wpf_Notifications_System Tray - Fatal编程技术网

C# 是什么导致我的NotifyIcon在Alt+F4之后隐藏?

C# 是什么导致我的NotifyIcon在Alt+F4之后隐藏?,c#,wpf,notifications,system-tray,C#,Wpf,Notifications,System Tray,我有一个WPF应用程序,它使用winforms Notify图标在托盘上显示上下文菜单。当我执行以下步骤时,图标消失 右键单击任务栏中的通知图标 选择显示模式对话框的关联菜单项 关闭该对话框 按Alt+F4 下面是我看到这个bug的一个小例子 XAML: 代码隐藏: namespace killtrayicon { using System.Windows; /// <summary> /// Interaction logic for MainWindow

我有一个WPF应用程序,它使用winforms Notify图标在托盘上显示上下文菜单。当我执行以下步骤时,图标消失

右键单击任务栏中的通知图标 选择显示模式对话框的关联菜单项 关闭该对话框 按Alt+F4 下面是我看到这个bug的一个小例子

XAML:

代码隐藏:

namespace killtrayicon
{
    using System.Windows;

    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private System.Windows.Forms.NotifyIcon notifyIcon = new System.Windows.Forms.NotifyIcon();

        public MainWindow()
        {
            InitializeComponent();

            notifyIcon.Icon = Properties.Resources.icon;
            notifyIcon.Visible = true;
            notifyIcon.Text = "test";
            notifyIcon.ContextMenu = new System.Windows.Forms.ContextMenu();
            notifyIcon.ContextMenu.MenuItems.Add("click", (s, e) =>
            {
                MessageBox.Show("menu");
            });
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            notifyIcon.Icon = Properties.Resources.icon;
        }
    }
}
单击“我的主窗口”中的按钮将重置图标,并再次显示通知图标。因此,通知图标本身没有被删除。检查NotifyIcon实例表明,在重置图标之前,它仍然可见,并且icon属性指向“我的资源”中的有效ICO

我怀疑上下文菜单是问题所在,因为如果我通过单击托盘图标显示模式对话框,则不会出现此问题

如何使NotifyIcon不响应Alt+F4


编辑:此问题是的副本,但该问题没有复制问题死链接的示例代码,提交给Microsoft的问题链接也是死链接,并且没有实际解决方案的可接受答案。

我发现了解决方案。NotifyIcon创建一个隐藏的NativeWindow作为由Shell_NotifyIcon创建的图标生成的窗口消息的收件人。该窗口使用默认的窗口进程,该进程与其他窗口一样处理Alt+F4。通过将其转换为WM_CLOSE。您需要使用Win32 API在该NativeWindow中对HWND进行子类化,截取WM_CLOSE并忽略它

首先从comctl32.dll添加一些Win32方法:

public static class Comctl32
{
    public const string DLL = "comctl32.dll";

    public const uint WM_CLOSE = 0x0010;
    public const uint WM_NCDESTROY = 0x0082;

    public delegate IntPtr SubclassWndProc(IntPtr hWnd, uint uMsg, UIntPtr wParam, UIntPtr lParam, UIntPtr uIdSubclass, UIntPtr dwRefData);

    [DllImport(DLL, CharSet = CharSet.Auto, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
    public static extern bool SetWindowSubclass(
        [param: In]
            IntPtr hWnd,
        [param: In]
            SubclassWndProc pfnSubclass,
        [param: In]
            UIntPtr uIdSubclass,
        [param: In]
            UIntPtr dwRefData);

    [DllImport(DLL, CharSet = CharSet.Auto, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
    public static extern bool RemoveWindowSubclass(
        [param: In]
            IntPtr hWnd,
        [param: In]
            SubclassWndProc pfnSubclass,
        [param: In]
            UIntPtr uIdSubclass);

    [DllImport(DLL, CharSet = CharSet.Auto, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
    public static extern IntPtr DefSubclassProc(
        [param: In]
            IntPtr hWnd,
        [param: In, MarshalAs(UnmanagedType.U4)]
            uint uMsg,
        [param: In]
            UIntPtr WPARAM,
        [param: In]
            UIntPtr LPARAM);
}
然后将代码添加到NotifyIcon,以对隐藏的托盘图标窗口进行子类化。您需要使用反射来访问窗口,因为它不是公共的:

private Native.Comctl32.SubclassWndProc subclassWndProc;

...

// Get the HWND from the notify icon
Type notifyIconType = typeof(System.Windows.Forms.NotifyIcon);
BindingFlags hidden = BindingFlags.NonPublic | BindingFlags.Instance;
var window = notifyIconType.GetField("window", hidden).GetValue(this.notifyIcon) as System.Windows.Forms.NativeWindow;

// Inject our window proc to intercept window messages
this.subclassWndProc = this.TrayWndProc;
Native.Comctl32.SetWindowSubclass(window.Handle, this.subclassWndProc, UIntPtr.Zero, UIntPtr.Zero);
然后截取WM_CLOSE以忽略Alt+F4。我们还确保取消WM_NCDESTROY上的子类:


哇,对一个没有死链接的措辞更好的问题投了反对票?
private Native.Comctl32.SubclassWndProc subclassWndProc;

...

// Get the HWND from the notify icon
Type notifyIconType = typeof(System.Windows.Forms.NotifyIcon);
BindingFlags hidden = BindingFlags.NonPublic | BindingFlags.Instance;
var window = notifyIconType.GetField("window", hidden).GetValue(this.notifyIcon) as System.Windows.Forms.NativeWindow;

// Inject our window proc to intercept window messages
this.subclassWndProc = this.TrayWndProc;
Native.Comctl32.SetWindowSubclass(window.Handle, this.subclassWndProc, UIntPtr.Zero, UIntPtr.Zero);
private IntPtr TrayWndProc(IntPtr hWnd, uint uMsg, UIntPtr wParam, UIntPtr lParam, UIntPtr uIdSubclass, UIntPtr dwRefData)
{
    switch (uMsg)
    {
        // Ignore the close message to avoid Alt+F4 killing the tray icon
        case Native.Comctl32.WM_CLOSE:
            return IntPtr.Zero;

        // Clean up subclassing
        case Native.Comctl32.WM_NCDESTROY:
            Native.Comctl32.RemoveWindowSubclass(hWnd, this.subclassWndProc, UIntPtr.Zero))
            break;
    }

    // Invoke the default window proc
    return Native.Comctl32.DefSubclassProc(hWnd, uMsg, wParam, lParam);
}