.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 de belangrijkste sollicitatievragen met antwoorden.

.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 richt .NET MAUI 10 zich op 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 tot nu toe 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 — hier worden services, lettertypen en handlers geregistreerd.

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 — hoewel beschikbaar — 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.cs — Customizing the Entry control on Androidcsharp
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 geintroduceerd, zijn nu standaard op iOS en Mac Catalyst en lossen langdurige stabiliteitsproblemen op.

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.

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.cs — HybridWebView interactioncsharp
public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();

        // Initialization event for platform-specific tweaks
        hybridWebView.WebViewInitialized += (sender, args) =>
        {
            // Access the native platform view after initialization
            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",  // JS function name
            HybridSampleContext.Default.String  // JSON serialization context
        );
        await DisplayAlert("Result", result, "OK");
    }

    // Fire-and-forget: no return type needed (.NET 10)
    private async void OnResetClicked(object sender, EventArgs e)
    {
        await hybridWebView.InvokeJavaScriptAsync("resetForm");
    }
}

Het bijbehorende JavaScript ontvangt aanroepen en kan berichten terugsturen naar C#:

wwwroot/index.html (HybridWebView content)javascript
function getFormData() {
    return JSON.stringify({
        name: document.getElementById('name').value,
        email: document.getElementById('email').value
    });
}

function resetForm() {
    document.getElementById('name').value = '';
    document.getElementById('email').value = '';
}

JavaScript-exceptions die tijdens InvokeJavaScriptAsync worden gegooid, worden nu automatisch doorgestuurd naar .NET als exceptions, waardoor stille fouten tot het verleden behoren.

SafeAreaEdges: Pixel-Perfecte Layouts op Elk Apparaat

.NET MAUI 10 introduceert de SafeAreaEdges-property voor Layout, ContentView, ContentPage, Border en ScrollView. De nieuwe enum (None, SoftInput, Container, Default, All) vervangt de verouderde iOS-specifieke Page.UseSafeArea met een cross-platform aanpak.

xml
<!-- Granular safe area control per section -->
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             SafeAreaEdges="All">
    <Grid RowDefinitions="Auto,*,Auto">
        <!-- Header respects all safe areas -->
        <Border Grid.Row="0" SafeAreaEdges="Container">
            <Label Text="Header" />
        </Border>

        <!-- Content scrolls under safe areas -->
        <ScrollView Grid.Row="1" SafeAreaEdges="SoftInput">
            <VerticalStackLayout Padding="16">
                <Entry Placeholder="Type here..." />
            </VerticalStackLayout>
        </ScrollView>

        <!-- Footer avoids home indicator -->
        <Border Grid.Row="2" SafeAreaEdges="Container">
            <Label Text="Footer" />
        </Border>
    </Grid>
</ContentPage>

SoftInput past de content aan wanneer het schermtoetsenbord verschijnt. Container vermijdt notches, sensorbehuizingen en de home-indicator. Deze kunnen per control gecombineerd worden, zodat een header onder de statusbalk kan zitten terwijl het contentgebied vrij blijft.

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.

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 strategieen 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.

Conclusie

  • .NET MAUI 10 is een LTS-release (ondersteuning tot november 2028) gericht op stabiliteit en performance in plaats van feature-inflatie — een betrouwbare keuze voor cross-platform productie-apps
  • De handler-architectuur vervangt Xamarin-renderers door stateless mappers, met verbeterde testbaarheid en aanpasbaarheid via PropertyMapper en CommandMapper
  • CommunityToolkit.Mvvm source generators verwijderen het meeste MVVM-boilerplate — [ObservableProperty]- en [RelayCommand]-attributen vervangen handmatige INotifyPropertyChanged- en command-implementaties
  • HybridWebView in .NET 10 voegt fire-and-forget JavaScript-aanroepen, initialisatie-events en request interception toe voor native-web integratie
  • SafeAreaEdges biedt granulaire, cross-platform controle over device cutouts, toetsenborden en systeembalken, ter vervanging van het verouderde iOS-only UseSafeArea
  • De Xamarin.Forms-migratie vereist handler-herschrijvingen en startup-refactoring — de .NET Upgrade Assistant handelt namespace-wijzigingen af, maar handmatig werk blijft nodig voor custom renderers
  • Sollicitatievoorbereiding moet zich richten op handler- vs. renderer-architectuur, DI lifetime-valkuilen in langlopende apps, compiled bindings en de afwegingen tussen HybridWebView en BlazorWebView

Begin met oefenen!

Test je kennis met onze gespreksimulatoren en technische tests.

Tags

#dotnet
#maui
#cross-platform
#mobile

Delen

Gerelateerde artikelen