Icônes de la zone de notification et notifications toast dans les applications Windows — les pièges de NotifyIcon et comment choisir la bonne AppNotification
· Go Komura · Zone de notification, NotifyIcon, Notifications toast, AppNotification, Windows App SDK, WinForms, WPF, C#, .NET, Application résidente, Développement Windows, Conseil technique
« Je veux discrètement informer l’utilisateur quand un traitement se termine. » « Je veux que la surveillance continue même après la fermeture de la fenêtre. » Voici deux exigences classiques qui apparaissent souvent ensemble dans les applications métier : rester résident dans la zone de notification (system tray) et envoyer des notifications toast. Mais dès qu’on les implémente réellement, de petits problèmes surgissent les uns après les autres : une application censée se fermer refuse réellement de quitter, l’icône disparaît après un redémarrage de l’Explorateur, ou un toast qui fonctionnait parfaitement pendant le développement n’apparaît jamais chez le client.
De plus, les notifications toast constituent un domaine où l’API n’a cessé de changer de génération depuis l’époque UWP. Il n’est pas rare de rechercher en ligne et de tomber sur du code d’exemple qui, selon les standards actuels, utilise une API désormais en maintenance uniquement, au mieux. Cet article organise à la fois la conception de la résidence dans la zone de notification avec NotifyIcon et le choix d’une API de notification toast à partir de 2026, ainsi que les pièges pratiques que vous êtes susceptible de rencontrer.
1. L’essentiel d’abord
- La base de la résidence dans la zone de notification reste
System.Windows.Forms.NotifyIcon. L’icône n’apparaît que si vous définissezIconet réglezVisible = true(la valeur par défaut estfalse). Le texte de l’infobulleTextpeut aller jusqu’à 127 caractères à partir de .NET 6 (63 caractères avant cela).12 - WPF ne dispose d’aucun contrôle équivalent à NotifyIcon. Le tableau de comparaison officiel indique explicitement « Aucun contrôle équivalent ». Activer à la fois
UseWPFetUseWindowsFormsdans le csproj et utiliser le NotifyIcon de WinForms constitue la configuration minimale.34 - « Garder l’application dans la zone de notification même lorsque l’utilisateur clique sur le bouton de fermeture » s’implémente en réglant
e.Cancel = truedansFormClosinget en appelantHide(). Fournissez toujours un moyen de quitter explicite et distinct (un élément « Quitter » dans le menu de la zone de notification), et vérifiezCloseReasonpour ne jamais bloquer un arrêt du système d’exploitation.5 - L’API de toast recommandée est claire à partir de 2026. Que vous construisiez une application WinForms, WPF ou non empaquetée, l’
AppNotificationManagerdu Windows App SDK (NuGet : Microsoft.WindowsAppSDK) est recommandé.Windows.UI.Notificationsest « en maintenance uniquement », et le composant de notifications du Community Toolkit est archivé.67 - L’AppNotification du Windows App SDK fonctionne même depuis un simple exe sans identité de package.
AppNotificationManager.Default.Register()gère automatiquement l’enregistrement du serveur COM et le travail équivalent à un AUMID, si bien que vous n’avez plus besoin de configurer un raccourci dans le menu Démarrer comme l’exigeaient les générations précédentes. Cela dit, les notifications provenant de processus élevés (administrateur) ne sont pas prises en charge.8910 - Un toast n’est pas un moyen garanti d’atteindre l’utilisateur. Tant que l’assistance de concentration (ne pas déranger) est active, la bannière ne s’affiche pas et la notification va directement dans le centre de notifications, et l’utilisateur peut aussi désactiver totalement les notifications dans les paramètres. Votre conception ne doit pas supposer que « le toast s’est affiché » comme condition préalable à un flux métier.1112
- Un service Windows ne peut pas envoyer de toast (la Session 0 n’a pas d’interface utilisateur). L’approche standard consiste à placer un agent résident dans la zone de notification au sein de la session de l’utilisateur et à coordonner via IPC.13
2. Les bases de la résidence dans la zone de notification avec NotifyIcon
System.Windows.Forms.NotifyIcon est le composant qui place une icône dans la zone de notification, à l’extrémité droite de la barre des tâches. Les applications qui continuent de s’exécuter en arrière-plan l’utilisent comme point d’entrée pour l’affichage de l’état et un menu d’actions.1
private NotifyIcon _trayIcon = null!;
private void InitializeTrayIcon()
{
var menu = new ContextMenuStrip();
menu.Items.Add("Ouvrir", null, (_, _) => ShowMainWindow());
menu.Items.Add(new ToolStripSeparator());
menu.Items.Add("Quitter", null, (_, _) => ExitApplication());
_trayIcon = new NotifyIcon
{
Icon = Properties.Resources.AppIcon, // L'icône est obligatoire ; sans elle, rien ne s'affiche
Text = "Outil de surveillance des commandes ── en cours d'exécution", // Infobulle (127 caractères max sur .NET 6+)
ContextMenuStrip = menu,
Visible = true // Valeur par défaut : false ; ne s'affiche qu'une fois passé à true
};
_trayIcon.DoubleClick += (_, _) => ShowMainWindow();
}
Trois points méritent d’être retenus.
- L’icône n’apparaît qu’une fois
IconetVisible = trueréunis. La valeur par défaut deVisibleestfalse.1 Texta une limite de longueur. Elle est de 127 caractères maximum à partir de .NET 6, et de 63 caractères pour .NET 5 et antérieur ainsi que pour .NET Framework ; la dépasser lève uneArgumentException. Entasser trop d’informations d’état dans l’infobulle est un bon moyen de voir votre application planter soudainement avec une exception à un moment donné.214- Associez un menu au clic droit via
ContextMenuStrip. L’icône de la zone de notification est souvent le seul point d’entrée visible pour l’utilisateur, prévoyez donc au minimum un élément « Ouvrir » et un élément « Quitter ».15
Autre point important : l’icône de la zone de notification n’est pas seulement un point d’entrée pour les notifications, c’est aussi un indicateur d’état toujours visible. Puisque Icon et Text peuvent être remplacés pendant que l’application s’exécute, refléter l’état courant — une icône normale quand tout va bien, une icône d’avertissement en cas de problème, afficher l’heure du dernier traitement dans l’infobulle — permet à l’utilisateur de connaître l’état actuel d’un simple coup d’œil, même s’il a manqué un toast. Le toast est le canal pour « quelque chose vient de se produire à cet instant », tandis que l’icône de la zone de notification est le canal pour « voici l’état actuel » — c’est cette répartition des rôles.
3. Concevoir « rester dans la zone de notification à la fermeture » et un chemin de sortie correct
Un comportement classique des applications résidentes est le suivant : cliquer sur le bouton de fermeture ne termine pas le processus, il reste simplement dans la zone de notification. L’implémentation elle-même est facile à écrire en annulant FormClosing, mais l’écrire sans précaution mène à deux types de problèmes : il n’existe plus aucun moyen de quitter l’application, et cela bloque l’arrêt de Windows.
private bool _exitRequested;
protected override void OnFormClosing(FormClosingEventArgs e)
{
// Si l'utilisateur a simplement cliqué sur la croix, masquer au lieu de fermer
if (!_exitRequested && e.CloseReason == CloseReason.UserClosing)
{
e.Cancel = true;
Hide();
return;
}
// Fermeture normale via le menu « Quitter », l'arrêt du système, etc.
base.OnFormClosing(e);
}
private void ExitApplication()
{
_exitRequested = true;
_trayIcon.Visible = false;
_trayIcon.Dispose();
Close();
}
FormClosing se déclenche avant la fermeture du formulaire, et régler e.Cancel = true annule la fermeture. À ce moment-là, vérifiez toujours CloseReason. Le comportement correct consiste à n’annuler que pour UserClosing (une action de l’utilisateur), et à ne jamais annuler pour une fermeture déclenchée par le système d’exploitation comme WindowsShutDown.516
WPF suit la même logique : la documentation officielle elle-même décrit le schéma consistant à régler e.Cancel = true dans Window.Closing et à appeler Hide().17
Notez que, par nature, une application résidente est toujours exposée au risque suivant : « si elle est lancée deux fois, le même événement est traité deux fois ». Nous avons traité la prévention des lancements multiples dans « Empêcher les lancements multiples d’une application Windows — mutex nommés et activation de l’instance en cours lors d’un second lancement ». Et « Pourquoi utiliser .NET Generic Host et BackgroundService dans une application de bureau » constitue la base pour construire le contenu réel d’une application résidente — la boucle de surveillance ou le traitement périodique.
4. La résidence dans la zone de notification dans une application WPF
WPF ne dispose d’aucun contrôle équivalent à NotifyIcon. Il s’agit d’une lacune documentée de la plateforme, indiquée explicitement par « No equivalent control » dans le tableau de comparaison officiel « contrôles WPF équivalents aux contrôles WinForms ».3
Il existe deux options réalistes.
| Option | Aperçu | Recommandation |
|---|---|---|
| Utiliser le NotifyIcon de WinForms avec WPF | Activer à la fois UseWPF et UseWindowsForms dans le csproj |
Aucune dépendance supplémentaire. Suffisant si vous n’avez besoin que d’une icône et d’un menu |
| Bibliothèque tierce (par exemple H.NotifyIcon) | Implémentations d’icônes de zone de notification conçues pour WPF/WinUI | À choisir si vous voulez écrire en XAML ou avez besoin d’un popup plus riche. Gardez à l’esprit qu’il ne s’agit pas d’un composant officiel Microsoft |
La première option consiste simplement à lister deux propriétés côte à côte dans un fichier projet de style SDK.4
<PropertyGroup>
<TargetFramework>net8.0-windows</TargetFramework>
<UseWPF>true</UseWPF>
<UseWindowsForms>true</UseWindowsForms>
</PropertyGroup>
Vous pouvez ensuite simplement instancier un System.Windows.Forms.NotifyIcon directement depuis une Application WPF. Seul le menu se retrouve en WinForms (ContextMenuStrip), mais pour quelque chose d’aussi simple qu’un menu de zone de notification, cela pose rarement un problème pratique.
5. Trois pièges des icônes de la zone de notification
5.1. Les icônes vont par défaut dans les « icônes masquées » — impossible de forcer leur affichage
La demande de garder l’icône de votre application en permanence visible dans la barre des tâches revient toujours, mais cela ne peut pas être réalisé par programmation. La documentation officielle indique clairement que les icônes sont ajoutées par défaut à la zone de débordement (icônes masquées), et que seul l’utilisateur peut décider de promouvoir une icône pour un affichage permanent dans la zone de notification.18
Sur Windows 11, l’utilisateur active ou désactive cela application par application via « Paramètres → Personnalisation → Barre des tâches → Autres icônes de zone de notification ». Si l’affichage permanent est important sur le plan opérationnel, la bonne solution consiste à le documenter dans votre guide d’installation ou votre aide (« veuillez activer ce paramètre »), et non à essayer de le forcer dans le code.
5.2. L’icône disparaît quand l’Explorateur redémarre — TaskbarCreated
Lorsque l’Explorateur plante ou redémarre et reconstruit la barre des tâches, toutes les icônes de zone de notification enregistrées disparaissent. Le shell diffuse un message TaskbarCreated à toutes les fenêtres de premier niveau lors de la création de la barre des tâches, et la convention au niveau Win32 est de réenregistrer votre icône dès réception de ce message.19
Le NotifyIcon de WinForms gère ce message en interne et se réenregistre automatiquement, vous n’avez donc normalement pas besoin d’y penser. Si vous appelez Shell_NotifyIcon vous-même via P/Invoke (ou si vous maintenez une application native disposant d’une icône de zone de notification), assurez-vous que cette logique de réenregistrement est en place. Le symptôme « l’icône disparaît seule quand l’Explorateur redémarre, mais le processus est toujours vivant » correspond presque toujours exactement à ce problème.
5.3. Oublier Dispose laisse une icône fantôme
Au niveau Win32, une icône de zone de notification doit être explicitement supprimée (NIM_DELETE) dès qu’elle n’est plus nécessaire, et dans WinForms, cette responsabilité incombe à NotifyIcon.Dispose().18 Assurez-vous que votre chemin de sortie passe toujours par Visible = false puis Dispose(). Tout développeur d’application résidente a déjà vu cette scène au moins une fois : le processus se termine anormalement sans nettoyage, et une icône fantôme reste bloquée dans la zone de notification jusqu’à ce que l’utilisateur y passe le curseur de la souris.
Comme dans le code du chapitre 3, il est plus sûr de nettoyer l’icône de la zone de notification dans le gestionnaire du menu « Quitter », avant d’appeler Close().
6. Notifications toast — quelle API utiliser
Une notification toast est la bannière qui apparaît dans le coin inférieur droit de l’écran, puis qui reste dans le centre de notifications. La façon d’en envoyer une depuis une application de bureau n’a cessé de changer au cours de la dernière décennie, et les résultats de recherche restent pleins d’anciens exemples. Voici où en sont les choses à partir de 2026.6
| API | NuGet / Espace de noms | Statut (à partir de 2026) | Verdict |
|---|---|---|---|
| Windows App SDK AppNotification | Microsoft.WindowsAppSDK / Microsoft.Windows.AppNotifications |
Officiellement recommandée pour WinForms, WPF et Win32 non empaqueté | À utiliser pour tout nouveau développement |
| Community Toolkit Notifications | Microsoft.Toolkit.Uwp.Notifications | Archivé. Ne fait plus partie du Community Toolkit actuel ; dernière mise à jour en 2022 | Uniquement pour maintenir du code existant. Ne pas adopter pour un nouveau projet |
| Utilisation directe de WinRT | Windows.UI.Notifications (via le TFM Windows) |
Maintenance uniquement. Recommandé principalement pour UWP | Ne pas adopter pour un nouveau projet |
| NotifyIcon.ShowBalloonTip | System.Windows.Forms |
API de notification en bulle. Rendue comme un toast sur Windows 10 ; sur Windows 11, il s’agit d’un affichage temporaire qui ne persiste pas dans le centre de notifications | Convient pour des cas simples, mais notez que son comportement change selon la version de l’OS |
Deux remarques supplémentaires.
ShowBalloonTipfait partie de ces cas « ancienne API, mais en réalité toujours bien vivante ». Sur Windows 10, les bulles s’affichent comme un toast et restent dans le centre de notifications jusqu’à leur fermeture. Sur Windows 11, en revanche, elles se comportent davantage comme une bulle temporaire traditionnelle et ne persistent pas dans le centre de notifications une fois disparues. La durée d’affichage (timeout) est désormais elle aussi ignorée, et suit à la place les paramètres d’accessibilité du système. Cela suffit amplement pour une application résidente dans la zone de notification qui veut simplement signaler légèrement un changement d’état, mais si vous voulez qu’un historique persiste dans le centre de notifications, gardez à l’esprit que cela ne vous aidera pas sur Windows 11.20- L’approche classique consistant à utiliser
Windows.UI.Notificationsbrut depuis une application de bureau comporte une contrainte bien connue : le toast ne s’affiche pas tant que vous n’avez pas enregistré un raccourci avec un AUMID (AppUserModelID) dans le menu Démarrer.21 L’AppNotification traitée au chapitre suivant est justement ce qui élimine cette contrainte.
7. Une implémentation minimale d’AppNotification du Windows App SDK
L’API de notifications d’application du Windows App SDK fonctionne même depuis un exe simple et non empaqueté, sans identité de package.8 Les prérequis côté projet sont un TFM spécifique à Windows (par exemple net8.0-windows10.0.19041.0), <WindowsPackageType>None</WindowsPackageType> (pour le cas non empaqueté), et le fait d’avoir le runtime du Windows App SDK installé sur la cible de déploiement.9
using Microsoft.Windows.AppNotifications;
using Microsoft.Windows.AppNotifications.Builder;
// Une seule fois au démarrage ; l'ordre enregistrement du gestionnaire → Register() est important
AppNotificationManager.Default.NotificationInvoked += (_, args) =>
{
// Les clics sur le toast et les appuis sur les boutons arrivent ici (à distinguer via args.Arguments)
if (args.Arguments.TryGetValue("action", out var action) && action == "openLog")
{
ShowLogWindow();
}
};
AppNotificationManager.Default.Register();
// Afficher la notification
var notification = new AppNotificationBuilder()
.AddText("Importation des commandes terminée")
.AddText("12 nouvelles, 1 erreur")
.AddButton(new AppNotificationButton("Ouvrir le journal")
.AddArgument("action", "openLog"))
.BuildNotification();
AppNotificationManager.Default.Show(notification);
Les points pratiques à surveiller :
- Abonnez-vous à
NotificationInvokedavant d’appelerRegister(). Inversez cet ordre et vous manquerez l’événement lorsqu’un clic sur le toast lance l’application.9 - Appelez
AppNotificationManager.Default.Unregister()avant que l’application ne se ferme. La documentation officielle indique explicitement qu’appeler Unregister avant la fermeture nettoie les ressources et garantit que l’application se lance correctement la prochaine fois qu’une notification est cliquée. Intégrez cela dans le gestionnaire du menu « Quitter » du chapitre 3, aux côtés deNotifyIcon.Dispose()(il existe aussi unUnregisterAll()distinct pour des cas comme la désinstallation d’une application qui n’utilisera plus jamais les notifications, lequel efface entièrement les informations d’enregistrement).22 - Pour les applications non empaquetées,
Register()gère automatiquement l’enregistrement du serveur COM et le travail équivalent à un AUMID. Vous n’avez plus besoin de la configuration de raccourci ni de l’enregistrement dans le registre qu’exigeait l’ancienne génération, celle du WinRT brut. Si vous empaquetez avec MSIX à la place, vous devrez déclarer l’activateur COM dans Package.appxmanifest.9 - Soyez prudent si vous choisissez un déploiement autonome (self-contained) qui embarque le runtime du Windows App SDK.
AppNotificationManagerdépend du package Singleton du Windows App SDK, et des considérations officiellement documentées existent pour l’appeler depuis une application autonome. Vérifiez ce point avant d’arrêter votre méthode de distribution.23 - Les notifications provenant de processus élevés (administrateur) ne sont pas prises en charge.
Showne lève pas d’exception, elle échoue simplement en silence, ce qui rend la cause racine difficile à repérer. Pour les applications nécessitant une élévation, envisagez d’isoler uniquement la notification dans un processus non élevé (cette approche d’isolation est traitée dans « Une manière concrète d’isoler uniquement les parties d’une application Windows nécessitant des privilèges administrateur »).10 - Lorsqu’un toast est cliqué, si l’application n’est pas en cours d’exécution, un nouveau processus sera lancé. Dans une application résidente dans la zone de notification, vous devez combiner cela avec la prévention des instances multiples (chapitre 3) afin que le travail soit transmis à l’instance existante.
8. Usage avancé — toasts avec barre de progression et nettoyage des notifications
8.1. Mettre à jour la progression à l’intérieur d’un toast — UpdateAsync
Pour un traitement long comme « import de 120 enregistrements de commande », la bonne approche n’est pas de redéclencher une nouvelle notification encore et encore, mais de mettre à jour la barre de progression à l’intérieur d’un seul toast. AppNotification dispose d’un mécanisme de liaison de données et de mise à jour construit précisément pour cela.24
La construction se fait en trois étapes. D’abord, transformez chaque valeur de la barre de progression en espace réservé à l’aide des méthodes Bind, donnez au toast une identité via Tag (et Group, si nécessaire), puis affichez-le. Ensuite, il vous suffit de passer un AppNotificationProgressData à UpdateAsync, et seul le contenu du toast déjà affiché est réécrit.
const string tag = "import-progress";
const string group = "batch";
// Premier affichage : lier la valeur et définir la valeur initiale sur Progress
var notification = new AppNotificationBuilder()
.AddText("Importation des données de commande en cours")
.AddProgressBar(new AppNotificationProgressBar()
.BindStatus().BindValue().BindValueStringOverride())
.SetTag(tag)
.SetGroup(group)
.BuildNotification();
notification.Progress = new AppNotificationProgressData(1) // numéro de séquence
{
Status = "Importation en cours...", Value = 0, ValueStringOverride = "0/120 éléments"
};
AppNotificationManager.Default.Show(notification);
// À chaque progression : incrémenter le numéro de séquence et mettre à jour
var data = new AppNotificationProgressData(2)
{
Status = "Importation en cours...", Value = 45 / 120.0, ValueStringOverride = "45/120 éléments"
};
await AppNotificationManager.Default.UpdateAsync(data, tag, group);
Le numéro de séquence est un entier non nul indiquant l’ordre de mise à jour ; si plusieurs mises à jour arrivent dans le désordre, celle ayant le numéro le plus élevé l’emporte. Ce mécanisme existe pour que des mises à jour concurrentes envoyées depuis un traitement asynchrone ne reviennent pas en arrière vers une valeur périmée, veillez donc à ce qu’il augmente toujours de façon monotone.25
8.2. « Mise à jour » contre « remplacement » — quand utiliser l’un ou l’autre
Vous pouvez aussi mettre à jour l’apparence en réaffichant (Show) une nouvelle notification avec le même Tag — un « remplacement » — mais le comportement diffère de celui d’une « mise à jour ».24
| Remplacement (nouveau Show avec le même Tag) | Mise à jour (UpdateAsync) | |
|---|---|---|
| Position dans le centre de notifications | Se déplace en haut | Reste en place |
| Ce qui peut être modifié | Tout, y compris la mise en page | Uniquement la barre de progression liée et le texte principal |
| Popup | Peut réapparaître | Ne réapparaît pas (réécriture silencieuse) |
| Si l’utilisateur l’avait déjà fermée | Toujours délivrée | Échoue |
La recommandation officielle est claire ici aussi : mise à jour pour la progression intermédiaire, remplacement à l’achèvement. Il n’est pas nécessaire de faire apparaître une notification chaque fois que la progression passe de 50 % à 65 %, mais « import terminé (3 erreurs) » devrait atteindre l’utilisateur même s’il a déjà fermé la notification de progression. En pratique, le schéma courant consiste à retirer la barre de progression à l’achèvement et à la remplacer par une autre mise en page dotée de boutons, comme « Voir les détails de l’erreur ».
8.3. Nettoyer les anciennes notifications laissées dans le centre de notifications
Les toasts s’accumulent dans le centre de notifications jusqu’à ce que l’utilisateur les efface. Si une application résidente envoie plusieurs notifications chaque jour, le centre de notifications finit rempli des anciennes notifications de votre application, ce qui peut finir par enterrer les notifications importantes.
Attacher un Tag / Group vous permet de supprimer par le code les notifications de votre propre application (par tag, par groupe, ou toutes). Vous pouvez aussi définir une expiration. Il vaut la peine de décider vos règles de nettoyage — « effacer les notifications de type progression à l’achèvement », « raccourcir l’expiration des notifications informatives » — en même temps que vous concevez la façon dont les notifications sont envoyées.26
9. Concevoir pour les cas où une notification « n’arrive pas »
Une notification toast n’est pas un mécanisme de livraison garanti. Il existe des chemins parfaitement normaux où elle n’est pas affichée ou n’est pas remarquée.
| Cas | Comportement |
|---|---|
| L’assistance de concentration (ne pas déranger) est activée | La bannière ne s’affiche pas ; la notification va directement dans le centre de notifications |
| Notifications désactivées, par application ou pour tout le système | Rien n’est affiché |
| AppNotification depuis un processus élevé | Non prise en charge. Rien n’est affiché |
| Une application plein écran est en cours d’exécution, etc. | L’OS peut la supprimer à sa propre discrétion |
Le mode Ne pas déranger s’appelle « Assistant de concentration » sur Windows 10 et est contrôlé via le bouton « Ne pas déranger » sous « Paramètres → Système → Notifications » sur Windows 11 ; il peut être régi par l’utilisateur ou par une stratégie de groupe. Il existe même une règle selon laquelle il est automatiquement activé pendant la première heure suivant une mise à niveau de l’OS.11 L’assistance de concentration ne signifie pas « ne pas envoyer de notifications », mais « supprimer la bannière et l’acheminer directement vers le centre de notifications » — l’utilisateur la verra donc toujours s’il ouvre ensuite le centre de notifications.12
L’implication pour la conception est simple :
- Traitez le toast comme un canal complémentaire qui aide les utilisateurs à réagir plus vite s’ils le remarquent, et assurez-vous que les informations obligatoires pour le processus métier puissent toujours être confirmées dans un écran ou une liste au sein de l’application. Ne construisez pas un flux qui suppose que « le toast s’est probablement affiché ».
- Pour les notifications qui doivent absolument interrompre l’utilisateur (comme une alerte d’arrêt d’urgence), il existe un mécanisme pour outrepasser le mode Ne pas déranger avec le consentement de l’utilisateur via
AppNotificationScenario.Urgent,27 mais un usage abusif conduira les utilisateurs à désactiver complètement les notifications de votre application. Réservez-le aux cas véritablement urgents uniquement.
Pour la question plus large de savoir comment afficher à l’écran des éléments comme les erreurs de périphériques externes, voir aussi « Bonnes pratiques pour vérifier et afficher l’état des périphériques externes ».
10. Quand vous devez notifier depuis un service Windows
C’est une exigence naturelle : « quand un service résident détecte un problème, je veux avertir l’utilisateur connecté par un toast » — mais un service ne peut pas envoyer de toast directement. Depuis Windows Vista, les services s’exécutent dans une session dédiée appelée Session 0 et n’ont aucune capacité à afficher une interface utilisateur qui interagit avec un utilisateur.13
L’approche standard consiste à séparer l’interface utilisateur dans un processus s’exécutant dans la session de l’utilisateur.
[Session 0] [Session utilisateur]
Service Windows <-- IPC --> Agent résident dans la zone de notification
(surveillance/logique métier) tubes nommés, etc. (NotifyIcon + AppNotification)
- Le service se concentre uniquement sur la surveillance et la logique métier, et envoie à l’agent tout ce qu’il doit notifier, via IPC.
- L’agent est une application résidente dans la zone de notification (exactement ce que décrivent les chapitres 2 à 8 de cet article) qui se lance à la connexion de l’utilisateur, et affiche les événements reçus sous forme de toasts ou de changements d’icône.
- Le choix d’un mécanisme d’IPC a été traité dans « Comment choisir la communication inter-processus sous Windows », la construction du côté service dans « Comment créer et exploiter un service Windows », et le mécanisme de session lui-même dans « Comment comprendre l’isolation des sessions Windows — Session 0, RDP et exécution simultanée de plusieurs utilisateurs ».
Dans les environnements où plusieurs utilisateurs sont connectés simultanément (RDP, terminaux partagés), l’agent finit par s’exécuter une fois par session. Décider en amont, comme exigence, « qui doit être notifié » (tout le monde, ou seulement un utilisateur spécifique) évite que la conception ne parte dans tous les sens plus tard.
11. Résumé
- La résidence dans la zone de notification repose sur
NotifyIcon. Affichez-la viaIcon+Visible = true, respectez la limite de 127 caractères pourText(.NET 6+), et assurez-vous queDispose()est bien appelé dans le chemin de sortie. Utilisez aussi l’icône et l’infobulle comme un indicateur toujours visible de l’état courant. - « Rester dans la zone de notification même fermé avec le bouton × » s’implémente en annulant
FormClosing, mais n’annulez que pourCloseReason.UserClosinget fournissez toujours un menu « Quitter » explicite. - Seul l’utilisateur peut décider si une icône est toujours visible. Gérez la disparition de l’icône lors des redémarrages de l’Explorateur en la réenregistrant sur
TaskbarCreated(WinForms le fait automatiquement). - Pour tout nouveau développement de notifications toast, l’
AppNotificationManagerdu Windows App SDK est le seul vrai choix. Il fonctionne même depuis un exe non empaqueté sans identité de package, etRegister()automatise le travail d’enregistrement fastidieux. Les notifications du Community Toolkit sont archivées, et le WinRT brut est en maintenance uniquement. - Pour la progression intermédiaire d’un traitement long, réécrivez silencieusement la barre de progression à l’intérieur d’un seul toast avec
UpdateAsync, et utilisez un remplacement pour faire apparaître une notification à l’achèvement — c’est le schéma standard. Attachez unTag/Group, et incluez le nettoyage des anciennes notifications dans votre conception. - Un toast est un canal complémentaire qui peut échouer à arriver en raison du mode Ne pas déranger ou de notifications désactivées. Concevez de sorte que les informations obligatoires puissent toujours être confirmées dans l’application, et gardez à l’esprit que les notifications depuis des processus élevés ne sont pas prises en charge.
- Les notifications depuis un service se réalisent via l’architecture séparée d’un agent résident dans la zone de notification côté session utilisateur, combinée à de l’IPC.
Articles connexes
- Empêcher les lancements multiples d’une application Windows — mutex nommés et activation de l’instance en cours lors d’un second lancement
- Comment créer et exploiter un service Windows — du choix entre service et Planificateur de tâches à la transformation d’un BackgroundService en service
- Comment choisir la communication inter-processus sous Windows — tableau de décision tubes nommés / TCP / gRPC / mémoire partagée / COM
- Comment comprendre l’isolation des sessions Windows — Session 0, RDP et exécution simultanée de plusieurs utilisateurs
- Pourquoi utiliser .NET Generic Host et BackgroundService dans une application de bureau
- Une manière concrète d’isoler uniquement les parties d’une application Windows nécessitant des privilèges administrateur
- Bonnes pratiques pour vérifier et afficher l’état des périphériques externes — une conception qui ne s’arrête pas à « Connecté »
Domaines de conseil associés
KomuraSoft LLC (合同会社小村ソフト) prend en charge la conception et l’implémentation d’outils de surveillance et d’agents de notification résidents dans la zone de notification, la revue d’architecture de systèmes résidents combinés à des services Windows, et le dépannage d’applications résidentes existantes.
Références
-
Microsoft Learn, NotifyIcon Class / NotifyIcon.Visible Property. Au sujet du fait que NotifyIcon est le composant qui affiche une icône dans la zone de notification, de la nécessité de définir la propriété Icon, et du fait que Visible vaut false par défaut. ↩ ↩2 ↩3
-
Microsoft Learn, NotifyIcon.Text Property. Au sujet de la limite du texte de l’infobulle et de l’ArgumentException levée en cas de dépassement. ↩ ↩2
-
Microsoft Learn, Windows Forms Controls and Equivalent WPF Controls. Au sujet de l’absence, dans WPF, d’un contrôle équivalent à NotifyIcon. ↩ ↩2
-
Microsoft Learn, MSBuild properties for .NET desktop projects. Au sujet de la possibilité d’activer ensemble UseWPF et UseWindowsForms. ↩ ↩2
-
Microsoft Learn, Form.FormClosing Event. Au sujet du déclenchement de l’événement avant la fermeture du formulaire, et de la possibilité d’annuler la fermeture via Cancel. ↩ ↩2
-
Microsoft Learn, Windows notifications overview. Au sujet de l’API de notification recommandée selon le type d’application, y compris la recommandation du Windows App SDK pour WinForms/WPF/Win32 non empaqueté, et du statut « maintenance uniquement » de Windows.UI.Notifications. ↩ ↩2
-
Microsoft Learn, Windows Community Toolkit — Notifications (archive). Au sujet de l’archivage du composant Notifications, remplacé par les notifications d’application du Windows App SDK. ↩
-
Microsoft Learn, Use the Windows App SDK in an existing project. Au sujet du fait que l’API de notifications d’application du Windows App SDK prend en charge à la fois les applications empaquetées et non empaquetées, sans exiger d’identité de package. ↩ ↩2
-
Microsoft Learn, Quickstart: App notifications in the Windows App SDK. Au sujet de l’utilisation d’AppNotificationManager/AppNotificationBuilder, de l’enregistrement automatique via Register() pour les applications non empaquetées, de la nécessité de s’abonner à NotificationInvoked avant Register(), et des déclarations de manifeste pour les applications empaquetées. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, App notifications overview. Au sujet du fait que l’envoi de notifications depuis une application élevée n’est pas pris en charge. ↩ ↩2
-
Microsoft Learn, Notifications don’t appear or aren’t displayed. Au sujet de la suppression des notifications par le mode Ne pas déranger (Quiet Hours / Focus Assist), de l’activation automatique pendant la première heure suivant une mise à niveau de l’OS, et des étapes de vérification lorsque les notifications ne s’affichent pas. ↩ ↩2
-
Microsoft Learn, Focus assist. Au sujet du fait que l’assistance de concentration supprime l’affichage de la bannière de notification et l’achemine directement vers le centre de notifications. ↩ ↩2
-
Microsoft Learn, Service Changes for Windows Vista / Interactive Services. Au sujet du fait que la Session 0 est dédiée aux services et ne prend pas en charge l’interaction avec un utilisateur, et de la recommandation d’utiliser CreateProcessAsUser pour créer un processus dans la session de l’utilisateur et coordonner via IPC afin d’afficher quelque chose à l’utilisateur. ↩ ↩2
-
Microsoft Learn, NotifyIcon.Text maximum text length increased. Au sujet du changement cassant de .NET 6 qui a étendu la longueur maximale de Text de 63 à 127 caractères. ↩
-
Microsoft Learn, FormClosingEventArgs Class. Au sujet de la possibilité de déterminer la raison de la fermeture du formulaire via CloseReason. ↩
-
Microsoft Learn, How to close a window or dialog box (WPF). Au sujet du schéma de l’événement Closing de WPF consistant à régler e.Cancel = true et à appeler Hide() pour masquer plutôt que fermer. ↩
-
Microsoft Learn, Notification Area (Windows Shell). Au sujet du fait que les icônes sont ajoutées par défaut à la zone de débordement, que seul l’utilisateur peut promouvoir une icône vers la zone de notification, et de la nécessité de supprimer les icônes inutiles via NIM_DELETE. ↩ ↩2
-
Microsoft Learn, The Taskbar. Au sujet de la diffusion du message TaskbarCreated lors de la création de la barre des tâches, et du fait qu’il faut réenregistrer son icône de zone de notification dès réception de ce message. ↩
-
Microsoft Learn, Shell_NotifyIconW function. Au sujet du fait que les notifications en bulle s’affichent comme un toast (bannière) et persistent dans le centre de notifications sur Windows 10, qu’il s’agit d’un affichage temporaire ne persistant pas sur Windows 11, et que la durée d’affichage suit les paramètres d’accessibilité. ↩
-
Microsoft Learn, Send a local toast notification from a C# app (Win32/API classique). Au sujet de l’exigence d’enregistrer un raccourci portant un AUMID dans le menu Démarrer lors de l’utilisation du ToastNotificationManager brut. ↩
-
Microsoft Learn, AppNotificationManager.Register Method. Au sujet du fait qu’il faut appeler Unregister avant la fermeture de l’application pour nettoyer les ressources et garantir que les lancements de notification ultérieurs fonctionnent correctement, et de l’utilisation d’UnregisterAll pour effacer les informations d’enregistrement lorsque les notifications ne seront plus jamais utilisées. ↩
-
Microsoft Learn, AppNotificationManager.UpdateAsync Method / Windows App SDK deployment architecture. Au sujet du fait que la classe AppNotificationManager dépend du package Singleton du Windows App SDK, et des considérations pour l’appeler depuis une application autonome (self-contained). ↩
-
Microsoft Learn, App notification progress bar and data binding. Au sujet de la liaison de données via les méthodes Bind, de la mise à jour via AppNotificationProgressData et UpdateAsync, et des différences entre mise à jour et remplacement (position dans le centre de notifications, ce qui peut être modifié, réaffichage du popup, et comportement une fois que l’utilisateur l’a fermée), et du fait qu’un remplacement doit être envisagé à l’achèvement. ↩ ↩2
-
Microsoft Learn, AppNotificationProgressData(UInt32) Constructor. Au sujet du fait que le numéro de séquence est un entier non nul spécifiant l’ordre de mise à jour, avec les données au numéro le plus élevé affichées lorsque plusieurs mises à jour sont reçues. ↩
-
Microsoft Learn, Remove app notifications. Au sujet de l’attachement de tags/groupes, de la suppression des notifications déjà affichées, et de la définition d’une expiration. ↩
-
Microsoft Learn, App notification content. Au sujet de la priorité des notifications importantes avec scenario=”urgent” sur les paramètres Ne pas déranger, avec le consentement de l’utilisateur. ↩
Articles associés
Articles récents partageant les mêmes étiquettes, pour approfondir des sujets proches.
Internationalisation des applications WinForms/WPF : resx, assemblies satellites et changement de culture en pratique
Un guide pratique pour internationaliser une application de bureau Windows : la différence entre CurrentCulture et CurrentUICulture, le f...
Impression et sortie PDF dans les applications métier Windows — choisir entre System.Drawing.Printing, WPF et bibliothèques de rapports
Organise l'impression WinForms avec PrintDocument, l'impression WPF FlowDocument/FixedDocument et les options de sortie PDF dans une tabl...
Jusqu'à quand les applications VB6 continueront-elles de fonctionner ? — état du support du runtime et démarche concrète vers une migration .NET
Jusqu'à quand les applications VB6 continueront-elles de fonctionner ? Cet article clarifie l'asymétrie entre la politique de support du ...
Ère japonaise, jours fériés et dates de clôture dans les applications métier — conception résiliente aux changements d'ère, JapaneseCalendar et calcul des jours ouvrés en pratique
Afficher « Reiwa 8 » sur un bordereau, calculer des jours ouvrés en excluant les jours fériés, régler un paiement à la fin du mois suivan...
Au-delà de appsettings.json — guide pratique de la gestion de configuration dans les applications métier Windows (environnements, secrets et emplacements d'écriture)
Guide pratique de la configuration des applications métier Windows : superposition de appsettings.json, choix entre IConfiguration et IOp...
Sujets associés
Ces pages replacent le sujet dans un contexte plus large de services et de décisions.
Thèmes techniques Windows
Portail des sujets sur le développement Windows, l'analyse des incidents et la valorisation des actifs existants.
Thread UI et minuteries
Thread UI WPF / WinForms, flux asynchrones, Dispatcher et temporisation.
Services liés à ce sujet
Cet article est directement lié aux services suivants.
Développement d'applications Windows
Applications métier, intégration d'équipements et outils de communication, des besoins au développement.
Questions fréquentes
Questions souvent posées lors d’une consultation sur le sujet de cet article.
- Comment créer une application résidente dans la zone de notification avec WPF ?
- WPF ne dispose d'aucun contrôle équivalent à NotifyIcon ; la configuration minimale consiste donc à activer à la fois UseWPF et UseWindowsForms dans le csproj et à utiliser le NotifyIcon de WinForms. Si vous souhaitez une écriture compatible XAML, une bibliothèque tierce comme H.NotifyIcon est une option, mais gardez à l'esprit qu'il ne s'agit pas d'un composant officiel Microsoft avant de décider de l'adopter.
- Quelle API de notification toast faut-il utiliser ?
- Pour tout nouveau développement à partir de 2026, que vous construisiez une application WinForms, WPF ou non empaquetée, l'AppNotificationManager du Windows App SDK est la solution officiellement recommandée. Microsoft.Toolkit.Uwp.Notifications est archivé et ne fait plus partie du Community Toolkit actuel, tandis que le ToastNotificationManager de WinRT est désormais en maintenance uniquement. Si votre code existant fonctionne déjà avec l'un de ces deux éléments, rien ne presse de le réécrire, mais il n'y a aucune raison de les choisir pour un nouveau projet.
- Que faut-il vérifier lorsqu'une notification toast ne s'affiche pas ?
- Commencez par les paramètres du système d'exploitation. Si l'assistance de concentration (ne pas déranger) est activée, les notifications ne s'affichent pas sous forme de bannière et vont directement dans le centre de notifications ; les notifications peuvent également être désactivées par application ou pour tout le système dans l'application Paramètres. Côté implémentation, les deux causes courantes sont qu'AppNotification n'est pas prise en charge lorsqu'elle est envoyée depuis un processus élevé (administrateur), et que Windows.UI.Notifications brut n'affiche rien lorsqu'il est appelé depuis une application de bureau sans AUMID.
- Un service Windows peut-il envoyer des notifications toast ?
- Non, ce n'est pas possible. Depuis Windows Vista, les services s'exécutent dans la Session 0 et n'ont aucune capacité à afficher une interface utilisateur pour interagir avec l'utilisateur. Si vous devez notifier l'utilisateur, le schéma standard consiste à placer un processus agent résident dans la zone de notification au sein de la session utilisateur, et à le faire communiquer avec le service via un mécanisme d'IPC tel que les tubes nommés, l'agent lui-même étant responsable de l'affichage de la notification.
Profil de l’auteur
Page de présentation de l’auteur de l’article.
Go Komura
Représentant de KomuraSoft LLC
Spécialisé dans le développement de logiciels Windows, le conseil technique et l’analyse de pannes, notamment pour les systèmes existants et les incidents difficiles à reproduire.
Liens publics