Почему я вижу несколько значков Systray?

Я добавил значок уведомлений в свое приложение, и довольно часто я вижу до 3-х копий значка уведомления в моем systray. есть ли причина для этого?

есть способ остановить его.

Часто это сохраняется после закрытия моего приложения, пока я не перейду на systray, и systray не расширится и не разрушит snd, тогда все они исчезнут.

Ответ 1

Это во время отладки вашего приложения? если это так, потому что сообщения, удаляющие значок из системного лотка, отправляются только тогда, когда приложение выходит из него нормально, если оно завершается из-за исключения или из-за того, что вы завершаете его из Visual Studio, значок будет оставаться до тех пор, пока вы не нажмете на него.

Ответ 2

Вы можете убить значок, используя родительское событие Window Closed. Это работает в моем приложении WPF, даже при тестировании в Visual Studio (2010 в моем случае):

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

Ответ 3

Что я сделал:

  • Создайте библиотеку классов, которая обновляет системный трей.

    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);
                                        }
                                    }
                                }
                            }
                        }
                    } 
                }
            }
        }
    }
    
  • Скопируйте dll в "%ProgramFiles%\Microsoft Visual Studio x.x\Common7\IDE\PublicAssemblies\SystrayUtil.dll"

    Где x.x - номер версии Visual Studio

  • Записать макрос и сохранить его

  • Отредактируйте макрос

    Добавьте ссылку на созданную dll.

    Добавьте Imports SystrayUtil в список импорта в верхней части модуля EnvironmentEvents.

    Удалите все нежелательные элементы и добавьте следующий код в модуль EnvironmentEvents.

    Public Sub DebuggerEvents_OnEnterDesignMode(ByVal Reason As EnvDTE.dbgEventReason) Handles DebuggerEvents.OnEnterDesignMode
    Systray.Cleanup()
    MsgBox("Entered design mode!")
    End Sub
    
  • Если он работает, удалите MsgBox("Entered design mode!"), потому что это раздражает появление окна сообщения каждый раз, когда вы возвращаетесь из сеанса отладки.

Ответ 4

Это должно работать, когда вы обычно закрываете приложение:

// in form 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 отключаете кнопку отладки - процесс убит и не запускается никаких событий.