2009-03-17 14 views
11

He agregado un ícono de notificación a mi aplicación, y con bastante frecuencia veo hasta 3 copias del ícono de notificación en mi bandeja del sistema. ¿Hay alguna razón para esto?¿Por qué veo múltiples iconos de Systray?

hay una manera de evitar que esto suceda.

A menudo esto persiste después de que mi aplicación se ha cerrado, hasta que me paso a la bandeja del sistema y la bandeja del sistema se expande y se colapsa, y luego desaparecen.

+0

¿Cómo agregaste NotifyIcon? En el diseñador o en el código? – OregonGhost

+0

... y ¿cómo se elimina durante el cierre de la aplicación? –

+0

Diseñador y yo no lo quito, ¿verdad? –

Respuesta

21

¿Está esto mientras está depurando su aplicación? de ser así, esto se debe a que los mensajes que eliminan el icono de la bandeja del sistema solo se envían cuando la aplicación sale normalmente, si finaliza debido a una excepción o porque la finaliza desde Visual Studio, el icono permanecerá hasta que pase el mouse sobre él.

+0

Odio trabajar en aplicaciones que tienen íconos en la bandeja del sistema y detenerlos con Visual Studio. Termina con docenas de ellos si no los paso sobre ellos. – Samuel

+6

aunque mover un poco el brazo de vez en cuando puede ser saludable: p – Svish

+2

Sí, pero en un monitor de 24 pulgadas, es todo un viaje para el mouse. ;) – Samuel

9

Puede matar el icono utilizando el evento de ventana principal cerrado. Esto funciona en mi aplicación WPF, incluso cuando se prueba en Visual Studio (2010, en mi caso):

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

Lo que hice:

  1. Crear una biblioteca de clases que actualiza la bandeja del sistema.

    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. Copiar la dll a "%ProgramFiles%\Microsoft Visual Studio x.x\Common7\IDE\PublicAssemblies\SystrayUtil.dll"

    donde xx es el número de versión de Visual Studio

  3. Grabar una macro y guardarlo

  4. Editar la macro

    Agregar una referencia al dll creado.

    Agregue Imports SystrayUtil a la lista de importaciones en la parte superior de Module EnvironmentEvents.

    eliminar los elementos no deseados y agregue el código siguiente al módulo de EnvironmentEvents

    Public Sub DebuggerEvents_OnEnterDesignMode(ByVal Reason As EnvDTE.dbgEventReason) Handles DebuggerEvents.OnEnterDesignMode 
    Systray.Cleanup() 
    MsgBox("Entered design mode!") 
    End Sub 
    
  5. Si funciona eliminar MsgBox("Entered design mode!") porque es molesto tener un cuadro de mensaje apareciendo cada vez que regrese de una sesión de depuración.

0

Esto debería funcionar normalmente cuando se cierra la aplicación:

// 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 { } 
} 

Cuando se detiene la aplicación desde el botón de depuración de Visual Studio parada - se elimina el proceso y no hay eventos Desechar se disparan.

Cuestiones relacionadas