.NET MAUI in 2026: Cross-Platform Ontwikkeling en Sollicitatievragen

.NET MAUI tutorial voor 2026: cross-platform apps bouwen met .NET 10, handlers, MVVM, HybridWebView. Inclusief sollicitatievragen.

.NET MAUI Cross-Platform Development 2026

.NET MAUI (Multi-platform App UI) heeft zich met .NET 10 ontwikkeld tot een volwassen, productierijp cross-platform framework. Als Long-Term Support-release met ondersteuning tot november 2028 wordt .NET MAUI 10 geleverd als workload en NuGet-pakketten, met verbeterde kwaliteit, performance en nieuwe API's zoals HybridWebView-verbeteringen en SafeAreaEdges. Deze tutorial begeleidt bij het bouwen van een cross-platform app, legt de onderliggende architectuur uit en behandelt de sollicitatievragen die bij technische interviews in 2026 worden gesteld.

.NET MAUI 10 LTS

.NET 10 is een Long-Term Support-release (ondersteuning tot november 2028). MAUI 10 richt zich op kwaliteit en performance in plaats van nieuwe UI-controls, waardoor het de meest stabiele MAUI-release is. Het wordt nu geleverd als .NET workload en NuGet-pakketten, wat version pinning per project mogelijk maakt.

Een .NET MAUI 10 Project Opzetten vanuit Scratch

Het snelste pad naar een werkende MAUI-app begint met de .NET CLI. .NET 10 introduceert een bijgewerkt projecttemplate dat .NET Aspire service defaults bevat, waardoor telemetrie en service discovery out of the box worden gekoppeld.

bash
# 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-android

De single-project structuur consolideert platformspecifieke code onder een Platforms/-map terwijl de rest gedeeld wordt. Het MauiProgram.cs-bestand dient als composition root, waar services, lettertypen en handlers geregistreerd worden.

MauiProgram.cscsharp
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();
    }
}

Dependency injection in MAUI volgt hetzelfde patroon als in ASP.NET Core. Singleton-services blijven bestaan gedurende de gehele levensduur van de app, Transient-services worden per verzoek aangemaakt, en Scoped-services vereisen voorzichtigheid omdat MAUI geen ingebouwd scope-concept heeft zoals HTTP-verzoeken.

Handlers: De Architectuur Achter Cross-Platform Rendering

MAUI heeft de renderers van Xamarin.Forms vervangen door een handler-architectuur. Handlers mappen elk cross-platform control naar zijn native tegenhanger via een dunne abstractielaag. Het cruciale verschil: handlers zijn stateless en losgekoppeld van de virtuele view, waardoor ze sneller en gemakkelijker aan te passen zijn.

CustomEntryHandler.cscsharp
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>();
});

In .NET 10 zijn de Android Entry- en Editor-controls overgestapt van AppCompatEditText naar MauiAppCompatEditText, met native ondersteuning voor het SelectionChanged-event. De verbeterde CollectionView- en CarouselView-handlers die in .NET 9 werden geïntroduceerd, zijn nu standaard op iOS en Mac Catalyst en lossen langdurige stabiliteitsproblemen op.

Android 16 Edge-to-Edge: Breaking Change en Vereiste Oplossing

Android 16 verwijdert het opt-out mechanisme voor edge-to-edge weergave. Apps die zich richten op API 36 moeten system bar insets correct afhandelen, anders wordt content verkeerd gerenderd. .NET 10 introduceerde een stille breaking change: in .NET 9 respecteerde ContentPage standaard de systeembalken (Container-gedrag), maar .NET 10 gebruikt standaard edge-to-edge (None).

Breaking Change in .NET 10

Apps die migreren van .NET 9 naar .NET 10 kunnen ervaren dat content onder de statusbalk of navigatiebalk wordt gerenderd op Android 15+. De oplossing vereist het expliciet instellen van SafeAreaEdges om het vorige gedrag te herstellen.

De oplossing omvat het toevoegen van een globale impliciete stijl aan App.xaml:

xml
<!-- 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>

De SafeAreaEdges enum biedt granulaire controle:

  • None: edge-to-edge content zonder safe area padding
  • SoftInput: altijd padding voor toetsenbord
  • Container: onder toetsenbord doorstromen, buiten balken en notch blijven
  • Default: standaard platformgedrag
  • All: alle safe area insets respecteren

Deze aanpak gebruikt de Window Insets API tijdens runtime, waardoor het compatibel is met Android 16 waar opt-outs op manifestniveau niet meer werken.

MVVM met CommunityToolkit.Mvvm: Boilerplate Elimineren

De CommunityToolkit.Mvvm source generator elimineert circa 80% van de MVVM-boilerplate. Geen handmatige INotifyPropertyChanged-implementatie, geen command wrappers: attributen sturen de codegeneratie aan.

MainViewModel.cscsharp
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;
        }
    }
}

De XAML bindt direct aan de gegenereerde properties en commands:

xml
<!-- 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>

Het x:DataType-attribuut activeert compiled bindings, die sneller zijn dan reflection-gebaseerde bindings en compile-time fouten produceren wanneer een binding pad onjuist is.

Klaar om je .NET gesprekken te halen?

Oefen met onze interactieve simulatoren, flashcards en technische tests.

XAML Source Generator in .NET 10

.NET MAUI 10 introduceert een XAML source generator die XAML compileert tijdens build-time in plaats van het te parsen tijdens runtime. Dit verbetert de opstartprestaties en vangt XAML-fouten af tijdens compilatie.

Om XAML source generation in te schakelen, voeg de property toe aan het projectbestand:

xml
<PropertyGroup>
  <MauiXamlInflator>SourceGen</MauiXamlInflator>
</PropertyGroup>

.NET 10 Preview 5 introduceerde ook impliciete XML namespaces die boilerplate xmlns declaraties elimineren. Een GlobalXmlns.cs bestand kan meerdere namespaces aggregeren:

GlobalXmlns.cscsharp
[assembly: XmlnsDefinition(
    "http://schemas.microsoft.com/dotnet/maui/global",
    "MyApp.Views")]
[assembly: XmlnsDefinition(
    "http://schemas.microsoft.com/dotnet/maui/global",
    "MyApp.Controls")]

Met deze setup worden XAML-bestanden schoner:

xml
<!-- Voorheen -->
<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>

<!-- Achteraf (met globale xmlns) -->
<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 in .NET 10: De Brug tussen Native en Web

HybridWebView maakt het mogelijk om webcontent in een MAUI-app in te bedden met behoud van bidirectionele communicatie tussen C# en JavaScript. .NET 10 voegt drie mogelijkheden toe: fire-and-forget JavaScript-aanroepen, initialisatie-events voor platformspecifieke configuratie en web request interception.

MainPage.xaml.cscsharp
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");
    }
}

JavaScript-exceptions die tijdens InvokeJavaScriptAsync worden gegooid, worden nu automatisch doorgestuurd naar .NET als exceptions, waardoor stille fouten tot het verleden behoren. Web request interception maakt het mogelijk om headers te wijzigen of lokale responses te leveren:

csharp
webView.WebResourceRequested += (s, e) =>
{
    if (e.Uri.ToString().Contains("api/secure"))
    {
        e.Handled = true;
        e.SetResponse(200, "OK", "application/json", GetCustomStream());
    }
};

Verouderde API's en Migratiepad

.NET MAUI 10 markeert verschillende API's als verouderd. Applicaties die deze gebruiken moeten migreren naar de aanbevolen alternatieven.

ListView en gerelateerde cellen: ListView, EntryCell, ImageCell, SwitchCell, TextCell en ViewCell zijn verouderd. Gebruik CollectionView, dat betere performance en stabiliteit biedt met de nieuwe iOS/Mac Catalyst handlers.

MessagingCenter: Intern gemaakt in .NET 10. Vervangen door WeakReferenceMessenger van CommunityToolkit.Mvvm.

Animatie-methoden: FadeTo, RotateTo, ScaleTo en vergelijkbare methoden zijn verouderd. Gebruik de async equivalenten: FadeToAsync, RotateToAsync, ScaleToAsync.

TableView: Verouderd ten gunste van CollectionView.

DisplayAlert/DisplayActionSheet: Vervangen door DisplayAlertAsync en DisplayActionSheetAsync.

Migratie van Xamarin.Forms naar .NET MAUI

De ondersteuning voor Xamarin.Forms is gestopt in mei 2024. Migratie naar MAUI vereist structurele wijzigingen die verder gaan dan een namespace-swap. Hier is een migratiechecklist gebaseerd op echte projectconversies:

Xamarin EOL

Xamarin.Forms wordt sinds mei 2024 niet meer ondersteund. Applicaties die nog op Xamarin draaien brengen beveiligings- en compatibiliteitsrisico's met zich mee. .NET MAUI 10 (LTS, ondersteund tot november 2028) is het aangewezen migratiedoel.

  1. Projectstructuur: Conversie van platformspecifieke projecten naar het MAUI single-project model. Gedeelde code gaat naar de root, platformcode onder Platforms/.
  2. Namespaces: Vervang Xamarin.Forms door Microsoft.Maui.Controls en Xamarin.Essentials door Microsoft.Maui.Essentials (nu ingebouwd in MAUI).
  3. Renderers naar Handlers: Custom renderers moeten worden herschreven als handlers. De handler API is eenvoudiger, maar de mapping-logica verschilt.
  4. Startup: Vervang de App.xaml.cs-initialisatie door MauiProgram.cs met het builder pattern.
  5. NuGet-pakketten: Veel pakketten uit het Xamarin-tijdperk hebben MAUI-equivalenten. Controleer de compatibiliteit voor de upgrade.
  6. Dependency injection: MAUI gebruikt Microsoft.Extensions.DependencyInjection native. Vervang eventuele third-party DI-containers of DependencyService-aanroepen.

De .NET Upgrade Assistant automatiseert delen van stappen 1-2, maar handlers (stap 3) en aanpassingen aan de businesslogica vereisen handmatig werk.

De Belangrijkste .NET MAUI Sollicitatievragen voor 2026

Deze vragen weerspiegelen wat ontwikkelteams in 2026 tijdens sollicitatiegesprekken vragen, gebaseerd op het huidige .NET 10 ecosysteem. Voor meer C# en .NET sollicitatievoorbereiding, zie de volledige .NET sollicitatiegids.

Hoe verschilt de MAUI handler-architectuur van Xamarin.Forms renderers?

Renderers in Xamarin.Forms waren nauw gekoppeld aan zowel het cross-platform control als de native view, waardoor een bidirectionele afhankelijkheid ontstond. Handlers in MAUI zijn stateless mappers: ze ontvangen property change notificaties en passen deze toe op de native view via een mapper dictionary. Deze ontkoppeling maakt handlers eenvoudiger te testen, uit te breiden en te hergebruiken. De PropertyMapper- en CommandMapper-dictionaries vervangen het OnElementPropertyChanged override-patroon, waardoor aanpassingen expliciet worden in plaats van verborgen in switch statements.

Welke DI lifetime-valkuilen zijn specifiek voor MAUI?

MAUI ondersteunt Singleton-, Transient- en Scoped-lifetimes, maar Scoped gedraagt zich anders dan in ASP.NET Core. Er is geen natuurlijke scope-grens (zoals een HTTP-verzoek). Een Scoped service geregistreerd in MAUI gedraagt zich als een Singleton tenzij aangepaste scopes handmatig worden aangemaakt. Veelvoorkomende fouten: een ViewModel registreren als Singleton terwijl het paginaspecifieke state bevat (verouderde data bij navigatie), of een databaseverbinding registreren als Transient (connection pool-uitputting). De vuistregel: ViewModels zijn Transient, services zijn Singleton, en Scoped wordt vermeden tenzij de scope-levenscyclus expliciet wordt beheerd.

Sollicitatietip

Bij het beantwoorden van DI-vragen is het belangrijk om begrip te tonen van hoe de MAUI-lifecycle verschilt van het request-scoped model van ASP.NET Core. Interviewers zoeken naar bewustzijn van memory leaks en problemen met verouderde state die specifiek zijn voor langlopende mobiele apps.

Hoe verschilt compiled binding van reflection-gebaseerde binding in MAUI?

Reflection-gebaseerde bindings lossen property-paden op tijdens runtime met System.Reflection, wat traag is en runtime-fouten produceert bij typefouten. Compiled bindings, geactiveerd met x:DataType, lossen binding-paden op tijdens compile-time. De compiler genereert directe property-toegangscode en slaat reflection volledig over. Dit verbetert de opstarttijd, vermindert geheugentoewijzingen en vangt binding-fouten af tijdens de build. In .NET 10 optimaliseert de nieuwe XAML source generator dit verder door XAML te compileren tijdens build-time in plaats van het te parsen tijdens runtime.

Welke strategieën bestaan er voor het delen van code tussen een MAUI-app en een ASP.NET Core backend?

De aanbevolen aanpak gebruikt een shared class library met DTO's, validatielogica en business rules. Zowel de MAUI-app als de ASP.NET Core backend verwijzen naar deze library. .NET 10 versterkt dit patroon met de nieuwe .NET Aspire integratie voor MAUI, die service discovery en telemetrie biedt over mobiele en backend-projecten heen. Gedeelde contracts met System.Text.Json source generators zorgen voor serialisatieconsistentie. De belangrijkste beperking: de shared library moet net10.0 targeten (niet platformspecifieke TFM's) om portable te blijven.

Hoe verschilt HybridWebView van BlazorWebView in MAUI?

BlazorWebView host een volledige Blazor-applicatie binnen de MAUI-app. Razor-componenten renderen in een ingebedde WebView, maar de .NET runtime draait native (niet via WebAssembly). HybridWebView is lichter: het laadt statische HTML/CSS/JS-content en biedt C#-naar-JavaScript interop zonder de overhead van het Blazor framework. De keuze hangt af van het gebruiksscenario. BlazorWebView past bij teams met bestaande Blazor-componenten die code willen hergebruiken. HybridWebView past bij scenario's waar bestaande webcontent (dashboards, kaarten, editors) native integratie nodig heeft zonder een volledig framework.

Meer .NET sollicitatievragen op SharpSkill helpen bij het versterken van deze concepten met interactieve oefeningen.

Begin met oefenen!

Test je kennis met onze gespreksimulatoren en technische tests.

Bronnen

Wat .NET MAUI 10 Ontwikkelaars Moeten Onthouden

  • .NET MAUI 10 is een LTS-release (ondersteuning tot november 2028) gericht op stabiliteit en performance, waardoor het een betrouwbare keuze is voor cross-platform productie-apps
  • Android 16 maakt edge-to-edge verplicht: voeg SafeAreaEdges="Container" toe als globale stijl in App.xaml om het .NET 9 gedrag te herstellen
  • De XAML source generator (MauiXamlInflator=SourceGen) compileert XAML tijdens build-time, verbetert opstartprestaties en vangt fouten eerder af
  • ListView, TableView en MessagingCenter zijn verouderd: migreer naar CollectionView en WeakReferenceMessenger
  • De handler-architectuur vervangt Xamarin-renderers door stateless mappers, met verbeterde testbaarheid via PropertyMapper en CommandMapper
  • CommunityToolkit.Mvvm source generators verwijderen het meeste MVVM-boilerplate: [ObservableProperty]- en [RelayCommand]-attributen vervangen handmatige implementaties
  • HybridWebView in .NET 10 voegt fire-and-forget JavaScript-aanroepen, initialisatie-events en request interception toe voor native-web integratie
  • Sollicitatievoorbereiding moet zich richten op handler- vs. renderer-architectuur, DI lifetime-valkuilen in langlopende apps, compiled bindings en de afwegingen tussen HybridWebView en BlazorWebView
Dagelijkse challenge

Zie jij de bug in .NET?

Een echt codefragment, een verborgen bug, één poging per dag. Zonder account uit te proberen.

Anthony Fillion-Maillet

Geschreven door

Anthony Fillion-Maillet

Oprichter van SharpSkill

Al meer dan 10 jaar fullstack-ontwikkelaar. Hij leidt SharpSkill en staat in voor alles wat hier verschijnt.

Bijgewerkt op 14 september 2026

Tags

#dotnet
#maui
#cross-platform
#mobile

Delen

Gerelateerde artikelen