Iconos de la bandeja del sistema y notificaciones toast en aplicaciones Windows — los escollos de NotifyIcon y cómo elegir el AppNotification adecuado
· Actualizado el: · Go Komura · Bandeja del sistema, NotifyIcon, Notificaciones toast, AppNotification, Windows App SDK, WinForms, WPF, C#, .NET, Aplicación residente, Desarrollo Windows, Consultoría técnica
Historial de revisiones (1 actualizaciones, última el 22 Aug 2026)
Registro de los cambios realizados en este artículo. Cuando se archivó una versión previa, sigue siendo legible mediante un enlace permanente con DOI.
- Se ha sustituido la traducción, que estaba abreviada, por una traducción completa del artículo japonés en su versión actual: el texto crece un 36 %. Se han incorporado 5 apartados, 36 filas de tabla, 2 notas al pie y 4 bloques de código que no estaban en la edición anterior. El contenido no cambia respecto al original japonés; esta edición simplemente ya no lo resume. Además, los enlaces a otros artículos que ya tienen edición en español apuntan ahora a esa edición en lugar de a la japonesa. Leer la versión anterior a esta actualización (DOI: 10.5281/zenodo.21638422)
- Primera publicación
Citar este artículo(DOI: 10.5281/zenodo.21638421)
Este artículo está archivado en Zenodo. A continuación se muestran tanto el DOI que siempre resuelve a la última versión como el DOI fijado a la versión que está leyendo.
Go Komura (2026). Iconos de la bandeja del sistema y notificaciones toast en aplicaciones Windows — los escollos de NotifyIcon y cómo elegir el AppNotification adecuado. KomuraSoft LLC. https://doi.org/10.5281/zenodo.21638421 https://comcomponent.com/es/blog/windows-tray-icon-toast-notification-guide/
- DOI (última versión)
- 10.5281/zenodo.21638421
- DOI (esta versión)
- 10.5281/zenodo.22053488
«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á.
Cómo leer este artículo
Como el artículo tiene 11 capítulos y es extenso, aquí tiene puntos de entrada según su objetivo. No es necesario leerlo de principio a fin.
| Objetivo | Dónde leer |
|---|---|
| Solo quiero una visión general | Capítulo 1 (conclusión) y capítulo 11 (resumen) |
| Voy a crear una aplicación residente en la bandeja | Capítulos 2 a 5 ── fundamentos de NotifyIcon, diseño de la ruta de salida, uso combinado con WPF, tres escollos habituales |
| Quiero decidir qué API de notificación toast usar | La tabla comparativa del capítulo 6. Si solo necesita decidir, con esto basta |
| Voy a implementar AppNotification | Capítulo 7 ── implementación mínima, configuración del csproj, distribución del runtime al destino |
| Quiero crear notificaciones más elaboradas, con barra de progreso | Capítulo 8. Puede omitirlo mientras solo busca que funcione |
| Estoy investigando por qué «no aparece la notificación» | Capítulo 9 ── dónde comprobar la configuración del sistema operativo y las restricciones de los procesos elevados |
| Quiero notificar al usuario desde un servicio de Windows | Capítulo 10 |
Términos usados en este artículo
| Término | Significado |
|---|---|
| Área de notificación (bandeja del sistema) | La zona con los iconos alineados en el extremo derecho de la barra de tareas. En la terminología de Windows, «área de notificación (notification area)»1 |
| Notificación toast | Notificación que aparece como un banner en la esquina inferior derecha de la pantalla y permanece en el centro de notificaciones |
| TFM | Target Framework Moniker (identificador de plataforma de destino). Es el identificador que se escribe en <TargetFramework> del csproj, y que expresa tanto la versión de .NET como la plataforma de destino, como en net8.0-windows10.0.19041.0 |
| MSIX | El formato de paquete de aplicaciones de Windows. A una aplicación distribuida en este formato se le llama aplicación «empaquetada (packaged)» |
| Aplicación no empaquetada (unpackaged) | El exe tradicional, no empaquetado con MSIX. Las aplicaciones de escritorio WPF, WinForms y Win32 son así por defecto2 |
| AUMID | AppUserModelID. El identificador que usa Windows para identificar de forma unívoca una aplicación, y que se emplea para identificar al remitente de una notificación toast |
| Sesión 0 | La sesión reservada exclusivamente para los servicios desde Windows Vista. No puede tener una interfaz de usuario interactiva (capítulo 10)3 |
1. Lo esencial primero
- La base de la residencia en la bandeja sigue siendo
System.Windows.Forms.NotifyIcon. No aparece a menos que establezcaIcony pongaVisible = true(el valor predeterminado esfalse). El texto de información sobre herramientasTextpuede llegar hasta 127 caracteres a partir de .NET 6 (63 caracteres antes de eso).45 - WPF no tiene ningún control equivalente a NotifyIcon. La tabla de comparación oficial indica explícitamente «Ningún control equivalente». Habilitar tanto
UseWPFcomoUseWindowsFormsen el csproj y usar el NotifyIcon de WinForms es la configuración mínima.67 - «Mantener la aplicación en la bandeja incluso cuando el usuario hace clic en el botón de cerrar» se implementa estableciendo
e.Cancel = trueenFormClosingy llamando aHide(). Proporcione siempre una forma explícita y separada de salir (un elemento «Salir» en el menú de la bandeja) y compruebeCloseReasonpara no bloquear nunca un apagado del sistema operativo.8 - 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
AppNotificationManagerde Windows App SDK (NuGet: Microsoft.WindowsAppSDK).Windows.UI.Notificationsestá «solo en mantenimiento», y el componente de notificaciones del Community Toolkit está archivado.910 - 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.111213 - 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.1415
- 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.3
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.4
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 conviene tener presentes.
- Solo se muestra cuando
IconyVisible = trueestán presentes a la vez. El valor predeterminado deVisibleesfalse.4 Texttiene un límite de longitud. A partir de .NET 6 el máximo es de 127 caracteres; en .NET 5 y anteriores, y en .NET Framework, es de 63 caracteres, y superarlo provoca unaArgumentException. Una implementación que intenta meter demasiado estado en la información sobre herramientas puede acabar fallando de repente con una excepción.516- El menú del clic derecho se asocia mediante
ContextMenuStrip. Como el icono de la bandeja suele ser el único punto de entrada visible para el usuario, prepare como mínimo las opciones «Abrir» y «Salir».17
Hay otro aspecto a tener en cuenta: el icono de la bandeja no es solo la puerta de entrada a las notificaciones, sino también un indicador de estado siempre visible. Como Icon y Text pueden reemplazarse mientras la aplicación se ejecuta, si los mantiene reflejando el estado actual —por ejemplo, «icono normal en condiciones normales, icono de advertencia ante una anomalía» o «mostrar la hora del último procesamiento en la información sobre herramientas»—, el usuario podrá conocer el estado actual con solo mirar el icono, aunque haya pasado por alto un toast. Es una división de funciones: el toast informa «de lo que acaba de ocurrir en ese instante», mientras que el icono de la bandeja «sigue mostrando el estado actual».
3. El diseño «se mantiene en la bandeja al cerrar» y la ruta de salida correcta
Un comportamiento clásico de las aplicaciones residentes es que, al pulsar el botón de cerrar (×), el proceso no termina y la aplicación permanece en la bandeja. La implementación en sí es sencilla, con la cancelación de FormClosing, pero si se escribe de forma descuidada puede provocar dos incidentes: que ya no quede ninguna forma de salir de la aplicación y que se bloquee el apagado de Windows.
private bool _exitRequested;
protected override void OnFormClosing(FormClosingEventArgs e)
{
// Si el usuario solo pulsó ×, ocultar en lugar de cerrar
if (!_exitRequested && e.CloseReason == CloseReason.UserClosing)
{
e.Cancel = true;
Hide();
return;
}
// Si viene del menú "Salir" o de un apagado del sistema operativo, cerrar con normalidad
base.OnFormClosing(e);
}
private void ExitApplication()
{
_exitRequested = true;
_trayIcon.Visible = false;
_trayIcon.Dispose();
Close();
}
FormClosing se produce antes de que el formulario se cierre, y e.Cancel = true permite cancelar el cierre. En este punto es imprescindible comprobar CloseReason. El comportamiento correcto es cancelar solo cuando el motivo es UserClosing (una acción del usuario), y no cancelar los cierres originados por el sistema operativo, como WindowsShutDown.818
En WPF el planteamiento es el mismo: el patrón de establecer e.Cancel = true en Window.Closing y llamar a Hide() aparece tal cual en la documentación oficial.19
Cabe señalar que, por su propia naturaleza, una aplicación residente convive con el riesgo de «procesar el mismo evento dos veces si se inicia por duplicado». La prevención de la ejecución múltiple se trata en «Prevención de la ejecución múltiple de aplicaciones Windows ── Mutex con nombre y activación al iniciar por duplicado». Además, la forma de construir el contenido de una aplicación residente (el bucle de supervisión, el procesamiento periódico) se apoya en «Por qué usar .NET Generic Host y BackgroundService en una aplicación de escritorio».
4. Residencia en la bandeja en aplicaciones WPF
WPF no tiene ningún control equivalente a NotifyIcon. Se trata de una carencia reconocida oficialmente: la tabla comparativa «Controles de WinForms y sus controles WPF equivalentes» indica explícitamente «No equivalent control» (ningún control equivalente).6
Las opciones prácticas son dos.
| Opción | Resumen | Criterio de decisión |
|---|---|---|
| Usar el NotifyIcon de WinForms junto con WPF | Habilitar UseWPF + UseWindowsForms en el csproj |
Sin dependencias adicionales. Suficiente si solo necesita un icono y un menú |
| Biblioteca de terceros (como H.NotifyIcon) | Implementación de icono de bandeja para WPF/WinUI | Cuando se quiere escribir en XAML o se necesitan ventanas emergentes más elaboradas. Tenga en cuenta que no es de Microsoft |
La primera opción consiste simplemente en escribir dos propiedades juntas en un archivo de proyecto de estilo SDK.7
<PropertyGroup>
<TargetFramework>net8.0-windows</TargetFramework>
<UseWPF>true</UseWPF>
<UseWindowsForms>true</UseWindowsForms>
</PropertyGroup>
Puede crear una instancia normal de System.Windows.Forms.NotifyIcon desde el Application de WPF y usarla sin más. Solo el menú queda en WinForms (ContextMenuStrip), pero para algo del tamaño de un menú de bandeja esto rara vez supone un problema práctico.
5. Tres escollos del icono de la bandeja
5.1. El icono se ubica de forma predeterminada entre los «iconos ocultos» — no se puede forzar su visualización permanente
Siempre surge la petición de mantener el propio icono visible de forma permanente en la barra de tareas, pero esto no se puede lograr desde el programa. La documentación oficial indica explícitamente que, de forma predeterminada, el icono se añade a la zona de desbordamiento (iconos ocultos), y que solo el usuario puede decidir promoverlo al área de notificación (visualización permanente).1
En Windows 11, el usuario activa o desactiva esto por aplicación desde «Configuración → Personalización → Barra de tareas → Otros iconos de la bandeja del sistema». Si la visualización permanente es importante desde el punto de vista operativo, lo correcto es indicarlo en el manual de instalación o en la ayuda: «active esta opción».
Si en el manual se incluye la ruta completa del menú, será posible guiar al usuario incluso por teléfono. A continuación se muestra un ejemplo de texto.
- Haga clic con el botón derecho en un espacio vacío de la barra de tareas y elija «Configuración de la barra de tareas».
- En la pantalla que se abre, entre en «Otros iconos de la bandeja del sistema».
- Busque esta aplicación en la lista y active el interruptor.
- Si no encuentra el icono, pulse el botón «^» (flecha hacia arriba) situado a la derecha de la barra de tareas: los iconos ocultos se mostrarán temporalmente.
5.2. El icono desaparece al reiniciar el Explorador — TaskbarCreated
Cuando el Explorador recrea la barra de tareas tras un bloqueo o un reinicio, los iconos de bandeja ya registrados desaparecen. Al crear la barra de tareas, el shell difunde el mensaje TaskbarCreated a todas las ventanas de nivel superior, así que la norma a nivel de Win32 es volver a registrar el icono al recibirlo.20
El NotifyIcon de WinForms gestiona este mensaje internamente y se reregistra de forma automática, por lo que normalmente no hace falta tenerlo en cuenta. Si invoca Shell_NotifyIcon mediante P/Invoke por su cuenta (o si mantiene una aplicación nativa con icono de bandeja), compruebe que este reregistro esté implementado. El síntoma de «al reiniciar el Explorador solo desaparece el icono, pero el proceso sigue vivo» casi siempre se debe a esto.
5.3. Olvidar Dispose deja el icono huérfano
A nivel de Win32, un icono de bandeja que ya no se necesita debe eliminarse de forma explícita (NIM_DELETE), y en WinForms esa responsabilidad recae en NotifyIcon.Dispose().1 Asegúrese de que la ruta de salida pase siempre por Visible = false → Dispose(). Si el proceso termina de forma anómala y el icono no llega a eliminarse, queda un icono fantasma que persiste hasta que el cursor del ratón pasa por encima; es una escena que todo desarrollador de aplicaciones residentes ha visto alguna vez.
Como en el código del capítulo 3, lo más seguro es que el manejador del elemento de menú «Salir» limpie primero el icono de la bandeja y llame a Close() después.
6. Notificaciones toast — qué API usar
Una notificación toast es una notificación que se muestra como un banner en la esquina inferior derecha de la pantalla y permanece en el centro de notificaciones. La forma de emitirlas desde una aplicación de escritorio ha cambiado de generación repetidamente durante la última década, y los resultados de búsqueda conservan una gran cantidad de ejemplos anticuados. A continuación se resume la situación en 2026.9
| API | NuGet / espacio de nombres | Posición (a fecha de 2026) | Decisión |
|---|---|---|---|
| Windows App SDK AppNotification | Microsoft.WindowsAppSDK / Microsoft.Windows.AppNotifications |
Recomendación oficial para WinForms, WPF y Win32 no empaquetado | La opción para todo desarrollo nuevo |
| Community Toolkit Notifications | Microsoft.Toolkit.Uwp.Notifications | Archivado. No forma parte del Community Toolkit actual; su última actualización fue 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. Su público recomendado es UWP | No adoptar en proyectos nuevos |
| NotifyIcon.ShowBalloonTip | System.Windows.Forms |
API de notificaciones tipo globo. En Windows 10 se muestra como un toast; en Windows 11 aparece de forma temporal y no permanece en el centro de notificaciones | Válido para usos sencillos. Tenga en cuenta que su comportamiento cambia según el sistema operativo |
Hay dos aclaraciones adicionales.
ShowBalloonTippertenece a la categoría de «API antigua pero en realidad sigue viva». En Windows 10 el globo se dibuja como un toast y permanece en el centro de notificaciones hasta que se cierra. En Windows 11, en cambio, se muestra de forma temporal, de forma similar al globo tradicional, y no permanece en el centro de notificaciones una vez que desaparece. Además, actualmente se ignora el tiempo de visualización especificado (timeout) y se sigue la configuración de accesibilidad del sistema operativo. Es suficiente si una aplicación residente en la bandeja solo necesita avisar de forma ligera de sus propios cambios de estado, pero tenga presente que en Windows 11 no sirve si lo que busca es «dejar un historial en el centro de notificaciones».21- El método clásico de usar
Windows.UI.Notificationspuro desde una aplicación de escritorio tiene una restricción conocida: el toast no se muestra a menos que haya registrado en el menú Inicio un acceso directo con un AUMID (AppUserModelID).22 Esta molestia es precisamente lo que resuelve el AppNotification del siguiente capítulo.
Hasta dónde llega el «válido para usos sencillos» de la tabla se puede delimitar por funcionalidad. Si se cumplen las cinco condiciones siguientes, ShowBalloonTip es suficiente y no hace falta añadir una dependencia de Windows App SDK.
- Para empezar, la aplicación ya tiene un icono de bandeja (el globo es una notificación asociada al icono de bandeja, así que esto es un requisito previo)
- La notificación no necesita botones de acción ni campos de entrada. Basta con que, al hacer clic, se traiga al frente la ventana de la aplicación
- No es necesario conservarla como historial en el centro de notificaciones. Como no permanece en Windows 11, no sirve para «volver a consultarla más tarde»21
- No se necesita barra de progreso ni actualizar el contenido de una notificación ya mostrada
- La notificación es una ayuda del tipo «si se nota, se puede reaccionar antes», y el trabajo sigue adelante aunque se pase por alto
Por el contrario, si se cumple aunque sea una sola de las siguientes condiciones, use sin dudarlo el AppNotification del capítulo 7.
| Requisito | Motivo |
|---|---|
| Quiere poner botones (como «Abrir el registro») o campos de entrada en la notificación | El globo solo tiene título, cuerpo e icono; no puede tener elementos interactivos |
| Quiere que permanezca en el centro de notificaciones también en Windows 11 | El globo no permanece en Windows 1121 |
| Quiere actualizar el progreso de un proceso largo en una sola notificación | La barra de progreso y UpdateAsync son funciones de AppNotification (capítulo 8) |
| Necesita gestionar también la recuperación desde un estado en el que la aplicación no está en ejecución | El globo no existe si la aplicación no se ha iniciado y no muestra un icono de bandeja. AppNotification puede iniciar el proceso al hacer clic en la notificación (capítulo 7) |
| Quiere poder eliminar o reemplazar notificaciones antiguas más tarde desde el código | La gestión mediante Tag / Group es una función de AppNotification (capítulo 8) |
Cuando dude, hay un único criterio: si quiere o no que el usuario realice alguna acción sobre esa notificación. Si solo hace falta que la lea, use el globo; si hace falta que pulse algo, use AppNotification.
7. Implementación mínima de AppNotification en Windows App SDK
La API de notificaciones de aplicación de Windows App SDK funciona incluso en un exe normal sin empaquetar, sin identidad de paquete.11 Sin embargo, no basta con «instalar el paquete NuGet»: hay requisitos previos tanto del lado del desarrollo como del lado de la distribución. Vamos a verlos en orden.
7.1. Preparación del proyecto — NuGet y el csproj
Los requisitos previos oficiales son tres: que sea un proyecto WPF o WinForms de .NET 6 o posterior, que ese proyecto esté configurado para poder llamar a las API de WinRT, y que esté configurado para usar Windows App SDK.12
Hay dos cosas que hacer. Primero, añada el paquete NuGet Microsoft.WindowsAppSDK (en Visual Studio, desde «Herramientas → Administrador de paquetes NuGet → Administrar paquetes NuGet para la solución»). Este paquete incluye los subpaquetes de cada componente de Windows App SDK, y la documentación oficial también recomienda instalar primero el paquete principal.2
A continuación, edite el csproj. Si al ejemplo de WPF + WinForms del capítulo 4 se le añade lo necesario para Windows App SDK, queda así.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<!-- Para poder llamar a las API de WinRT, el TFM debe incluir la versión de Windows -->
<TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
<UseWPF>true</UseWPF>
<UseWindowsForms>true</UseWindowsForms>
<!-- Aplicación no empaquetada (no MSIX): inicializa el runtime automáticamente al arrancar -->
<WindowsPackageType>None</WindowsPackageType>
</PropertyGroup>
<ItemGroup>
<!-- La versión será la que haya elegido en el administrador de paquetes NuGet -->
<PackageReference Include="Microsoft.WindowsAppSDK" Version="(versión estable elegida)" />
</ItemGroup>
</Project>
<WindowsPackageType>None</WindowsPackageType> es la clave. Una aplicación no empaquetada debe inicializar el runtime antes de usar cualquier función de Windows App SDK, y escribir esta propiedad activa la inicialización automática (auto-initialization) en el arranque. Al compilar, se añaden al proyecto MddBootstrapAutoInitializer.cs y WindowsAppSDK-VersionInfo.cs. Solo si necesita un control más fino, llame directamente a la API de arranque (bootstrap) en lugar de usar la inicialización automática.2
7.2. Distribución del runtime al destino
Este es un punto que suele pasarse por alto. En el caso de una aplicación no empaquetada, la responsabilidad de hacer llegar el runtime de Windows App SDK al equipo del usuario recae en quien la distribuye.23 No basta con distribuir el exe.
Como requisito previo, una aplicación no empaquetada también necesita los paquetes redistribuibles de Visual C++.23 Hay dos formas de instalarlo.
| Método | Contenido | Caso adecuado |
|---|---|---|
| Ejecutar el instalador | Ejecutar WindowsAppRuntimeInstall.exe, distribuido oficialmente. Hay un instalador distinto para x86, x64 y Arm64, y solo debe colocarse el paquete de la arquitectura indicada en el nombre23 |
Lo habitual |
| Instalar el paquete MSIX directamente | Incluir el paquete MSIX junto con la propia instalación o el MSI y colocarlo así23 | Cuando se quiere controlar la instalación con más detalle |
Como el instalador no tiene interfaz de usuario, se invoca encadenado desde el propio instalador de la aplicación. Existen opciones para ejecutarlo de forma desatendida.23
:: Instala sin mostrar ninguna pantalla ni salida de texto
WindowsAppRuntimeInstall.exe --quiet
:: Fuerza la actualización tras cerrar los procesos de Windows App SDK en uso (desde la versión 1.1)
WindowsAppRuntimeInstall.exe --force
Hay tres puntos que conviene tener en cuenta al instalarlo.23
- El resultado cambia según si se dispone o no de privilegios de administrador. Si se ejecuta elevado y el usuario que lo ejecuta tiene privilegios de administrador, se registra para todo el sistema (incluidos los usuarios que se añadan en el futuro). En caso contrario, la instalación se limita solo al usuario que lo ejecutó. El valor de retorno
0x80070005corresponde precisamente a este caso de «no elevado / sin privilegios de administrador». - El éxito o el fracaso se determina por el valor de retorno.
0x0significa éxito;0x80073d06indica que uno o más paquetes no se instalaron. Si lo encadena desde su propio instalador, compruebe siempre este valor de retorno. - El runtime instalado en el equipo de desarrollo debe coincidir con la versión y el canal de publicación del paquete NuGet referenciado.2 No es raro que la causa de «funciona en el equipo de desarrollo pero no en el destino» esté precisamente aquí.
Si distribuye la aplicación empaquetada en MSIX, la distribución del runtime puede tratarse como una dependencia del paquete, pero a cambio es necesario declarar el activador COM en Package.appxmanifest (véase el final de la sección 7.3).
7.3. Implementación mínima
using System;
using System.Windows.Forms;
using Microsoft.Windows.AppNotifications;
using Microsoft.Windows.AppNotifications.Builder;
internal static class ToastActivation
{
private static readonly object Gate = new();
private static Action? _pending;
private static bool _uiReady;
// Una sola vez, al arrancar. El orden importa: primero registrar el manejador, luego llamar a Register()
public static void Initialize()
{
AppNotificationManager.Default.NotificationInvoked += (_, args) =>
{
// Aquí llegan el clic en el toast y la pulsación de botones (el argumento se distingue con args.Arguments)
if (!args.Arguments.TryGetValue("action", out var action) || action != "openLog")
{
return;
}
// NotificationInvoked se produce en un hilo en segundo plano.
// Cualquier operación que toque la UI debe pasarse siempre al hilo de la UI
Dispatch(ShowLogWindow);
};
AppNotificationManager.Default.Register();
}
// Se llama desde el OnShown de MainForm. Aquí se procesa lo que llegó antes de que existiera el formulario
public static void MarkUiReady()
{
Action? pending;
lock (Gate)
{
_uiReady = true;
pending = _pending;
_pending = null;
}
// OnShown se ejecuta en el hilo de la UI, así que puede invocarse directamente
pending?.Invoke();
}
private static void Dispatch(Action action)
{
lock (Gate)
{
if (!_uiReady)
{
// El clic en el toast fue lo que inició la aplicación: en este punto todavía
// no existe ningún formulario. Se guarda en espera y MarkUiReady lo procesará
_pending = action;
return;
}
}
MainWindow()?.Invoke(action);
// Para WPF: Application.Current.Dispatcher.Invoke(action);
}
private static Form? MainWindow() =>
Application.OpenForms.Count > 0 ? Application.OpenForms[0] : null;
private static void ShowLogWindow() { /* Abre la ventana de registro */ }
}
// Lado de MainForm. Si el arranque se debió al clic en un toast, se recoge aquí
protected override void OnShown(EventArgs e)
{
base.OnShown(e);
ToastActivation.MarkUiReady();
}
ToastActivation.Initialize();
// Emitir la notificación
var notification = new AppNotificationBuilder()
.AddText("Se completó la importación de pedidos")
.AddText("12 nuevos, 1 error")
.AddButton(new AppNotificationButton("Abrir el registro")
.AddArgument("action", "openLog"))
.BuildNotification();
AppNotificationManager.Default.Show(notification);
Las siguientes son consideraciones prácticas.
- Suscríbase a
NotificationInvokedantes de llamar aRegister(). Si invierte el orden, perderá el evento cuando la aplicación se inicie por un clic en el toast.12 - Si la aplicación se inició por ese clic, en el momento en que se ejecuta el manejador todavía no existe ningún formulario. Si comprueba
Application.OpenFormsy, al sernull, no hace nada, la operación de esta ruta se descarta en silencio. Como se muestra arriba, guárdela una vez y procésela después de que se muestre el formulario. De nada sirve recibir el evento en el orden correcto si luego se descarta aquí. NotificationInvokedse produce en un hilo en segundo plano. El propio ejemplo oficial indica explícitamente: «como se produce en un hilo en segundo plano, las actualizaciones de la UI deben despacharse al hilo de la UI». Si desde el manejador abre ventanas o manipula controles directamente, se encontrará con excepciones relacionadas con hilos o bloqueos difíciles de explicar. Páselo al hilo de la UI conApplication.Current.Dispatcher.Invoke(...)en WPF, o conControl.Invoke(...)en WinForms.12- Llame a
AppNotificationManager.Default.Unregister()antes de que la aplicación termine. La documentación oficial indica explícitamente que se deben liberar los recursos con Unregister antes de salir, para que los futuros clics en notificaciones inicien la aplicación correctamente. Incorpórelo junto aNotifyIcon.Dispose()en el manejador del menú «Salir» del capítulo 3 (para cuando se desinstala una aplicación que ya no va a usar nunca más la función de notificaciones, existe ademásUnregisterAll(), que borra también la información de registro).24 - En una aplicación no empaquetada,
Register()realiza automáticamente el registro del servidor COM y el trabajo equivalente al AUMID. No hace falta la instalación de accesos directos ni el registro en el registro de Windows que exigía la generación anterior (WinRT puro). Si empaqueta con MSIX, en cambio, sí es necesario declarar el activador COM en Package.appxmanifest.12 - Tenga cuidado si opta por una distribución self-contained que incluya el runtime de Windows App SDK.
AppNotificationManagerdepende del paquete Singleton de Windows App SDK, y la documentación oficial describe consideraciones específicas al invocarlo desde una aplicación self-contained. Revíselas antes de decidir el método de distribución.25 - Las notificaciones desde un proceso elevado a administrador no son compatibles.
Showfalla en silencio, sin lanzar una excepción, por lo que es un problema difícil de detectar. Si su aplicación necesita elevación, considere separar solo la notificación en un proceso no elevado (este planteamiento de separación se trata en «Cómo separar en la práctica solo el procesamiento que requiere privilegios de administrador en una aplicación Windows»).13 - Cuando se hace clic en el toast, si la aplicación no está en ejecución, se inicia un nuevo proceso. En una aplicación residente en la bandeja, esto debe combinarse con la prevención de la ejecución múltiple (véase el capítulo 3) para que el diseño transfiera el procesamiento a la instancia ya existente.
8. Un paso más allá — toasts con barra de progreso y limpieza de notificaciones
8.1. Actualizar el progreso dentro del toast — UpdateAsync
Para el progreso de un proceso largo, como «importando 120 registros de pedidos», la forma correcta de construirlo no es volver a emitir la notificación una y otra vez, sino reescribir la barra de progreso dentro de un único toast. AppNotification dispone de un mecanismo de enlace de datos y actualización pensado justo para esto.26
La construcción tiene tres pasos. Primero, convierta cada valor de la barra de progreso en un marcador de posición con los métodos Bind, y muéstrela de forma que la notificación pueda identificarse mediante Tag (y Group si es necesario). Después, basta con pasar un AppNotificationProgressData a UpdateAsync para que solo se reescriba el contenido del toast ya mostrado.
const string tag = "import-progress";
const string group = "batch";
// Primera visualización: los valores se enlazan y el valor inicial se establece 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"
};
AppNotificationManager.Default.Show(notification);
// Cada vez que avanza el progreso: se incrementa el número de secuencia y se actualiza
var data = new AppNotificationProgressData(2)
{
Status = "Importando...", Value = 45 / 120.0, ValueStringOverride = "45/120"
};
await AppNotificationManager.Default.UpdateAsync(data, tag, group);
El número de secuencia es un entero distinto de cero que indica el orden de las actualizaciones; si llegan varias actualizaciones desordenadas, se muestra la que tiene el número más alto. Es un mecanismo pensado para que, aunque se envíen actualizaciones en paralelo desde procesos asíncronos, el valor no retroceda a uno antiguo, así que hágalo estrictamente creciente.27
8.2. Cuándo usar «actualizar» y cuándo «reemplazar»
También se puede actualizar la apariencia «reemplazando» —volviendo a llamar a Show con una nueva notificación que use el mismo Tag—, pero el comportamiento es distinto.26
| Reemplazar (volver a Show con el mismo Tag) | Actualizar (UpdateAsync) | |
|---|---|---|
| Posición en el centro de notificaciones | Se mueve al principio | Permanece en su sitio |
| Qué se puede cambiar | Todo, incluido el diseño | Solo la barra de progreso enlazada y el primer texto |
| Ventana emergente | Puede volver a mostrarse | No vuelve a mostrarse (se reescribe en silencio) |
| Si el usuario ya la había cerrado | Siempre se envía | Falla |
La recomendación de la documentación oficial también es clara: actualizar durante el progreso, reemplazar al finalizar. No hace falta avisar con una ventana emergente cada vez que el progreso pasa del 50 % al 65 %, pero un mensaje como «importación completada (3 errores)» debe llegar incluso si el usuario ya cerró la notificación de progreso. Un patrón habitual en la práctica es, al completarse el proceso, quitar la barra de progreso y reemplazarla por un diseño distinto con botones (por ejemplo, «Ver detalles de los errores»).
8.3. Limpiar las notificaciones antiguas que quedan en el centro de notificaciones
Los toasts se van acumulando en el centro de notificaciones hasta que el usuario los elimina. Si una aplicación residente emite varias notificaciones cada día, el centro de notificaciones acaba lleno de notificaciones antiguas de esa misma aplicación, y las notificaciones realmente importantes terminan enterradas.
Si se asignan Tag / Group, es posible eliminar desde el código las notificaciones de la propia aplicación (por etiqueta, por grupo o eliminando todas). También se puede configurar una fecha de caducidad, así que se recomienda decidir de antemano, junto con el diseño de las notificaciones, reglas de limpieza como «eliminar las de progreso al completarse» o «acortar la caducidad de las informativas».28
9. Incorporar al diseño los casos en que la notificación «no llega»
Las notificaciones toast no son un medio de comunicación garantizado. Existen, como parte del comportamiento normal, casos en los que no se muestran o pasan desapercibidas.
| Caso | Comportamiento |
|---|---|
| El asistente de enfoque (Focus Assist / no molestar) está activado | El banner no se muestra; la notificación va directamente al centro de notificaciones |
| Las notificaciones están desactivadas por aplicación o para todo el sistema | No se muestra |
| AppNotification desde un proceso elevado a administrador | No compatible. No se muestra |
| Se está ejecutando una aplicación a pantalla completa, entre otros casos | El sistema operativo puede suprimirla según su propio criterio |
El modo no molestar lo controlan el usuario o una directiva de grupo mediante el «Modo de concentración (Focus assist)» en Windows 10, o el interruptor «No molestar» en «Configuración → Sistema → Notificaciones» en Windows 11. Incluso existe una especificación por la que se activa automáticamente durante la hora siguiente a una actualización del sistema operativo.14 El comportamiento del modo de concentración no es «no emitir la notificación», sino «suprimir el banner y enviarla al centro de notificaciones», así que el usuario podrá verla más tarde si abre el centro de notificaciones.15
Conviene tener a mano la ruta completa del menú donde comprobar cada cosa, porque resulta más rápido sobre el terreno. Es habitual guiar al usuario por teléfono o chat cuando «no aparece la notificación».
| Qué comprobar | Dónde mirar (Windows 11) |
|---|---|
| Si el modo no molestar está activado | Configuración → Sistema → Notificaciones → interruptor «No molestar» |
| Si hay configuradas condiciones que activan el modo no molestar automáticamente | En la misma pantalla de «Notificaciones», la configuración de condiciones para activar el modo no molestar de forma automática |
| Si las notificaciones de la propia aplicación están desactivadas | En la misma pantalla de «Notificaciones», desplácese hacia abajo y busque la aplicación en la lista por aplicación |
| Si solo falta el banner o si la notificación no llega en absoluto | Haga clic en la fecha y la hora, en el extremo derecho de la barra de tareas, para abrir el centro de notificaciones y comprobar si hay notificaciones acumuladas |
| Si el icono de la bandeja simplemente está oculto | Configuración → Personalización → Barra de tareas → Otros iconos de la bandeja del sistema (sección 5.1) |
En Windows 10, el equivalente al modo no molestar es «Configuración → Sistema → Modo de concentración». Comprobar primero si ha llegado al centro de notificaciones es el atajo para aislar el problema: si llegó, puede sospechar de una supresión del banner por parte del sistema operativo (como el modo no molestar); si no llegó, puede sospechar del propio envío desde la aplicación.
Las implicaciones para el diseño son sencillas.
- Use el toast como un canal auxiliar del tipo «si se nota, se puede reaccionar antes», y asegúrese de que la información imprescindible para el negocio siempre pueda comprobarse en una pantalla o un listado dentro de la propia aplicación. No dé por sentado en el flujo de trabajo que «el toast debió mostrarse».
- Para las notificaciones que necesitan interrumpir sí o sí (como una advertencia de parada de emergencia), existe un mecanismo que, con el permiso del usuario, atraviesa el modo no molestar mediante
AppNotificationScenario.Urgent(notificación importante)29, pero si se abusa de él, el usuario acabará desactivando todas las notificaciones de la aplicación. Debe reservarse solo para lo realmente urgente.
Para una perspectiva más amplia sobre cómo mostrar en pantalla anomalías de dispositivos externos, consulte también «Buenas prácticas para comprobar y mostrar el estado de dispositivos externos».
10. Cuando quiere notificar desde un servicio de Windows
Es natural que surja el requisito de que «cuando un servicio residente detecte una anomalía, se avise mediante un toast al usuario que ha iniciado sesión», pero un servicio no puede emitir un toast directamente. Desde Windows Vista, los servicios se ejecutan en una sesión exclusiva llamada sesión 0, y no pueden tener una interfaz de usuario que interactúe con el usuario.3
El planteamiento estándar consiste en separar la interfaz de usuario en un proceso del lado de la sesión del usuario.
[Sesión 0] [Sesión de usuario]
Servicio de Windows ←─ IPC ─→ Agente residente en la bandeja
(supervisión y procesos) tuberías con nombre, etc. (NotifyIcon + AppNotification)
- El servicio se dedica exclusivamente a la supervisión y al procesamiento de negocio, y envía al agente por IPC los eventos que quiere notificar.
- El agente es una aplicación residente en la bandeja que se inicia al iniciar sesión el usuario (los propios capítulos 2 a 8 de este artículo), y muestra los eventos recibidos mediante toasts o cambios de icono.
- La elección del mecanismo de IPC se trata en «Cómo elegir la comunicación entre procesos de Windows», la construcción del lado del servicio en «Cómo crear y operar un servicio de Windows», y el propio mecanismo de las sesiones en «Cómo entender la separación de sesiones de Windows ── Sesión 0, RDP y múltiples usuarios simultáneos».
En entornos donde varios usuarios inician sesión simultáneamente (RDP, equipos compartidos), el agente se ejecuta uno por cada sesión. Decidir de antemano, como requisito, «a quién se debe notificar» (a todos o solo a un usuario concreto) evita que el diseño se tambalee.
11. Resumen
- La residencia en la bandeja se basa en
NotifyIcon. Se muestra conIcon+Visible = true,Texttiene un límite de 127 caracteres (.NET 6+), y la ruta de salida debe pasar siempre porDispose(). El icono y la información sobre herramientas también sirven como indicador permanente del «estado actual». - «Permanecer en la bandeja aunque se cierre con ×» se implementa cancelando
FormClosing, pero solo debe cancelarse cuando el motivo esCloseReason.UserClosing, y siempre debe proporcionarse un menú «Salir» explícito. - Solo el usuario puede decidir la visualización permanente del icono. La desaparición al reiniciar el Explorador se resuelve reregistrando con
TaskbarCreated(en WinForms esto es automático). - Para cualquier implementación nueva de notificaciones toast, la única opción es el
AppNotificationManagerde Windows App SDK. Funciona incluso en un exe no empaquetado sin identidad de paquete, yRegister()automatiza el tedioso registro. Las notificaciones del Community Toolkit están archivadas, y el WinRT puro está solo en mantenimiento. Si la notificación es ligera y no necesita botones, historial ni progreso, sigue siendo válido resolverlo conShowBalloonTip(capítulo 6). - En una aplicación no empaquetada, es responsabilidad de quien distribuye hacer llegar el runtime de Windows App SDK al destino. Incluya en el diseño de la distribución tanto escribir
<WindowsPackageType>None</WindowsPackageType>en el csproj como encadenarWindowsAppRuntimeInstall.exedesde el instalador (sección 7.2). - El planteamiento estándar es reescribir en silencio la barra de progreso de un único toast con
UpdateAsyncdurante un proceso largo, y usar el reemplazo para mostrar una ventana emergente al finalizar. AsigneTag/Groupe incluya en el diseño incluso la eliminación de las notificaciones antiguas. - El toast es un canal auxiliar que puede no llegar por el modo no molestar o por tener las notificaciones desactivadas. Diseñe de forma que la información imprescindible pueda comprobarse dentro de la propia aplicación, y tenga en cuenta también que las notificaciones desde procesos elevados no son compatibles.
- La notificación desde un servicio se logra con una configuración separada: un agente residente en la bandeja en la sesión del usuario, combinado con IPC.
Artículos relacionados
- Prevención de la ejecución múltiple de aplicaciones Windows ── Mutex con nombre y activación al iniciar por duplicado
- Cómo crear y operar un servicio de Windows ── de cuándo usarlo frente al Programador de tareas a convertir un BackgroundService en servicio
- Cómo elegir la comunicación entre procesos de Windows ── tabla de decisión entre tuberías con nombre / TCP / gRPC / memoria compartida / COM
- Cómo entender la separación de sesiones de Windows ── Sesión 0, RDP y múltiples usuarios simultáneos
- Por qué usar .NET Generic Host y BackgroundService en una aplicación de escritorio
- Cómo separar en la práctica solo el procesamiento que requiere privilegios de administrador en una aplicación Windows
- Buenas prácticas para comprobar y mostrar el estado de dispositivos externos - un diseño que no se conforma con «conectado»
Áreas de consultoría relacionadas
KomuraSoft LLC se ocupa del diseño e implementación de herramientas de supervisión y agentes de notificación residentes en la bandeja, del estudio de configuraciones de sistemas residentes combinados con servicios de Windows, y de la investigación de fallos en aplicaciones residentes ya existentes.
Referencias
-
Microsoft Learn, Notification Area (Windows Shell). Sobre que el icono se añade de forma predeterminada a la zona de desbordamiento, que solo el usuario puede decidir su promoción al área de notificación, y que un icono que ya no se necesita debe eliminarse con NIM_DELETE. ↩ ↩2 ↩3
-
Microsoft Learn, Use the Windows App SDK in an existing project. Sobre que las aplicaciones de escritorio WPF, WinForms y Win32 son no empaquetadas de forma predeterminada, que se recomienda instalar el paquete NuGet
Microsoft.WindowsAppSDKy comenzar por el paquete principal, que una aplicación no empaquetada necesita inicializar el runtime antes de usar las funciones de Windows App SDK y que<WindowsPackageType>None</WindowsPackageType>activa la inicialización automática en el arranque, que al compilar se añadenMddBootstrapAutoInitializer.csyWindowsAppSDK-VersionInfo.cs, y que el runtime instalado en el equipo de desarrollo debe coincidir con la versión y el canal de publicación del paquete NuGet. ↩ ↩2 ↩3 ↩4 -
Microsoft Learn, Service Changes for Windows Vista / Interactive Services. Sobre que la sesión 0 está reservada para los servicios y no admite la interacción con el usuario, y que se recomienda usar CreateProcessAsUser para crear un proceso en la sesión del usuario y coordinarse mediante IPC para mostrarle información. ↩ ↩2 ↩3
-
Microsoft Learn, NotifyIcon Class / NotifyIcon.Visible Property. Sobre que es el componente que muestra un icono en el área de notificación, que es necesario establecer la propiedad Icon, y que el valor predeterminado de Visible es false. ↩ ↩2 ↩3
-
Microsoft Learn, NotifyIcon.Text Property. Sobre el límite del texto de la información sobre herramientas y que se produce una ArgumentException al superarlo. ↩ ↩2
-
Microsoft Learn, Windows Forms Controls and Equivalent WPF Controls. Sobre que WPF no dispone de ningún control equivalente a NotifyIcon. ↩ ↩2
-
Microsoft Learn, MSBuild properties for .NET desktop projects. Sobre la posibilidad de habilitar conjuntamente UseWPF y UseWindowsForms. ↩ ↩2
-
Microsoft Learn, Form.FormClosing Event. Sobre que se produce antes de que el formulario se cierre y que la propiedad Cancel permite anular el cierre. ↩ ↩2
-
Microsoft Learn, Windows notifications overview. Tabla de correspondencia de la API de notificaciones recomendada según el tipo de aplicación. Sobre la recomendación de Windows App SDK para WinForms/WPF/Win32 no empaquetado, y la posición de Windows.UI.Notifications como solo mantenimiento. ↩ ↩2
-
Microsoft Learn, Windows Community Toolkit — Notifications (archive). Sobre que el componente Notifications fue archivado y sustituido por las notificaciones de aplicación de Windows App SDK. ↩
-
Microsoft Learn, Use the Windows App SDK in an existing project. Sobre que la API de notificaciones de aplicación de Windows App SDK admite tanto aplicaciones empaquetadas como no empaquetadas, y que no necesita identidad de paquete. ↩ ↩2
-
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 la declaración en el manifiesto para aplicaciones empaquetadas. ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, App notifications overview. Sobre que el envío de notificaciones desde una aplicación elevada a administrador no es compatible. ↩ ↩2
-
Microsoft Learn, Notifications don’t appear or aren’t displayed. Sobre la supresión de notificaciones por el modo no molestar (Quiet Hours / Focus Assist), la activación automática durante la hora siguiente a una actualización del sistema operativo, y los pasos de comprobación cuando no se muestran las notificaciones. ↩ ↩2
-
Microsoft Learn, Focus assist. Sobre que el modo de concentración es un mecanismo que suprime la visualización del banner de la notificación y la envía directamente al centro de notificaciones. ↩ ↩2
-
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. ↩
-
Microsoft Learn, FormClosingEventArgs Class. Sobre que CloseReason permite determinar el motivo por el que se cierra el formulario. ↩
-
Microsoft Learn, How to close a window or dialog box (WPF). Sobre el patrón de ocultación del evento Closing de WPF, estableciendo e.Cancel = true y llamando a Hide(). ↩
-
Microsoft Learn, The Taskbar. Sobre que el mensaje TaskbarCreated se difunde al crearse la barra de tareas y que, al recibirlo, se debe reregistrar el icono de bandeja. ↩
-
Microsoft Learn, Shell_NotifyIconW function. Sobre que la notificación de globo se muestra como un toast (banner) y permanece en el centro de notificaciones en Windows 10, que en Windows 11 se convierte en una visualización temporal que no permanece en el centro de notificaciones, y que el tiempo de visualización sigue la configuración de accesibilidad. ↩ ↩2 ↩3
-
Microsoft Learn, Send a local toast notification from a C# app (Win32/API clásica). Sobre que, al usar el ToastNotificationManager puro, es obligatorio registrar en el menú Inicio un acceso directo con AUMID. ↩
-
Microsoft Learn, Windows App SDK deployment guide for framework-dependent apps packaged with external location or unpackaged. Sobre que el desarrollador de una aplicación no empaquetada es responsable de distribuir el runtime de Windows App SDK a los usuarios, que se necesitan los paquetes redistribuibles de Visual C++, que existen los dos métodos de instalador y de colocación directa del paquete MSIX, que el instalador está separado por arquitectura (x86, x64, Arm64) y solo debe colocarse el paquete de esa arquitectura, las opciones
--quiety--force, que si se ejecuta elevado y con privilegios de administrador se instala para todo el sistema y en caso contrario solo para el usuario que lo ejecutó, el significado de los valores de retorno0x0,0x80073d06y0x80070005, y la posibilidad de encadenarlo mediante ShellExecute desde la propia instalación. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 -
Microsoft Learn, AppNotificationManager.Register Method. Sobre que antes de que la aplicación termine se debe llamar a Unregister para liberar los recursos y garantizar que los futuros inicios por notificación funcionen correctamente, y que si la función de notificaciones no se va a usar más, se debe eliminar también la información de registro con UnregisterAll. ↩
-
Microsoft Learn, AppNotificationManager.UpdateAsync Method / Windows App SDK deployment architecture. Sobre que la clase AppNotificationManager depende del paquete Singleton de Windows App SDK, y que existen consideraciones específicas al invocarla desde una aplicación con distribución self-contained. ↩
-
Microsoft Learn, App notification progress bar and data binding. Sobre el enlace de datos mediante los métodos Bind, la actualización con AppNotificationProgressData y UpdateAsync, las diferencias entre actualizar y reemplazar (posición en el centro de notificaciones, alcance de los cambios permitidos, reaparición de la ventana emergente, comportamiento tras el cierre por parte del usuario), y la recomendación de considerar el reemplazo al finalizar. ↩ ↩2
-
Microsoft Learn, AppNotificationProgressData(UInt32) Constructor. Sobre que el número de secuencia es un entero distinto de cero que especifica el orden de las actualizaciones, y que al recibir varios datos de actualización se muestran los del número más alto. ↩
-
Microsoft Learn, Remove app notifications. Sobre la asignación de etiqueta y grupo, la eliminación de notificaciones ya mostradas, y la configuración de la fecha de caducidad. ↩
-
Microsoft Learn, App notification content. Sobre que una notificación importante con scenario=”urgent” tiene prioridad sobre la configuración de no molestar, con el permiso del usuario. ↩
Artículos relacionados
Artículos recientes con las mismas etiquetas para profundizar en temas cercanos.
Práctica de CI/CD para aplicaciones WinForms / WPF — automatizar desde la compilación hasta la firma y la distribución con GitHub Actions
CI/CD para WinForms/WPF con GitHub Actions: build y pruebas, versión por tags, firma con signtool y tabla de decisión por formato de dist...
Integrar la autenticación de Entra ID en aplicaciones WinForms/WPF — Configuración práctica con MSAL.NET y el bróker WAM
Cómo integrar Entra ID en apps WinForms/WPF: cliente público, registro de la app, AcquireTokenSilent, bróker WAM y persistencia de la cac...
Cuando su aplicación Windows de desarrollo propio es tratada como virus — cómo abordar los falsos positivos de Microsoft Defender y su impacto en el rendimiento
Procedimiento oficial para resolver falsos positivos de Microsoft Defender en apps Windows propias: por qué ocurren, cómo reportarlos, re...
¿Las aplicaciones empresariales funcionan en Windows para Arm? — La realidad de la emulación x64 (Prism), las DLL nativas y COM
Respondemos si las aplicaciones empresariales funcionan en Windows para Arm: la emulación x64 (Prism), las capas que no funcionan (contro...
¿Hasta cuándo seguirán funcionando las aplicaciones VB6? — Estado del soporte del runtime y un camino práctico hacia la migración a .NET
¿Hasta cuándo seguirán funcionando las aplicaciones VB6? Este artículo organiza la situación actual: el runtime sigue dentro del soporte ...
Temas relacionados
Estas páginas sitúan el tema en un contexto más amplio de servicios y decisiones.
Temas técnicos de Windows
Portal sobre desarrollo de Windows, investigación de fallos y aprovechamiento de activos existentes.
Hilo de UI y temporizadores
Hilo de UI de WPF / WinForms, flujos asíncronos, Dispatcher y diseño de temporizadores.
Servicios relacionados con este tema
El artículo está directamente relacionado con los siguientes servicios.
Desarrollo de aplicaciones para Windows
Aplicaciones empresariales, integración de dispositivos y herramientas de comunicación, de los requisitos al desarrollo.
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.