.NET MAUI en 2026 : Développement Cross-Platform et Questions d'Entretien
Tutoriel .NET MAUI couvrant le développement cross-platform avec .NET 10, handlers, MVVM, HybridWebView et questions d'entretien essentielles pour 2026.

.NET MAUI (Multi-platform App UI) s'est imposé comme un framework cross-platform de qualité production avec .NET 10. Publié en tant que version Long-Term Support maintenue jusqu'en novembre 2028, .NET MAUI 10 est distribué sous forme de workload et de packages NuGet, offrant une qualité, des performances et de nouvelles API améliorées telles que les évolutions de HybridWebView et SafeAreaEdges. Ce tutoriel couvre la création d'une application cross-platform, l'architecture qui fait fonctionner MAUI, et les questions d'entretien que les recruteurs posent en 2026.
.NET 10 est une version Long-Term Support (maintenue jusqu'en novembre 2028). MAUI 10 privilégie la qualité et les performances plutôt que l'ajout de nouveaux contrôles UI, ce qui en fait la version la plus stable de MAUI à ce jour. Le framework est désormais distribué en tant que workload .NET et packages NuGet, permettant le verrouillage de version par projet.
Mise en Place d'un Projet .NET MAUI 10 de Zéro
Le chemin le plus rapide vers une application MAUI fonctionnelle commence avec la CLI .NET. .NET 10 introduit un template de projet mis à jour qui inclut les configurations par défaut d'Aspire, connectant la télémétrie et la découverte de services nativement.
# Install the MAUI workload (if not already present)
dotnet workload install maui
# Create a new MAUI app
dotnet new maui -n CrossPlatformDemo
cd CrossPlatformDemo
# Run on Android emulator
dotnet build -t:Run -f net10.0-androidLa structure mono-projet consolide le code spécifique à chaque plateforme dans un dossier Platforms/ tout en partageant le reste. Le fichier MauiProgram.cs sert de racine de composition, où les services, polices et handlers sont enregistrés.
using Microsoft.Extensions.Logging;
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
});
// Register services for dependency injection
builder.Services.AddSingleton<IApiService, ApiService>();
builder.Services.AddTransient<MainViewModel>();
#if DEBUG
builder.Logging.AddDebug();
#endif
return builder.Build();
}
}L'injection de dépendances dans MAUI suit le même modèle qu'ASP.NET Core. Les services Singleton persistent pendant toute la durée de vie de l'application, les services Transient sont créés à chaque demande, et les services Scoped nécessitent de la prudence car MAUI ne dispose pas d'un concept de scope intégré comme les requêtes HTTP.
Handlers : L'Architecture Derrière le Rendu Cross-Platform
MAUI a remplacé les renderers de Xamarin.Forms par une architecture de handlers. Les handlers associent chaque contrôle cross-platform à son équivalent natif via une fine couche d'abstraction. La différence clé : les handlers sont sans état et découplés de la vue virtuelle, ce qui les rend plus rapides et plus faciles à personnaliser.
using Microsoft.Maui.Handlers;
public class CustomEntryHandler : EntryHandler
{
protected override void ConnectHandler(MauiAppCompatEditText platformView)
{
base.ConnectHandler(platformView);
// Remove the default underline on Android
platformView.SetBackgroundColor(Android.Graphics.Color.Transparent);
}
}
// Register in MauiProgram.cs
builder.ConfigureMauiHandlers(handlers =>
{
handlers.AddHandler<Entry, CustomEntryHandler>();
});Dans .NET 10, les contrôles Android Entry et Editor sont passés de AppCompatEditText à MauiAppCompatEditText, ajoutant la prise en charge native de l'événement SelectionChanged. Les handlers améliorés pour CollectionView et CarouselView introduits dans .NET 9 sont désormais les handlers par défaut sur iOS et Mac Catalyst, résolvant des problèmes de stabilité de longue date.
Android 16 Edge-to-Edge : Breaking Change et Correctif Requis
Android 16 supprime le mécanisme de désactivation de l'affichage edge-to-edge. Les applications ciblant l'API 36 doivent gérer correctement les insets des barres système, sinon le contenu s'affiche de manière incorrecte. .NET 10 a introduit un breaking change silencieux : dans .NET 9, ContentPage respectait les barres système par défaut (comportement Container), mais .NET 10 passe par défaut à l'edge-to-edge (None).
Les applications migrant de .NET 9 vers .NET 10 peuvent voir le contenu s'afficher sous la barre de statut ou la barre de navigation sur Android 15+. Le correctif nécessite de définir explicitement SafeAreaEdges pour restaurer le comportement précédent.
Le correctif consiste à ajouter un style implicite global dans App.xaml :
<!-- App.xaml -->
<Application xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="CrossPlatformDemo.App">
<Application.Resources>
<ResourceDictionary>
<Style TargetType="ContentPage" ApplyToDerivedTypes="True">
<Setter Property="SafeAreaEdges" Value="Container" />
</Style>
</ResourceDictionary>
</Application.Resources>
</Application>L'enum SafeAreaEdges offre un contrôle granulaire :
None: contenu edge-to-edge sans padding de safe areaSoftInput: toujours ajouter un padding pour le clavierContainer: passer sous le clavier, rester en dehors des barres et de l'encocheDefault: comportement par défaut de la plateformeAll: respecter tous les insets de safe area
Cette approche utilise l'API Window Insets au runtime, ce qui la rend compatible avec Android 16 où les opt-outs au niveau du manifeste ne fonctionnent plus.
MVVM avec CommunityToolkit.Mvvm : Éliminer le Code Répétitif
Le générateur de code source CommunityToolkit.Mvvm élimine environ 80 % de la cérémonie MVVM. Plus besoin d'implémentation manuelle de INotifyPropertyChanged, plus de wrappers de commandes : les attributs pilotent la génération de code.
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
public partial class MainViewModel : ObservableObject
{
private readonly IApiService _apiService;
public MainViewModel(IApiService apiService)
{
_apiService = apiService;
}
// Source generator creates the 'Title' property with change notification
[ObservableProperty]
private string _title = string.Empty;
// Source generator creates the 'IsLoading' property
[ObservableProperty]
private bool _isLoading;
// Source generator creates an async ICommand
[RelayCommand]
private async Task LoadDataAsync()
{
IsLoading = true;
try
{
Title = await _apiService.FetchTitleAsync();
}
finally
{
IsLoading = false;
}
}
}Le XAML se lie directement aux propriétés et commandes générées :
<!-- MainPage.xaml -->
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:vm="clr-namespace:CrossPlatformDemo.ViewModels"
x:DataType="vm:MainViewModel">
<VerticalStackLayout Padding="20" Spacing="16">
<Label Text="{Binding Title}"
FontSize="24"
HorizontalOptions="Center" />
<Button Text="Load Data"
Command="{Binding LoadDataCommand}"
IsEnabled="{Binding IsLoading, Converter={StaticResource InverseBoolConverter}}" />
<ActivityIndicator IsRunning="{Binding IsLoading}"
IsVisible="{Binding IsLoading}" />
</VerticalStackLayout>
</ContentPage>L'attribut x:DataType active les bindings compilés, qui sont plus rapides que les bindings par réflexion et produisent des erreurs à la compilation lorsqu'un chemin de binding est incorrect.
Prêt à réussir tes entretiens .NET ?
Entraîne-toi avec nos simulateurs interactifs, fiches express et tests techniques.
Générateur de Source XAML dans .NET 10
.NET MAUI 10 introduit un générateur de source XAML qui compile le XAML au moment du build plutôt que de le parser au runtime. Cela améliore les performances de démarrage et détecte les erreurs XAML pendant la compilation.
Pour activer la génération de source XAML, ajouter la propriété au fichier projet :
<PropertyGroup>
<MauiXamlInflator>SourceGen</MauiXamlInflator>
</PropertyGroup>.NET 10 Preview 5 a également introduit des namespaces XML implicites qui éliminent les déclarations xmlns répétitives. Un fichier GlobalXmlns.cs peut agréger plusieurs namespaces :
[assembly: XmlnsDefinition(
"http://schemas.microsoft.com/dotnet/maui/global",
"MyApp.Views")]
[assembly: XmlnsDefinition(
"http://schemas.microsoft.com/dotnet/maui/global",
"MyApp.Controls")]Avec cette configuration, les fichiers XAML deviennent plus propres :
<!-- Avant -->
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:MyApp.Controls"
x:Class="MyApp.MainPage">
<controls:TagView />
</ContentPage>
<!-- Après (avec xmlns global) -->
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/maui/global"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MyApp.MainPage">
<TagView />
</ContentPage>HybridWebView dans .NET 10 : Le Pont entre Natif et Web
HybridWebView permet d'intégrer du contenu web dans une application MAUI tout en maintenant une communication bidirectionnelle entre C# et JavaScript. .NET 10 ajoute trois fonctionnalités : l'invocation JavaScript de type fire-and-forget, les événements d'initialisation pour la configuration spécifique à la plateforme, et l'interception des requêtes web.
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
// Initialization event for platform-specific tweaks
hybridWebView.WebViewInitialized += (sender, args) =>
{
System.Diagnostics.Debug.WriteLine("WebView ready");
};
}
// Call JavaScript from C#
private async void OnCallJsClicked(object sender, EventArgs e)
{
var result = await hybridWebView.InvokeJavaScriptAsync<string>(
"getFormData",
HybridSampleContext.Default.String
);
await DisplayAlertAsync("Result", result, "OK");
}
// Fire-and-forget: no return type needed (.NET 10)
private async void OnResetClicked(object sender, EventArgs e)
{
await hybridWebView.InvokeJavaScriptAsync("resetForm");
}
}Les exceptions JavaScript levées pendant InvokeJavaScriptAsync sont désormais automatiquement transmises vers .NET sous forme d'exceptions, éliminant les échecs silencieux. L'interception des requêtes web permet de modifier les headers ou de fournir des réponses locales :
webView.WebResourceRequested += (s, e) =>
{
if (e.Uri.ToString().Contains("api/secure"))
{
e.Handled = true;
e.SetResponse(200, "OK", "application/json", GetCustomStream());
}
};APIs Dépréciées et Chemin de Migration
.NET MAUI 10 déprécie plusieurs APIs. Les applications utilisant ces APIs doivent migrer vers les alternatives recommandées.
ListView et cellules associées : ListView, EntryCell, ImageCell, SwitchCell, TextCell et ViewCell sont dépréciés. Utiliser CollectionView à la place, qui offre de meilleures performances et stabilité avec les nouveaux handlers iOS/Mac Catalyst.
MessagingCenter : Rendu interne dans .NET 10. Remplacer par WeakReferenceMessenger du CommunityToolkit.Mvvm.
Méthodes d'animation : FadeTo, RotateTo, ScaleTo et méthodes similaires sont dépréciées. Utiliser les équivalents async : FadeToAsync, RotateToAsync, ScaleToAsync.
TableView : Déprécié en faveur de CollectionView.
DisplayAlert/DisplayActionSheet : Remplacés par DisplayAlertAsync et DisplayActionSheetAsync.
Migration de Xamarin.Forms vers .NET MAUI
Xamarin.Forms a atteint sa fin de support en mai 2024. La migration vers MAUI implique des changements structurels au-delà d'un simple remplacement de namespaces. Voici une checklist de migration basée sur des conversions de projets réels :
Xamarin.Forms n'est plus supporté depuis mai 2024. Les applications tournant encore sur Xamarin présentent des risques de sécurité et de compatibilité. .NET MAUI 10 (LTS, supporté jusqu'en novembre 2028) est la cible de migration désignée.
- Structure du projet : Convertir les projets spécifiques à chaque plateforme vers le modèle mono-projet MAUI. Déplacer le code partagé vers la racine, le code plateforme sous
Platforms/. - Namespaces : Remplacer
Xamarin.FormsparMicrosoft.Maui.ControlsetXamarin.EssentialsparMicrosoft.Maui.Essentials(désormais intégré à MAUI). - Renderers vers Handlers : Les renderers personnalisés doivent être réécrits en handlers. L'API des handlers est plus simple mais la logique de mapping diffère.
- Démarrage : Remplacer l'initialisation dans
App.xaml.csparMauiProgram.csutilisant le pattern builder. - Packages NuGet : De nombreux packages de l'ère Xamarin ont des équivalents MAUI. Vérifier la compatibilité avant la mise à niveau.
- Injection de dépendances : MAUI utilise
Microsoft.Extensions.DependencyInjectionnativement. Remplacer tout conteneur DI tiers ou les appels àDependencyService.
Le .NET Upgrade Assistant automatise une partie des étapes 1-2, mais les handlers (étape 3) et les ajustements de logique métier nécessitent un travail manuel.
Questions d'Entretien .NET MAUI Incontournables en 2026
Ces questions reflètent ce que les équipes de recrutement demandent en 2026, en se basant sur l'écosystème .NET 10 actuel. Pour plus de préparation aux entretiens C# et .NET, consulter le guide complet des entretiens .NET.
En quoi l'architecture de handlers de MAUI diffère-t-elle des renderers de Xamarin.Forms ?
Les renderers dans Xamarin.Forms étaient étroitement couplés à la fois au contrôle cross-platform et à la vue native, créant une dépendance bidirectionnelle. Les handlers dans MAUI sont des mappers sans état : ils reçoivent des notifications de changement de propriétés et les appliquent à la vue native via un dictionnaire de mappers. Ce découplage signifie que les handlers sont plus faciles à tester, étendre et réutiliser. Les dictionnaires PropertyMapper et CommandMapper remplacent le pattern d'override OnElementPropertyChanged, rendant la personnalisation explicite plutôt qu'enfouie dans des instructions switch.
Quels sont les pièges des durées de vie DI spécifiques à MAUI ?
MAUI supporte les durées de vie Singleton, Transient et Scoped, mais Scoped se comporte différemment d'ASP.NET Core. Il n'y a pas de limite de scope naturelle (comme une requête HTTP). Un service Scoped enregistré dans MAUI se comporte comme un Singleton à moins que des scopes personnalisés ne soient créés manuellement. Erreurs courantes : enregistrer un ViewModel en Singleton alors qu'il contient un état spécifique à la page (données périmées lors de la navigation), ou enregistrer une connexion de base de données en Transient (épuisement du pool de connexions). La règle générale : les ViewModels sont Transient, les services sont Singleton, et Scoped est évité sauf si le cycle de vie du scope est géré explicitement.
Lors de la réponse aux questions sur l'injection de dépendances, il est important de démontrer une compréhension de la façon dont le cycle de vie de MAUI diffère du modèle de scope par requête d'ASP.NET Core. Les recruteurs recherchent une conscience des fuites mémoire et des problèmes d'état périmé spécifiques aux applications mobiles de longue durée.
Quelle est la différence entre le binding compilé et le binding par réflexion dans MAUI ?
Les bindings par réflexion résolvent les chemins de propriétés au runtime en utilisant System.Reflection, ce qui est lent et produit des erreurs au runtime pour les fautes de frappe. Les bindings compilés, activés avec x:DataType, résolvent les chemins de binding à la compilation. Le compilateur génère du code d'accès direct aux propriétés, contournant entièrement la réflexion. Cela améliore le temps de démarrage, réduit les allocations mémoire et détecte les erreurs de binding pendant le build. Dans .NET 10, le nouveau générateur de source XAML optimise encore davantage en compilant le XAML au moment du build plutôt qu'en le parsant au runtime.
Quelles stratégies existent pour partager du code entre une application MAUI et un backend ASP.NET Core ?
L'approche recommandée utilise une bibliothèque de classes partagée contenant les DTOs, la logique de validation et les règles métier. L'application MAUI et le backend ASP.NET Core référencent tous deux cette bibliothèque. .NET 10 renforce ce pattern avec la nouvelle intégration .NET Aspire pour MAUI, qui fournit la découverte de services et la télémétrie entre projets mobiles et backend. Les contrats partagés utilisant les générateurs de source System.Text.Json assurent la cohérence de la sérialisation. La contrainte clé : la bibliothèque partagée doit cibler net10.0 (pas de TFMs spécifiques à une plateforme) pour rester portable.
Quelle est la différence entre HybridWebView et BlazorWebView dans MAUI ?
BlazorWebView héberge une application Blazor complète à l'intérieur de l'application MAUI. Les composants Razor sont rendus dans une WebView intégrée, mais le runtime .NET s'exécute nativement (pas via WebAssembly). HybridWebView est plus léger : il charge du contenu HTML/CSS/JS statique et fournit une interopérabilité C#-vers-JavaScript sans la surcharge du framework Blazor. Le choix dépend du cas d'usage. BlazorWebView convient aux équipes ayant des composants Blazor existants souhaitant la réutilisation de code. HybridWebView convient aux scénarios où du contenu web existant (tableaux de bord, cartes, éditeurs) nécessite une intégration native sans framework complet.
Pour approfondir ces concepts, il est possible de pratiquer davantage de questions d'entretien .NET sur SharpSkill avec des exercices interactifs.
Passe à la pratique !
Teste tes connaissances avec nos simulateurs d'entretien et tests techniques.
Sources
- What's new in .NET MAUI for .NET 10 : documentation officielle couvrant toutes les fonctionnalités de .NET 10 MAUI
- .NET MAUI GitHub Releases : notes de version des releases de service 10.0.x
- Edge-to-Edge Is Now Mandatory in Android 16 : guide de migration pour les exigences Android 16
- MAUI GitHub Discussion #34171 : retours de la communauté sur la stabilité de .NET MAUI 10
Ce que les Développeurs .NET MAUI 10 Doivent Retenir
- .NET MAUI 10 est une version LTS (support jusqu'en novembre 2028) axée sur la stabilité et les performances, ce qui en fait un choix fiable pour les applications cross-platform en production
- Android 16 rend l'edge-to-edge obligatoire : ajouter
SafeAreaEdges="Container"comme style global dans App.xaml pour restaurer le comportement de .NET 9 - Le générateur de source XAML (
MauiXamlInflator=SourceGen) compile le XAML au moment du build, améliorant les performances de démarrage et détectant les erreurs plus tôt - ListView, TableView et MessagingCenter sont dépréciés : migrer vers CollectionView et WeakReferenceMessenger
- L'architecture de handlers remplace les renderers Xamarin par des mappers sans état, améliorant la testabilité via
PropertyMapperetCommandMapper - Les générateurs de source CommunityToolkit.Mvvm suppriment la majeure partie du code répétitif MVVM : les attributs
[ObservableProperty]et[RelayCommand]remplacent les implémentations manuelles - HybridWebView dans .NET 10 ajoute les appels JavaScript fire-and-forget, les événements d'initialisation et l'interception de requêtes pour l'intégration native-web
- La préparation aux entretiens devrait se concentrer sur l'architecture handlers vs renderers, les pièges de durée de vie DI dans les applications longue durée, les bindings compilés et les compromis HybridWebView vs BlazorWebView
Tu saurais repérer le bug en .NET ?
Un vrai bout de code, un bug caché, une tentative par jour. Sans compte pour essayer.

Écrit par
Anthony Fillion-MailletFondateur de SharpSkill
Développeur fullstack depuis plus de 10 ans. Il dirige SharpSkill et répond de tout ce qui y est publié.
Mis à jour le 14 septembre 2026
Tags
Partager
Articles similaires

.NET 10 en 2026 : Nouvelles Fonctionnalités, AOT Natif et C# 14 pour la Préparation aux Entretiens
.NET 10 est la nouvelle version LTS avec des améliorations Native AOT, les extension members de C# 14, le mot-clé field et les applications fichier. Guide complet des nouvelles fonctionnalités, gains de performance et connaissances pour entretiens techniques .NET en 2026.

Clean Architecture .NET en 2026 : CQRS, MediatR et Questions d'Entretien Développeur
Clean Architecture en .NET avec CQRS et MediatR 14. Maîtrisez les patterns en couches, les pipeline behaviors et préparez les entretiens développeur senior.

Durée de Vie de DbContext dans ASP.NET Core : Performance vs Thread Safety en Async
Maîtrisez la gestion de la durée de vie de DbContext dans ASP.NET Core. Apprenez quand utiliser scoped vs transient, comment gérer les opérations async en toute sécurité et optimiser les performances avec le pooling de DbContext.