← blog

21 juillet 2026 · 5 min de lecture

Backends de plateforme : Avalonia, Uno et Headless

Cette page est une traduction. En cas de divergence, la version anglaise fait foi. English

Majorsilence.Forms effectue tout son dessin lui-même avec SkiaSharp. Chaque contrôle peint dans une SKSurface/SKCanvas ; le toolkit de fenêtrage en dessous n’est qu’un hôte — il crée les fenêtres natives, fait tourner la boucle de messages, achemine les entrées et présente la surface Skia à l’écran. C’est cette séparation qui permet au même jeu de contrôles, à l’identique, de tourner aujourd’hui sur trois toolkits très différents.

La couture

Deux interfaces définissent tout ce qu’un hôte doit fournir :

IPlatformBackend couvre les services au niveau de l’application — le dispatcher (Post/Invoke), les timers, le presse-papiers, l’énumération des écrans et la boucle modale. IWindowBackend couvre une seule fenêtre native — taille et position, afficher/masquer/fermer, curseur, décorations, boîtes de dialogue de fichiers. Les entrées et les demandes de peinture circulent dans l’autre sens : le backend appelle directement les méthodes neutres RenderFrame(SKCanvas, …) et Handle* de la fenêtre. Aucun type de plateforme — aucun type Avalonia, aucun type WinUI — ne franchit jamais la frontière vers le code cœur de Majorsilence.Forms.

Trois backends aujourd’hui

Majorsilence.Forms.Avalonia est le backend par défaut — Avalonia 12, qui donne Windows, macOS et Linux pour le bureau sans aucune configuration. Référencez-le, et Application.Run(new MyForm()) fonctionne tout simplement. Il ne se limite pas au bureau, d’ailleurs : Avalonia fournit ses propres cibles Android, iOS et Browser (WASM), si bien que ce même backend constitue une seconde voie vers le mobile et le web, à côté du backend Uno dédié présenté ci-dessous.

Majorsilence.Forms.Headless est le backend le plus simple possible et sert aussi de modèle de référence pour en écrire un nouveau : une boucle de messages à file de travail, un presse-papiers en mémoire, un écran virtuel et un rendu hors écran. Il n’a besoin d’aucun affichage ; c’est donc sur lui que tourne la suite de tests unitaires, et il peut rendre l’exemple ControlGallery directement en PNG pour la comparaison pixel par pixel en CI :

dotnet run --project samples/ControlGallery -- --render-headless out.png 1100 750 --select-row 0

Majorsilence.Forms.Uno cible le moteur de rendu Skia d’Uno Platform, héberge un SKXamlCanvas et atteint le bureau, iOS, Android et WebAssembly. Il a été vérifié de bout en bout sous macOS : l’hôte Uno se lance, le backend crée la fenêtre et le MainForm complet de la ControlGallery se rend dans le canvas. Comme il a besoin d’une session interactive, il s’exécute via une tête d’application dédiée — samples/Gallery.Uno — plutôt que par la build CI headless.

Un détail mérite d’être souligné : Uno n’a pas d’API programmatique « commencer un déplacement de fenêtre », si bien que le déplacement et le redimensionnement du chrome de fenêtre auto-dessiné de Majorsilence.Forms sont gérés de manière déclarative — un presenter sans bordure conserve gratuitement les marges de redimensionnement du système, et le glisser de la barre de titre s’appuie sur l’API de zone de légende (caption region) de WinUI sur la tête bureau Windows. Sous macOS, ce sont les décorations natives qui prennent en charge le déplacement et le redimensionnement.

Ajouter le vôtre

Un nouveau backend n’est qu’un assembly de plus : référencez le cœur Majorsilence.Forms et votre toolkit, implémentez IPlatformBackend et IWindowBackend, et calquez-vous sur le trio Avalonia/Headless/Uno — pilotez le dispatcher dans le backend de plateforme, et présentez une surface Skia et traduisez les entrées dans le backend de fenêtre. Voir Backends de plateforme pour la liste complète des interfaces.