为什么我会看到多个Systray图标?

时间:2009-03-17 13:20:36

标签: c# systray

我已经在我的应用程序中添加了Notify图标,并且我经常在系统托盘中看到最多3份通知图标。这是有原因的吗?

有没有办法阻止它发生。

在我的应用程序关闭后,这种情况经常会持续存在,直到我迷失到系统托盘并且系统托架扩展并折叠然后它们全部消失。

4 个答案:

答案 0 :(得分:22)

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

答案 1 :(得分:10)

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

        parentWindow.Closing += (object sender, CancelEventArgs e) =>
        {
            notifyIcon.Visible = false;
            notifyIcon.Icon = null;
            notifyIcon.Dispose();
        };

答案 2 :(得分: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"

    其中x.x是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!"),因为每次从调试会话返回时都会弹出一个消息框,这很烦人。

答案 3 :(得分: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停止调试按钮停止应用程序时 - 该进程被终止并且不会触发任何处置事件。