.NET MAUI nel 2026: Sviluppo Cross-Platform e Domande di Colloquio

Tutorial .NET MAUI per il 2026: sviluppare app cross-platform con .NET 10, handlers, MVVM, HybridWebView. Include le domande di colloquio.

.NET MAUI Cross-Platform Development 2026

.NET MAUI (Multi-platform App UI) si è affermato come framework cross-platform maturo e pronto per la produzione con .NET 10. Rilasciato come versione Long-Term Support con supporto fino a novembre 2028, .NET MAUI 10 viene distribuito come workload e pacchetti NuGet, offrendo miglioramenti in qualità, performance e nuove API come i potenziamenti di HybridWebView e SafeAreaEdges. Questo tutorial guida attraverso la creazione di un'app cross-platform, spiega l'architettura alla base di MAUI e affronta le domande di colloquio che i responsabili delle assunzioni pongono nel 2026.

.NET MAUI 10 LTS

.NET 10 è un rilascio Long-Term Support (supportato fino a novembre 2028). MAUI 10 punta su qualità e performance piuttosto che su nuovi controlli UI, rendendolo il rilascio MAUI più stabile. Ora viene distribuito come workload .NET e pacchetti NuGet, abilitando il version pinning per progetto.

Configurare un Progetto .NET MAUI 10 da Zero

Il percorso più rapido verso un'app MAUI funzionante inizia con la .NET CLI. .NET 10 introduce un template di progetto aggiornato che include i service defaults di .NET Aspire, collegando telemetria e service discovery out of the box.

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

La struttura a progetto singolo consolida il codice specifico per piattaforma sotto una cartella Platforms/, condividendo tutto il resto. Il file MauiProgram.cs funge da composition root, dove vengono registrati servizi, font e handlers.

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

La dependency injection in MAUI segue lo stesso pattern di ASP.NET Core. I servizi Singleton persistono per l'intera durata dell'app, i servizi Transient vengono creati per ogni richiesta, e i servizi Scoped richiedono cautela perché MAUI non possiede un concetto nativo di scope come le richieste HTTP.

Handlers: L'Architettura Dietro al Rendering Cross-Platform

MAUI ha sostituito i renderer di Xamarin.Forms con un'architettura basata su handler. Gli handler mappano ogni controllo cross-platform al suo corrispettivo nativo attraverso un sottile livello di astrazione. La differenza fondamentale: gli handler sono stateless e disaccoppiati dalla virtual view, rendendoli più veloci e più facili da personalizzare.

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, i controlli Entry e Editor su Android sono passati da AppCompatEditText a MauiAppCompatEditText, aggiungendo il supporto nativo per l'evento SelectionChanged. I miglioramenti ai CollectionView e CarouselView handler introdotti in .NET 9 sono ora predefiniti su iOS e Mac Catalyst, risolvendo problemi di stabilità di lunga data.

Android 16 Edge-to-Edge: Breaking Change e Correzione Richiesta

Android 16 rimuove il meccanismo di opt-out per la visualizzazione edge-to-edge. Le app che mirano all'API 36 devono gestire correttamente gli inset delle barre di sistema, altrimenti il contenuto viene renderizzato in modo errato. .NET 10 ha introdotto una breaking change silenziosa: in .NET 9, ContentPage rispettava le barre di sistema di default (comportamento Container), ma .NET 10 utilizza di default edge-to-edge (None).

Breaking Change in .NET 10

Le app che migrano da .NET 9 a .NET 10 potrebbero vedere il contenuto renderizzato sotto la barra di stato o la barra di navigazione su Android 15+. La correzione richiede l'impostazione esplicita di SafeAreaEdges per ripristinare il comportamento precedente.

La correzione comporta l'aggiunta di uno stile implicito globale in 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>

L'enum SafeAreaEdges fornisce controllo granulare:

  • None: contenuto edge-to-edge senza padding per safe area
  • SoftInput: sempre padding per la tastiera
  • Container: scorrere sotto la tastiera, restare fuori da barre e notch
  • Default: comportamento predefinito della piattaforma
  • All: rispettare tutti gli inset della safe area

Questo approccio utilizza la Window Insets API a runtime, rendendolo compatibile con Android 16 dove gli opt-out a livello di manifest non funzionano più.

MVVM con CommunityToolkit.Mvvm: Eliminare il Boilerplate

Il source generator di CommunityToolkit.Mvvm elimina circa l'80% del codice cerimoniale MVVM. Nessuna implementazione manuale di INotifyPropertyChanged, nessun wrapper per i command: gli attributi guidano la generazione del codice.

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;
        }
    }
}

Il XAML si lega direttamente alle proprietà e ai command generati:

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>

L'attributo x:DataType abilita i compiled binding, che sono più veloci dei binding basati su reflection e producono errori a compile-time quando un percorso di binding è errato.

Pronto a superare i tuoi colloqui su .NET?

Pratica con i nostri simulatori interattivi, flashcards e test tecnici.

XAML Source Generator in .NET 10

.NET MAUI 10 introduce un XAML source generator che compila XAML a build-time invece di parsificarlo a runtime. Questo migliora le performance di avvio e intercetta gli errori XAML durante la compilazione.

Per abilitare la generazione del source XAML, aggiungere la proprietà al file di progetto:

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

.NET 10 Preview 5 ha anche introdotto namespace XML impliciti che eliminano le dichiarazioni boilerplate xmlns. Un file GlobalXmlns.cs può aggregare più namespace:

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

Con questa configurazione, i file XAML diventano più puliti:

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

<!-- Dopo (con xmlns globale) -->
<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: Il Ponte tra Nativo e Web

HybridWebView consente di incorporare contenuti web all'interno di un'app MAUI mantenendo la comunicazione bidirezionale tra C# e JavaScript. .NET 10 aggiunge tre funzionalità: invocazione JavaScript fire-and-forget, eventi di inizializzazione per la configurazione specifica della piattaforma e intercettazione delle richieste web.

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");
    }
}

Le eccezioni JavaScript lanciate durante InvokeJavaScriptAsync vengono ora automaticamente inoltrate a .NET come eccezioni, eliminando i fallimenti silenziosi. L'intercettazione delle richieste web consente di modificare header o fornire risposte locali:

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

API Deprecate e Percorso di Migrazione

.NET MAUI 10 depreca diverse API. Le applicazioni che le utilizzano dovrebbero migrare alle alternative raccomandate.

ListView e celle correlate: ListView, EntryCell, ImageCell, SwitchCell, TextCell e ViewCell sono deprecate. Utilizzare CollectionView, che offre migliori performance e stabilità con i nuovi handler iOS/Mac Catalyst.

MessagingCenter: Reso interno in .NET 10. Sostituire con WeakReferenceMessenger di CommunityToolkit.Mvvm.

Metodi di animazione: FadeTo, RotateTo, ScaleTo e metodi simili sono deprecati. Utilizzare gli equivalenti async: FadeToAsync, RotateToAsync, ScaleToAsync.

TableView: Deprecato a favore di CollectionView.

DisplayAlert/DisplayActionSheet: Sostituiti con DisplayAlertAsync e DisplayActionSheetAsync.

Migrazione da Xamarin.Forms a .NET MAUI

Il supporto per Xamarin.Forms è terminato a maggio 2024. La migrazione a MAUI richiede modifiche strutturali che vanno oltre un semplice scambio di namespace. Ecco una checklist di migrazione basata su conversioni di progetti reali:

Xamarin EOL

Xamarin.Forms non è più supportato da maggio 2024. Le applicazioni ancora in esecuzione su Xamarin comportano rischi di sicurezza e compatibilità. .NET MAUI 10 (LTS, supportato fino a novembre 2028) è il target di migrazione designato.

  1. Struttura del progetto: Conversione dai progetti specifici per piattaforma al modello single-project di MAUI. Il codice condiviso va nella root, il codice specifico per piattaforma sotto Platforms/.
  2. Namespace: Sostituire Xamarin.Forms con Microsoft.Maui.Controls e Xamarin.Essentials con Microsoft.Maui.Essentials (ora integrato in MAUI).
  3. Renderer a Handler: I custom renderer devono essere riscritti come handler. L'API degli handler è più semplice, ma la logica di mapping è differente.
  4. Startup: Sostituire l'inizializzazione App.xaml.cs con MauiProgram.cs utilizzando il builder pattern.
  5. Pacchetti NuGet: Molti pacchetti dell'era Xamarin hanno equivalenti MAUI. Verificare la compatibilità prima dell'upgrade.
  6. Dependency injection: MAUI utilizza Microsoft.Extensions.DependencyInjection nativamente. Sostituire qualsiasi container DI di terze parti o chiamate a DependencyService.

Il .NET Upgrade Assistant automatizza parti dei passaggi 1-2, ma gli handler (passaggio 3) e gli aggiustamenti della logica di business richiedono lavoro manuale.

Le Domande di Colloquio più Importanti su .NET MAUI per il 2026

Queste domande riflettono ciò che i team di sviluppo chiedono nei colloqui del 2026, basandosi sull'ecosistema attuale .NET 10. Per ulteriore preparazione ai colloqui C# e .NET, consultare la guida completa ai colloqui .NET.

Come si differenzia l'architettura handler di MAUI dai renderer di Xamarin.Forms?

I renderer in Xamarin.Forms erano strettamente accoppiati sia al controllo cross-platform che alla view nativa, creando una dipendenza bidirezionale. Gli handler in MAUI sono mapper stateless: ricevono notifiche di cambiamento delle proprietà e le applicano alla view nativa attraverso un dizionario di mapping. Questo disaccoppiamento rende gli handler più facili da testare, estendere e riutilizzare. I dizionari PropertyMapper e CommandMapper sostituiscono il pattern di override OnElementPropertyChanged, rendendo la personalizzazione esplicita invece di nasconderla in blocchi switch.

Quali sono le insidie dei lifetime DI specifiche di MAUI?

MAUI supporta i lifetime Singleton, Transient e Scoped, ma Scoped si comporta diversamente rispetto ad ASP.NET Core. Non esiste un confine di scope naturale (come una richiesta HTTP). Un servizio Scoped registrato in MAUI agisce come un Singleton a meno che non vengano creati scope personalizzati manualmente. Errori comuni: registrare un ViewModel come Singleton quando contiene stato specifico della pagina (dati obsoleti durante la navigazione), o registrare una connessione al database come Transient (esaurimento del connection pool). La regola generale: i ViewModel sono Transient, i servizi sono Singleton, e Scoped viene evitato a meno che il ciclo di vita dello scope non sia gestito esplicitamente.

Consiglio per il Colloquio

Quando si risponde a domande sulla DI, è importante dimostrare di comprendere come il lifecycle di MAUI differisca dal modello request-scoped di ASP.NET Core. Gli intervistatori cercano la consapevolezza dei memory leak e dei problemi di stato obsoleto specifici delle app mobile a lunga esecuzione.

Come si differenzia il compiled binding dal binding basato su reflection in MAUI?

I binding basati su reflection risolvono i percorsi delle proprietà a runtime usando System.Reflection, il che è lento e produce errori a runtime in caso di errori di battitura. I compiled binding, abilitati con x:DataType, risolvono i percorsi di binding a compile-time. Il compilatore genera codice di accesso diretto alle proprietà, saltando completamente la reflection. Questo migliora il tempo di avvio, riduce le allocazioni di memoria e intercetta gli errori di binding durante la build. In .NET 10, il nuovo source generator XAML ottimizza ulteriormente compilando il XAML a build-time invece di parsificarlo a runtime.

Quali strategie esistono per condividere codice tra un'app MAUI e un backend ASP.NET Core?

L'approccio raccomandato utilizza una shared class library contenente DTO, logica di validazione e regole di business. Sia l'app MAUI che il backend ASP.NET Core fanno riferimento a questa libreria. .NET 10 rafforza questo pattern con la nuova integrazione .NET Aspire per MAUI, che fornisce service discovery e telemetria attraverso progetti mobile e backend. I contratti condivisi con System.Text.Json source generator assicurano la consistenza della serializzazione. Il vincolo chiave: la shared library deve targetizzare net10.0 (non TFM specifici per piattaforma) per rimanere portabile.

Come si differenzia HybridWebView da BlazorWebView in MAUI?

BlazorWebView ospita un'applicazione Blazor completa all'interno dell'app MAUI. I componenti Razor vengono renderizzati in un WebView incorporato, ma il runtime .NET viene eseguito nativamente (non tramite WebAssembly). HybridWebView è più leggero: carica contenuti HTML/CSS/JS statici e fornisce interop C#-to-JavaScript senza l'overhead del framework Blazor. La scelta dipende dal caso d'uso. BlazorWebView è adatto per team con componenti Blazor esistenti che desiderano riutilizzare il codice. HybridWebView è adatto per scenari dove contenuti web esistenti (dashboard, mappe, editor) necessitano di integrazione nativa senza un framework completo.

Altre domande di colloquio .NET su SharpSkill permettono di consolidare questi concetti con esercizi interattivi.

Inizia a praticare!

Metti alla prova le tue conoscenze con i nostri simulatori di colloquio e test tecnici.

Fonti

Cosa Ricordare per gli Sviluppatori .NET MAUI 10

  • .NET MAUI 10 è un rilascio LTS (supporto fino a novembre 2028) focalizzato su stabilità e performance, rendendolo una scelta affidabile per app cross-platform in produzione
  • Android 16 rende obbligatorio l'edge-to-edge: aggiungere SafeAreaEdges="Container" come stile globale in App.xaml per ripristinare il comportamento di .NET 9
  • Il XAML source generator (MauiXamlInflator=SourceGen) compila XAML a build-time, migliorando le performance di avvio e intercettando gli errori prima
  • ListView, TableView e MessagingCenter sono deprecati: migrare a CollectionView e WeakReferenceMessenger
  • L'architettura handler sostituisce i renderer Xamarin con mapper stateless, migliorando testabilità attraverso PropertyMapper e CommandMapper
  • I source generator di CommunityToolkit.Mvvm rimuovono la maggior parte del boilerplate MVVM: gli attributi [ObservableProperty] e [RelayCommand] sostituiscono le implementazioni manuali
  • HybridWebView in .NET 10 aggiunge chiamate JavaScript fire-and-forget, eventi di inizializzazione e intercettazione delle richieste per l'integrazione nativo-web
  • La preparazione ai colloqui dovrebbe concentrarsi su architettura handler vs. renderer, insidie dei lifetime DI nelle app a lunga esecuzione, compiled binding e trade-off tra HybridWebView e BlazorWebView
Sfida del giorno

Sapresti trovare il bug in .NET?

Uno snippet reale, un bug nascosto, un tentativo al giorno. Senza account per provare.

Anthony Fillion-Maillet

Scritto da

Anthony Fillion-Maillet

Fondatore di SharpSkill

Sviluppatore fullstack da oltre 10 anni. Guida SharpSkill e risponde di tutto ciò che vi viene pubblicato.

Aggiornato il 14 settembre 2026

Tag

#dotnet
#maui
#cross-platform
#mobile

Condividi

Articoli correlati