Iconos de la bandeja del sistema y notificaciones toast en aplicaciones Windows — los escollos de NotifyIcon y cómo elegir el AppNotification adecuado

· · Bandeja del sistema, NotifyIcon, Notificaciones toast, AppNotification, Windows App SDK, WinForms, WPF, C#, .NET, Aplicación residente, Desarrollo Windows, Consultoría técnica

«Quiero avisar discretamente al usuario cuando termine un proceso.» «Quiero que la supervisión siga funcionando incluso después de cerrar la ventana.» Estos son dos requisitos clásicos que suelen aparecer juntos en las aplicaciones empresariales: permanecer residente en la bandeja del sistema (system tray) y enviar notificaciones toast. Pero en cuanto se pasa a la implementación real, empiezan a surgir pequeños problemas uno tras otro: una aplicación que debería cerrarse en realidad no termina, el icono desaparece tras reiniciar el Explorador, o un toast que funcionaba perfectamente durante el desarrollo nunca aparece en las instalaciones del cliente.

Además, las notificaciones toast son un área en la que la API no ha dejado de cambiar de generación desde la época de UWP. No es raro buscar en línea y encontrar código de ejemplo que, según los estándares actuales, utiliza una API que ahora está, en el mejor de los casos, en solo mantenimiento. Este artículo organiza tanto el diseño de la residencia en la bandeja con NotifyIcon como la elección de una API de notificaciones toast a partir de 2026, junto con los escollos prácticos que probablemente encontrará.

1. Lo esencial primero

  • La base de la residencia en la bandeja sigue siendo System.Windows.Forms.NotifyIcon. No aparece a menos que establezca Icon y ponga Visible = true (el valor predeterminado es false). El texto de información sobre herramientas Text puede llegar hasta 127 caracteres a partir de .NET 6 (63 caracteres antes de eso).12
  • WPF no tiene ningún control equivalente a NotifyIcon. La tabla de comparación oficial indica explícitamente «Ningún control equivalente». Habilitar tanto UseWPF como UseWindowsForms en el csproj y usar el NotifyIcon de WinForms es la configuración mínima.34
  • «Mantener la aplicación en la bandeja incluso cuando el usuario hace clic en el botón de cerrar» se implementa estableciendo e.Cancel = true en FormClosing y llamando a Hide(). Proporcione siempre una forma explícita y separada de salir (un elemento «Salir» en el menú de la bandeja) y compruebe CloseReason para no bloquear nunca un apagado del sistema operativo.5
  • La API de toast recomendada es clara a partir de 2026. Independientemente de si está construyendo una aplicación WinForms, WPF o no empaquetada, se recomienda el AppNotificationManager de Windows App SDK (NuGet: Microsoft.WindowsAppSDK). Windows.UI.Notifications está «solo en mantenimiento», y el componente de notificaciones del Community Toolkit está archivado.67
  • El AppNotification de Windows App SDK funciona incluso desde un exe sencillo sin identidad de paquete. AppNotificationManager.Default.Register() gestiona automáticamente el registro del servidor COM y el trabajo equivalente al AUMID, por lo que ya no necesita configurar un acceso directo en el menú Inicio como requerían las generaciones anteriores. Dicho esto, las notificaciones desde procesos elevados (administrador) no son compatibles.8910
  • Un toast no es una forma garantizada de llegar al usuario. Mientras el asistente de enfoque (no molestar) está activo, el banner no aparece y la notificación va directamente al centro de notificaciones, y el usuario también puede desactivar las notificaciones por completo desde la configuración. Su diseño no debe suponer que «el toast se mostró» como condición previa de un flujo de trabajo empresarial.1112
  • Un servicio de Windows no puede enviar toasts (la sesión 0 no tiene interfaz de usuario). El enfoque estándar consiste en colocar un agente residente en la bandeja dentro de la sesión del usuario y coordinarse mediante IPC.13

2. Fundamentos de la residencia en la bandeja con NotifyIcon

System.Windows.Forms.NotifyIcon es el componente que coloca un icono en el área de notificación situada en el extremo derecho de la barra de tareas. Las aplicaciones que siguen ejecutándose en segundo plano lo usan como punto de entrada para mostrar el estado y un menú de operaciones.1

private NotifyIcon _trayIcon = null!;

private void InitializeTrayIcon()
{
    var menu = new ContextMenuStrip();
    menu.Items.Add("Abrir", null, (_, _) => ShowMainWindow());
    menu.Items.Add(new ToolStripSeparator());
    menu.Items.Add("Salir", null, (_, _) => ExitApplication());

    _trayIcon = new NotifyIcon
    {
        Icon = Properties.Resources.AppIcon, // El icono es obligatorio; sin él no se muestra nada
        Text = "Herramienta de supervisión de pedidos ── en ejecución",     // Información sobre herramientas (máx. 127 caracteres en .NET 6+)
        ContextMenuStrip = menu,
        Visible = true                        // El valor predeterminado es false; solo se muestra al establecerlo en true
    };
    _trayIcon.DoubleClick += (_, _) => ShowMainWindow();
}

Hay tres puntos que merece la pena recordar.

  • El icono solo aparece cuando se establecen a la vez Icon y Visible = true. El valor predeterminado de Visible es false.1
  • Text tiene un límite de longitud. Es de un máximo de 127 caracteres a partir de .NET 6, y de 63 caracteres para .NET 5 y anteriores, así como para .NET Framework; superarlo lanza una ArgumentException. Meter demasiada información de estado en la información sobre herramientas es una buena forma de que su aplicación acabe lanzando de repente una excepción en algún momento.214
  • Asocie un menú de clic derecho mediante ContextMenuStrip. El icono de la bandeja suele ser el único punto de entrada visible para el usuario, así que proporcione como mínimo un elemento «Abrir» y otro «Salir».15

Otra cosa: el icono de la bandeja no es solo un punto de entrada para las notificaciones, también es un indicador de estado siempre visible. Dado que Icon y Text pueden intercambiarse mientras la aplicación se está ejecutando, reflejar el estado actual — un icono normal cuando todo va bien, un icono de advertencia cuando hay un problema, mostrar la hora del último procesamiento en la información sobre herramientas — permite al usuario echar un vistazo al icono y conocer el estado actual aunque se haya perdido un toast. El toast es el canal para «algo acaba de ocurrir en este momento», mientras que el icono de la bandeja es el canal para «este es el estado actual» — esa es la división de funciones.

3. Diseñar «permanecer en la bandeja al cerrar» y una ruta de salida correcta

Un comportamiento clásico de las aplicaciones residentes es: hacer clic en el botón de cerrar no termina el proceso, simplemente lo deja en la bandeja. La implementación en sí es fácil de escribir cancelando FormClosing, pero escribirla sin cuidado lleva a dos tipos de problemas: ya no existe ninguna forma de salir de la aplicación, y se bloquea el apagado de Windows.

private bool _exitRequested;

protected override void OnFormClosing(FormClosingEventArgs e)
{
    // Si el usuario solo hizo clic en la X, ocultar en lugar de cerrar
    if (!_exitRequested && e.CloseReason == CloseReason.UserClosing)
    {
        e.Cancel = true;
        Hide();
        return;
    }
    // Cierre normal mediante el menú «Salir», apagado del sistema operativo, etc.
    base.OnFormClosing(e);
}

private void ExitApplication()
{
    _exitRequested = true;
    _trayIcon.Visible = false;
    _trayIcon.Dispose();
    Close();
}

FormClosing se dispara antes de que se cierre el formulario, y establecer e.Cancel = true cancela el cierre. En ese momento, compruebe siempre CloseReason. El comportamiento correcto es cancelar solo en el caso de UserClosing (una acción del usuario), y no cancelar nunca en un cierre desencadenado por el sistema operativo como WindowsShutDown.516

WPF sigue la misma lógica: la propia documentación oficial describe el patrón de establecer e.Cancel = true en Window.Closing y llamar a Hide().17

Cabe señalar que, por su naturaleza, una aplicación residente siempre corre el riesgo de que «si se inicia dos veces, el mismo evento se procese dos veces». Tratamos la prevención de inicios múltiples en «Evitar el inicio múltiple de una aplicación Windows — mutex con nombre y activación de la instancia en ejecución en un segundo inicio». Y «Por qué usar .NET Generic Host y BackgroundService en una aplicación de escritorio» es la base para construir el contenido real de una aplicación residente — el bucle de supervisión o el procesamiento periódico.

4. Residencia en la bandeja en una aplicación WPF

WPF no tiene ningún control equivalente a NotifyIcon. Se trata de una carencia documentada de la plataforma, indicada explícitamente como «No equivalent control» en la tabla de comparación oficial «controles WPF equivalentes a los controles de WinForms».3

Existen dos opciones realistas.

Opción Resumen Criterio
Usar el NotifyIcon de WinForms junto con WPF Habilitar tanto UseWPF como UseWindowsForms en el csproj Sin dependencias adicionales. Suficiente si solo se necesita un icono y un menú
Terceros (por ejemplo, H.NotifyIcon) Implementaciones de iconos de bandeja diseñadas para WPF/WinUI Elegir si se quiere escribir en XAML o se necesita un popup más elaborado. Tener en cuenta que no es un componente oficial de Microsoft

La primera opción consiste simplemente en enumerar dos propiedades una junto a la otra en un archivo de proyecto de estilo SDK.4

<PropertyGroup>
  <TargetFramework>net8.0-windows</TargetFramework>
  <UseWPF>true</UseWPF>
  <UseWindowsForms>true</UseWindowsForms>
</PropertyGroup>

Después puede simplemente instanciar un System.Windows.Forms.NotifyIcon directamente desde una Application de WPF. Solo el menú termina siendo de WinForms (ContextMenuStrip), pero para algo tan sencillo como un menú de bandeja, esto rara vez supone un problema práctico.

5. Tres escollos de los iconos de la bandeja

5.1. Los iconos van por defecto a los «iconos ocultos» — no se puede forzar su visualización

La petición de mantener el icono de su aplicación siempre visible en la barra de tareas siempre acaba surgiendo, pero esto no se puede lograr mediante programación. La documentación oficial establece claramente que los iconos se agregan por defecto al área de desbordamiento (iconos ocultos), y que solo el usuario puede decidir si un icono se promociona para mostrarse siempre en el área de notificación.18

En Windows 11, el usuario activa o desactiva esto por aplicación en «Configuración → Personalización → Barra de tareas → Otros iconos de la bandeja del sistema». Si la visibilidad permanente es operativamente importante, lo correcto es documentarlo en su guía de instalación o ayuda («active esta configuración»), no intentar forzarlo en el código.

5.2. El icono desaparece cuando el Explorador se reinicia — TaskbarCreated

Cuando el Explorador se bloquea o se reinicia y reconstruye la barra de tareas, todos los iconos de bandeja registrados desaparecen. El shell transmite un mensaje TaskbarCreated a todas las ventanas de nivel superior al crear la barra de tareas, y la convención a nivel de Win32 es volver a registrar su icono al recibir este mensaje.19

El NotifyIcon de WinForms gestiona este mensaje internamente y se vuelve a registrar automáticamente, por lo que normalmente no necesita pensar en ello. Si invoca Shell_NotifyIcon usted mismo mediante P/Invoke (o mantiene una aplicación nativa con un icono en la bandeja), asegúrese de que esta lógica de reregistro está implementada. El síntoma «el icono desaparece solo cuando el Explorador se reinicia, pero el proceso sigue vivo» es casi siempre exactamente este problema.

5.3. Olvidar Dispose deja un icono fantasma

A nivel de Win32, un icono de bandeja debe eliminarse explícitamente (NIM_DELETE) en cuanto ya no sea necesario, y en WinForms esa responsabilidad recae en NotifyIcon.Dispose().18 Asegúrese de que su ruta de salida siempre pase por Visible = falseDispose(). Cualquier desarrollador de aplicaciones residentes ha visto esta escena al menos una vez: el proceso termina de forma anómala sin limpieza, y un icono fantasma queda atascado en la bandeja hasta que el usuario pasa el cursor del ratón sobre él.

Como en el código del capítulo 3, es más seguro limpiar el icono de la bandeja en el controlador del menú «Salir», antes de llamar a Close().

6. Notificaciones toast — qué API usar

Una notificación toast es el banner que aparece en la esquina inferior derecha de la pantalla y luego permanece en el centro de notificaciones. La forma de enviar una desde una aplicación de escritorio no ha dejado de cambiar durante la última década, y los resultados de búsqueda todavía están llenos de ejemplos antiguos. Así están las cosas a partir de 2026.6

API NuGet / Espacio de nombres Estado (a partir de 2026) Veredicto
Windows App SDK AppNotification Microsoft.WindowsAppSDK / Microsoft.Windows.AppNotifications Oficialmente recomendado para WinForms, WPF y Win32 no empaquetado Usar para cualquier desarrollo nuevo
Community Toolkit Notifications Microsoft.Toolkit.Uwp.Notifications Archivado. Ya no forma parte del Community Toolkit actual; última actualización en 2022 Solo para mantener código existente. No adoptar en proyectos nuevos
Uso directo de WinRT Windows.UI.Notifications (a través del TFM de Windows) Solo mantenimiento. Recomendado principalmente para UWP No adoptar en proyectos nuevos
NotifyIcon.ShowBalloonTip System.Windows.Forms API de notificaciones tipo globo. Se representa como un toast en Windows 10; en Windows 11 es una visualización temporal que no persiste en el centro de notificaciones Adecuada para casos sencillos, pero tenga en cuenta que su comportamiento cambia entre versiones del sistema operativo

Dos notas adicionales.

  • ShowBalloonTip pertenece a esos casos de «API antigua, pero en realidad sigue viva». En Windows 10, los globos se representan como un toast y permanecen en el centro de notificaciones hasta que se cierran. En Windows 11, en cambio, se comportan más como un globo temporal tradicional y no persisten en el centro de notificaciones una vez que desaparecen. La duración de visualización (timeout) ahora también se ignora, y sigue en su lugar la configuración de accesibilidad del sistema operativo. Esto es más que suficiente para una aplicación residente en la bandeja que solo quiere avisar levemente de un cambio de estado, pero si quiere que un historial persista en el centro de notificaciones, tenga en cuenta que esto no le ayudará en Windows 11.20
  • El enfoque clásico de usar Windows.UI.Notifications puro desde una aplicación de escritorio tiene una restricción bien conocida: el toast no se mostrará a menos que haya registrado un acceso directo con un AUMID (AppUserModelID) en el menú Inicio.21 El AppNotification que se trata en el siguiente capítulo es precisamente lo que elimina esta molestia.

7. Una implementación mínima de Windows App SDK AppNotification

La API de notificaciones de aplicación de Windows App SDK funciona incluso desde un exe sencillo y no empaquetado, sin identidad de paquete.8 Los requisitos previos del lado del proyecto son un TFM específico de Windows (por ejemplo, net8.0-windows10.0.19041.0), <WindowsPackageType>None</WindowsPackageType> (para el caso no empaquetado), y tener el runtime de Windows App SDK instalado en el destino de despliegue.9

using Microsoft.Windows.AppNotifications;
using Microsoft.Windows.AppNotifications.Builder;

// Una sola vez al iniciar; el orden registro del controlador → Register() es importante
AppNotificationManager.Default.NotificationInvoked += (_, args) =>
{
    // Los clics en el toast y las pulsaciones de botones llegan aquí (distinguir mediante args.Arguments)
    if (args.Arguments.TryGetValue("action", out var action) && action == "openLog")
    {
        ShowLogWindow();
    }
};
AppNotificationManager.Default.Register();

// Mostrar la notificación
var notification = new AppNotificationBuilder()
    .AddText("Importación de pedidos completada")
    .AddText("12 nuevos, 1 error")
    .AddButton(new AppNotificationButton("Abrir registro")
        .AddArgument("action", "openLog"))
    .BuildNotification();
AppNotificationManager.Default.Show(notification);

Los puntos prácticos a los que hay que prestar atención:

  • Suscríbase a NotificationInvoked antes de llamar a Register(). Equivoque este orden y se perderá el evento cuando un clic en el toast inicie la aplicación.9
  • Llame a AppNotificationManager.Default.Unregister() antes de que la aplicación se cierre. La documentación oficial establece explícitamente que llamar a Unregister antes de salir limpia los recursos y garantiza que la aplicación se inicie correctamente la próxima vez que se haga clic en una notificación. Integre esto en el controlador del menú «Salir» del capítulo 3, junto a NotifyIcon.Dispose() (también existe un UnregisterAll() independiente para casos como desinstalar una aplicación que nunca volverá a usar notificaciones, el cual borra por completo la información de registro).22
  • Para las aplicaciones no empaquetadas, Register() gestiona automáticamente el registro del servidor COM y el trabajo equivalente al AUMID. Ya no se necesita la configuración de accesos directos ni el registro en el Registro que exigía la generación anterior, la del WinRT puro. Si en cambio empaqueta con MSIX, necesitará declarar el activador COM en Package.appxmanifest.9
  • Tenga cuidado si elige una implementación autónoma (self-contained) que incluya el runtime de Windows App SDK. AppNotificationManager depende del paquete Singleton de Windows App SDK, y existen consideraciones documentadas oficialmente para invocarlo desde una aplicación autónoma. Compruebe esto antes de decidir el método de distribución.23
  • Las notificaciones desde procesos elevados (administrador) no son compatibles. Show no lanza una excepción, simplemente falla en silencio, lo que hace que la causa raíz sea difícil de detectar. Para las aplicaciones que necesitan elevación, considere aislar solo la notificación en un proceso no elevado (este enfoque de aislamiento se trata en «Una forma concreta de aislar en una aplicación Windows solo las partes que requieren privilegios de administrador»).10
  • Cuando se hace clic en un toast, si la aplicación no se está ejecutando en ese momento, se iniciará un nuevo proceso. En una aplicación residente en la bandeja, esto debe combinarse con la prevención de instancias múltiples (capítulo 3), de modo que el trabajo se transfiera a la instancia existente.

8. Uso avanzado — toasts con barra de progreso y limpieza de notificaciones

8.1. Actualizar el progreso dentro de un toast — UpdateAsync

Para un proceso largo como «importando 120 registros de pedidos», el enfoque correcto no es volver a disparar una nueva notificación una y otra vez, sino actualizar la barra de progreso dentro de un único toast. AppNotification cuenta con un mecanismo de enlace de datos y actualización construido precisamente para esto.24

La construcción se realiza en tres etapas. Primero, convierta cada valor de la barra de progreso en un marcador de posición mediante los métodos Bind, dé al toast una identidad a través de Tag (y Group, si es necesario), y muéstrelo. Después de eso, basta con pasar un AppNotificationProgressData a UpdateAsync, y solo se reescribe el contenido del toast ya mostrado.

const string tag = "import-progress";
const string group = "batch";

// Visualización inicial: enlazar el valor y establecer el valor inicial en Progress
var notification = new AppNotificationBuilder()
    .AddText("Importando datos de pedidos")
    .AddProgressBar(new AppNotificationProgressBar()
        .BindStatus().BindValue().BindValueStringOverride())
    .SetTag(tag)
    .SetGroup(group)
    .BuildNotification();

notification.Progress = new AppNotificationProgressData(1) // número de secuencia
{
    Status = "Importando...", Value = 0, ValueStringOverride = "0/120 elementos"
};
AppNotificationManager.Default.Show(notification);

// Cada vez que avanza el progreso: incrementar el número de secuencia y actualizar
var data = new AppNotificationProgressData(2)
{
    Status = "Importando...", Value = 45 / 120.0, ValueStringOverride = "45/120 elementos"
};
await AppNotificationManager.Default.UpdateAsync(data, tag, group);

El número de secuencia es un entero distinto de cero que indica el orden de actualización; si llegan varias actualizaciones desordenadas, gana la que tenga el número más alto. Este mecanismo existe para que las actualizaciones concurrentes enviadas desde procesamiento asíncrono no retrocedan a un valor obsoleto, así que asegúrese de que siempre aumente de forma monótona.25

8.2. «Actualizar» frente a «reemplazar» — cuándo usar cada uno

También se puede actualizar la apariencia volviendo a mostrar (Show) una nueva notificación con el mismo Tag — un «reemplazo» — pero el comportamiento difiere del de una «actualización».24

  Reemplazo (nuevo Show con el mismo Tag) Actualización (UpdateAsync)
Posición en el centro de notificaciones Se mueve a la parte superior Permanece en su sitio
Qué se puede modificar Todo, incluido el diseño Solo la barra de progreso enlazada y el texto principal
Popup Puede volver a aparecer No vuelve a aparecer (se reescribe en silencio)
Si el usuario ya la había cerrado Siempre se entrega Falla

La recomendación oficial también es clara aquí: actualización para el progreso intermedio, reemplazo al completarse. No es necesario mostrar una notificación emergente cada vez que el progreso pasa del 50 % al 65 %, pero «importación completada (3 errores)» debería llegar al usuario aunque ya haya cerrado la notificación de progreso. En la práctica, el patrón habitual es retirar la barra de progreso al completarse y reemplazarla por un diseño diferente con botones, como «Ver detalles del error».

8.3. Limpiar las notificaciones antiguas que quedan en el centro de notificaciones

Los toasts se acumulan en el centro de notificaciones hasta que el usuario los borra. Si una aplicación residente envía varias notificaciones cada día, el centro de notificaciones termina lleno de notificaciones antiguas de su aplicación, lo que puede acabar sepultando las notificaciones importantes.

Adjuntar un Tag / Group le permite eliminar mediante código las notificaciones de su propia aplicación (por etiqueta, por grupo, o todas). También puede establecer una caducidad. Vale la pena decidir sus reglas de limpieza — «borrar las notificaciones de tipo progreso al completarse», «acortar la caducidad de las informativas» — al mismo tiempo que diseña cómo se envían las notificaciones.26

9. Diseñar para los casos en que una notificación «no llega»

Una notificación toast no es un mecanismo de entrega garantizado. Existen rutas totalmente normales en las que no se muestra o no se advierte.

Caso Comportamiento
El asistente de enfoque (no molestar) está activado El banner no aparece; la notificación va directamente al centro de notificaciones
Notificaciones desactivadas, por aplicación o para todo el sistema No se muestra nada
AppNotification desde un proceso elevado No compatible. No se muestra nada
Se está ejecutando una aplicación a pantalla completa, etc. El sistema operativo puede suprimirla a su propio criterio

El modo No molestar se llama «Asistente de enfoque (Focus assist)» en Windows 10 y se controla mediante el interruptor «No molestar» en «Configuración → Sistema → Notificaciones» en Windows 11, y puede regirlo el usuario o una directiva de grupo. Incluso hay una regla según la cual se activa automáticamente durante la primera hora tras una actualización del sistema operativo.11 El asistente de enfoque no significa «no enviar notificaciones», sino «suprimir el banner y enviarla directamente al centro de notificaciones» — por lo que el usuario la seguirá viendo si más tarde abre el centro de notificaciones.12

La implicación para el diseño es sencilla:

  • Trate el toast como un canal complementario que ayuda a los usuarios a responder más rápido si se dan cuenta, y asegúrese de que la información obligatoria para el proceso empresarial siempre se pueda confirmar en una pantalla o lista dentro de la aplicación. No construya un flujo de trabajo que suponga que «el toast probablemente se mostró».
  • Para las notificaciones que deben interrumpir absolutamente al usuario (como una alerta de parada de emergencia), existe un mecanismo para saltarse el modo No molestar con el consentimiento del usuario mediante AppNotificationScenario.Urgent,27 pero un uso excesivo hará que los usuarios acaben desactivando por completo las notificaciones de su aplicación. Resérvelo solo para los casos verdaderamente urgentes.

Para la cuestión más amplia de cómo mostrar en pantalla cosas como los errores de dispositivos externos, consulte también «Buenas prácticas para comprobar y mostrar el estado de dispositivos externos».

10. Cuando necesita notificar desde un servicio de Windows

Es un requisito natural: «cuando un servicio residente detecta un problema, quiero avisar al usuario que ha iniciado sesión mediante un toast» — pero un servicio no puede enviar un toast directamente. Desde Windows Vista, los servicios se ejecutan en una sesión dedicada llamada sesión 0 y no tienen ninguna capacidad de mostrar una interfaz de usuario que interactúe con un usuario.13

El enfoque estándar consiste en separar la interfaz de usuario en un proceso que se ejecuta en la sesión del usuario.

[Sesión 0]                         [Sesión de usuario]
 Servicio de Windows   <-- IPC -->   Agente residente en la bandeja
 (supervisión/lógica de negocio)   tuberías con nombre, etc.   (NotifyIcon + AppNotification)

En entornos donde varios usuarios inician sesión simultáneamente (RDP, terminales compartidos), el agente termina ejecutándose una vez por sesión. Decidir de antemano, como requisito, «a quién se debe notificar» (a todos, o solo a un usuario específico) hace que el diseño sea más estable.

11. Resumen

  • La residencia en la bandeja se basa en NotifyIcon. Muéstrelo mediante Icon + Visible = true, respete el límite de 127 caracteres para Text (.NET 6+), y asegúrese de que Dispose() se invoque de forma fiable en la ruta de salida. Use también el icono y la información sobre herramientas como un indicador siempre visible del estado actual.
  • «Permanecer en la bandeja incluso al cerrar con el botón ×» se implementa cancelando FormClosing, pero cancele solo en el caso de CloseReason.UserClosing y proporcione siempre un menú «Salir» explícito.
  • Solo el usuario puede decidir si un icono se muestra siempre. Gestione la desaparición del icono al reiniciar el Explorador volviendo a registrarlo en TaskbarCreated (WinForms lo hace automáticamente).
  • Para cualquier desarrollo nuevo de notificaciones toast, el AppNotificationManager de Windows App SDK es la única opción real. Funciona incluso desde un exe no empaquetado sin identidad de paquete, y Register() automatiza el tedioso trabajo de registro. Las notificaciones del Community Toolkit están archivadas, y el WinRT puro está solo en mantenimiento.
  • Para el progreso intermedio de un proceso largo, reescriba en silencio la barra de progreso dentro de un único toast con UpdateAsync, y use un reemplazo para mostrar una notificación emergente al completarse — ese es el patrón estándar. Adjunte un Tag/Group, e incluya en el diseño la limpieza de notificaciones antiguas.
  • Un toast es un canal complementario que puede no llegar debido al modo No molestar o a las notificaciones desactivadas. Diseñe de forma que la información obligatoria siempre se pueda confirmar dentro de la aplicación, y tenga en cuenta que las notificaciones desde procesos elevados no son compatibles.
  • Las notificaciones desde un servicio se logran mediante la arquitectura de separación de un agente residente en la bandeja del lado de la sesión de usuario más IPC.

Artículos relacionados

Áreas de consultoría relacionadas

KomuraSoft LLC (合同会社小村ソフト) se encarga del diseño e implementación de herramientas de supervisión y agentes de notificación residentes en la bandeja, la revisión de arquitectura de sistemas residentes combinados con servicios de Windows, y la resolución de problemas de aplicaciones residentes existentes.

Referencias

  1. Microsoft Learn, NotifyIcon Class / NotifyIcon.Visible Property. Sobre que NotifyIcon es el componente que muestra un icono en el área de notificación, la necesidad de establecer la propiedad Icon, y que Visible tiene por defecto el valor false.  2 3

  2. Microsoft Learn, NotifyIcon.Text Property. Sobre el límite del texto de información sobre herramientas y la ArgumentException que se lanza al superarlo.  2

  3. Microsoft Learn, Windows Forms Controls and Equivalent WPF Controls. Sobre la ausencia en WPF de un control equivalente a NotifyIcon.  2

  4. Microsoft Learn, MSBuild properties for .NET desktop projects. Sobre la posibilidad de habilitar juntos UseWPF y UseWindowsForms.  2

  5. Microsoft Learn, Form.FormClosing Event. Sobre que el evento se dispara antes de que se cierre el formulario, y que Cancel permite cancelar el cierre.  2

  6. Microsoft Learn, Windows notifications overview. Tabla de la API de notificaciones recomendada según el tipo de aplicación, incluida la recomendación de Windows App SDK para WinForms/WPF/Win32 no empaquetado, y el estado «solo mantenimiento» de Windows.UI.Notifications.  2

  7. Microsoft Learn, Windows Community Toolkit — Notifications (archive). Sobre el archivado del componente Notifications, sustituido por las notificaciones de aplicación de Windows App SDK. 

  8. Microsoft Learn, Use the Windows App SDK in an existing project. Sobre que la API de notificaciones de aplicación de Windows App SDK es compatible tanto con aplicaciones empaquetadas como no empaquetadas, sin requerir identidad de paquete.  2

  9. Microsoft Learn, Quickstart: App notifications in the Windows App SDK. Sobre el uso de AppNotificationManager/AppNotificationBuilder, el registro automático mediante Register() en aplicaciones no empaquetadas, la necesidad de suscribirse a NotificationInvoked antes de Register(), y las declaraciones de manifiesto para aplicaciones empaquetadas.  2 3 4

  10. Microsoft Learn, App notifications overview. Sobre que el envío de notificaciones desde una aplicación elevada no es compatible.  2

  11. Microsoft Learn, Notifications don’t appear or aren’t displayed. Sobre la supresión de notificaciones mediante el modo No molestar (Quiet Hours / Focus Assist), la activación automática durante la primera hora tras una actualización del sistema operativo, y los pasos de comprobación cuando las notificaciones no se muestran.  2

  12. Microsoft Learn, Focus assist. Sobre que el asistente de enfoque suprime la visualización del banner de la notificación y la envía directamente al centro de notificaciones.  2

  13. Microsoft Learn, Service Changes for Windows Vista / Interactive Services. Sobre que la sesión 0 está dedicada exclusivamente a los servicios y no admite la interacción con un usuario, y la recomendación de usar CreateProcessAsUser para crear un proceso en la sesión del usuario y coordinarse mediante IPC para mostrar algo al usuario.  2

  14. Microsoft Learn, NotifyIcon.Text maximum text length increased. Sobre el cambio disruptivo en .NET 6 que amplió la longitud máxima de Text de 63 a 127 caracteres. 

  15. Microsoft Learn, How to associate a shortcut menu with a Windows Forms NotifyIcon component. Sobre la asociación de un menú de clic derecho mediante ContextMenuStrip. 

  16. Microsoft Learn, FormClosingEventArgs Class. Sobre la posibilidad de determinar el motivo del cierre del formulario mediante CloseReason. 

  17. Microsoft Learn, How to close a window or dialog box (WPF). Sobre el patrón del evento Closing de WPF de establecer e.Cancel = true y llamar a Hide() para ocultar en lugar de cerrar. 

  18. Microsoft Learn, Notification Area (Windows Shell). Sobre que los iconos se agregan por defecto al área de desbordamiento, que solo el usuario puede promocionar un icono al área de notificación, y la necesidad de eliminar los iconos innecesarios mediante NIM_DELETE.  2

  19. Microsoft Learn, The Taskbar. Sobre la transmisión del mensaje TaskbarCreated al crearse la barra de tareas, y la necesidad de volver a registrar el icono de la bandeja al recibirlo. 

  20. Microsoft Learn, Shell_NotifyIconW function. Sobre que las notificaciones tipo globo se muestran como un toast (banner) y persisten en el centro de notificaciones en Windows 10, son una visualización temporal que no persiste en Windows 11, y que la duración de visualización sigue la configuración de accesibilidad. 

  21. Microsoft Learn, Send a local toast notification from a C# app (Win32/API clásica). Sobre el requisito de registrar un acceso directo con AUMID en el menú Inicio al usar el ToastNotificationManager puro. 

  22. Microsoft Learn, AppNotificationManager.Register Method. Sobre la necesidad de llamar a Unregister antes de que la aplicación se cierre para limpiar los recursos y garantizar que los inicios posteriores desde una notificación funcionen correctamente, y el uso de UnregisterAll para borrar la información de registro cuando las notificaciones ya no se vayan a usar nunca más. 

  23. Microsoft Learn, AppNotificationManager.UpdateAsync Method / Windows App SDK deployment architecture. Sobre que la clase AppNotificationManager depende del paquete Singleton de Windows App SDK, y las consideraciones para invocarla desde una aplicación autónoma (self-contained). 

  24. Microsoft Learn, App notification progress bar and data binding. Sobre el enlace de datos mediante los métodos Bind, la actualización mediante AppNotificationProgressData y UpdateAsync, y las diferencias entre actualización y reemplazo (posición en el centro de notificaciones, qué se puede modificar, reaparición del popup, y comportamiento tras cerrar el usuario la notificación), y que al completarse debería considerarse un reemplazo.  2

  25. Microsoft Learn, AppNotificationProgressData(UInt32) Constructor. Sobre que el número de secuencia es un entero distinto de cero que especifica el orden de actualización, mostrándose los datos con el número más alto cuando se reciben varias actualizaciones. 

  26. Microsoft Learn, Remove app notifications. Sobre la asignación de etiquetas/grupos, la eliminación de notificaciones ya mostradas, y el establecimiento de una caducidad. 

  27. Microsoft Learn, App notification content. Sobre la prioridad de las notificaciones importantes con scenario=”urgent” sobre la configuración de No molestar, con el consentimiento del usuario. 

Artículos recientes con las mismas etiquetas para profundizar en temas cercanos.

Estas páginas sitúan el tema en un contexto más amplio de servicios y decisiones.

El artículo está directamente relacionado con los siguientes servicios.

Preguntas frecuentes

Preguntas habituales en las consultas sobre el tema del artículo.

¿Cómo se crea una aplicación residente en la bandeja del sistema con WPF?
WPF no dispone de ningún control equivalente a NotifyIcon, por lo que la configuración mínima consiste en habilitar tanto UseWPF como UseWindowsForms en el csproj y usar el NotifyIcon de WinForms. Si se desea un estilo de escritura compatible con XAML, una biblioteca de terceros como H.NotifyIcon es una opción, pero conviene tener en cuenta que no es un componente oficial de Microsoft antes de decidir adoptarla.
¿Qué API debería usarse para las notificaciones toast?
Para cualquier desarrollo nuevo a partir de 2026, ya se trate de una aplicación WinForms, WPF o no empaquetada, el AppNotificationManager de Windows App SDK es la solución oficialmente recomendada. Microsoft.Toolkit.Uwp.Notifications está archivado y ya no forma parte del Community Toolkit actual, mientras que el ToastNotificationManager de WinRT se encuentra ahora en estado de solo mantenimiento. Si el código existente ya funciona con alguno de estos dos, no hay prisa por reescribirlo, pero no hay razón para elegirlos en un proyecto nuevo.
¿Qué hay que comprobar cuando una notificación toast no se muestra?
Empiece por la configuración del sistema operativo. Si el asistente de enfoque (no molestar) está activado, las notificaciones no se muestran como un banner y van directamente al centro de notificaciones; además, las notificaciones pueden desactivarse por aplicación o para todo el sistema desde la aplicación Configuración. En el lado de la implementación, las dos causas habituales son que AppNotification no es compatible cuando se envía desde un proceso elevado (administrador), y que Windows.UI.Notifications puro no muestra nada al invocarse desde una aplicación de escritorio sin AUMID.
¿Puede un servicio de Windows enviar notificaciones toast?
No, no puede. Desde Windows Vista, los servicios se ejecutan en la sesión 0 y no tienen ninguna capacidad de mostrar una interfaz de usuario para interactuar con el usuario. Si es necesario notificar al usuario, el patrón estándar consiste en colocar un proceso agente residente en la bandeja del sistema dentro de la sesión del usuario, y hacer que se comunique con el servicio mediante IPC, como tuberías con nombre, siendo el propio agente el responsable de mostrar la notificación.

Perfil del autor

Página de presentación del autor del artículo.

Go Komura

Representante de KomuraSoft LLC

Especializado en desarrollo de software para Windows, consultoría técnica e investigación de fallos, sobre todo en proyectos con sistemas existentes y errores difíciles de reproducir.

Volver al blog