13

我在我的应用程序中添加了一个通知图标,而且我经常在我的系统托盘中看到多达 3 个通知图标副本。是否有一个原因?

有没有办法阻止它发生。

在我的应用程序关闭后,这种情况通常会持续存在,直到我移到系统托盘上,系统托盘展开并折叠,然后它们都消失了。

4

4 回答 4

25

这是在调试应用程序时吗?如果是这样,这是因为从系统托盘中删除图标的消息仅在应用程序正常退出时发送,如果它因异常而终止或因为您从 Visual Studio 中终止它,该图标将一直保留,直到您将鼠标悬停在它上面。

于 2009-03-17T13:24:54.810 回答
11

您可以使用父窗口的 Closed 事件终止图标。这适用于我的 WPF 应用程序,即使在 Visual Studio 中进行测试(在我的情况下为 2010):

        parentWindow.Closing += (object sender, CancelEventArgs e) =>
        {
            notifyIcon.Visible = false;
            notifyIcon.Icon = null;
            notifyIcon.Dispose();
        };
于 2012-04-08T11:43:31.707 回答
2

我做了什么:

  1. 创建一个更新系统托盘的类库。

    using System;
    using System.Diagnostics;
    using System.Runtime.InteropServices;
    
    namespace SystrayUtil
    {
        internal enum MessageEnum
        {
            WM_MOUSEMOVE = 0x0200,
            WM_CLOSE = 0x0010,
        }
    
        internal struct RECT
        {
            internal int Left;
            internal int Top;
            internal int Right;
            internal int Bottom;
    
            internal RECT(int left, int top, int right, int bottom)
            {
                Left = left;
                Top = top;
                Right = right;
                Bottom = bottom;
            }
        }
    
        public sealed class Systray
        {
            [DllImport("user32.dll", SetLastError = true)]
            private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
    
            [DllImport("user32.dll", SetLastError = true)]
            private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, IntPtr lpszWindow);
    
            [DllImport("user32.dll", SetLastError = true)]
            private static extern IntPtr SendMessage(IntPtr hWnd, int message, uint wParam, long lParam);
    
            [DllImport("user32.dll", SetLastError = true)]
            private static extern bool GetClientRect(IntPtr hWnd, out RECT usrTray);
    
            public static void Cleanup()
            {
                RECT sysTrayRect = new RECT();
                IntPtr sysTrayHandle = FindWindow("Shell_TrayWnd", null);
                if (sysTrayHandle != IntPtr.Zero)
                {
                    IntPtr childHandle = FindWindowEx(sysTrayHandle, IntPtr.Zero, "TrayNotifyWnd", IntPtr.Zero);
                    if (childHandle != IntPtr.Zero)
                    {
                        childHandle = FindWindowEx(childHandle, IntPtr.Zero, "SysPager", IntPtr.Zero);
                        if (childHandle != IntPtr.Zero)
                        {
                            childHandle = FindWindowEx(childHandle, IntPtr.Zero, "ToolbarWindow32", IntPtr.Zero);
                            if (childHandle != IntPtr.Zero)
                            {
                                bool systrayWindowFound = GetClientRect(childHandle, out sysTrayRect);
                                if (systrayWindowFound)
                                {
                                    for (int x = 0; x < sysTrayRect.Right; x += 5)
                                    {
                                        for (int y = 0; y < sysTrayRect.Bottom; y += 5)
                                        {
                                            SendMessage(childHandle, (int)MessageEnum.WM_MOUSEMOVE, 0, (y << 16) + x);
                                        }
                                    }
                                }
                            }
                        }
                    } 
                }
            }
        }
    }
    
  2. 将dll复制到"%ProgramFiles%\Microsoft Visual Studio x.x\Common7\IDE\PublicAssemblies\SystrayUtil.dll"

    其中 xx 是 Visual Studio 的版本号

  3. 录制宏并保存

  4. 编辑宏

    添加对创建的 dll 的引用。

    添加Imports SystrayUtil到 Module EnvironmentEvents 顶部的导入列表。

    删除所有不需要的项目并将以下代码添加到 EnvironmentEvents 模块

    Public Sub DebuggerEvents_OnEnterDesignMode(ByVal Reason As EnvDTE.dbgEventReason) Handles DebuggerEvents.OnEnterDesignMode
    Systray.Cleanup()
    MsgBox("Entered design mode!")
    End Sub
    
  5. 如果它有效,请删除MsgBox("Entered design mode!"),因为每次从调试会话返回时弹出一个消息框很烦人。

于 2012-05-31T17:14:21.357 回答
0

当您通常关闭应用程序时,这应该可以工作:

// in form's constructor
Application.ApplicationExit += new EventHandler(this.OnApplicationExit);

private void OnApplicationExit(object sender, EventArgs e)
{
    try
    {
        if (notifyIcon1!= null)
        {
            notifyIcon1.Visible = false;
            notifyIcon1.Icon = null;
            notifyIcon1.Dispose();
            notifyIcon1= null;
        }
    }
    catch { }
}

当您从 Visual Studio 停止调试按钮停止应用程序时 - 进程被终止并且不会触发任何处置事件。

于 2013-12-11T07:34:05.947 回答