.NET MAUI in 2026: Cross-Platform Development Tutorial and Interview Questions
.NET MAUI tutorial covering cross-platform development with .NET 10, handlers, MVVM, HybridWebView, and essential interview questions for 2026.

.NET MAUI (Multi-platform App UI) has matured into a production-grade cross-platform framework with .NET 10. Released as a Long-Term Support version supported through November 2028, .NET MAUI 10 ships as a workload plus NuGet packages, delivering improved quality, performance, and new APIs like HybridWebView enhancements and SafeAreaEdges. This tutorial walks through building a cross-platform app, covers the architecture that makes MAUI work, and addresses the interview questions that hiring managers ask in 2026.
.NET 10 is a Long-Term Support release (supported through November 2028). MAUI 10 focuses on quality and performance over new UI controls, making it the most stable MAUI release to date. It now ships as a .NET workload and NuGet packages, enabling version pinning per project.
Setting Up a .NET MAUI 10 Project from Scratch
The fastest path to a running MAUI app starts with the .NET CLI. .NET 10 introduces an updated project template that includes .NET Aspire service defaults, connecting telemetry and service discovery out of the box.
# 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-androidThe single-project structure consolidates platform-specific code under a Platforms/ folder while sharing the rest. The MauiProgram.cs file serves as the composition root, where services, fonts, and handlers are registered.
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 follows the same pattern as ASP.NET Core. Singleton services persist for the app lifetime, Transient services are created per request, and Scoped services require caution because MAUI has no built-in scope concept like HTTP requests.
Handlers: The Architecture Behind Cross-Platform Rendering
MAUI replaced Xamarin.Forms renderers with a handler architecture. Handlers map each cross-platform control to its native counterpart through a thin abstraction layer. The key difference: handlers are stateless and decoupled from the virtual view, which makes them faster and easier to customize.
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, the Android Entry and Editor controls switched from AppCompatEditText to MauiAppCompatEditText, adding native support for the SelectionChanged event. The improved CollectionView and CarouselView handlers introduced in .NET 9 are now the default on iOS and Mac Catalyst, resolving long-standing stability issues.
Android 16 Edge-to-Edge: Breaking Change and Required Fix
Android 16 removes the opt-out mechanism for edge-to-edge display. Apps targeting API 36 must handle system bar insets properly, or content renders incorrectly. .NET 10 introduced a silent breaking change: in .NET 9, ContentPage respected system bars by default (Container behavior), but .NET 10 defaults to edge-to-edge (None).
Apps migrating from .NET 9 to .NET 10 may see content rendering under the status bar or navigation bar on Android 15+. The fix requires explicitly setting SafeAreaEdges to restore the previous behavior.
The fix involves adding a global implicit style to 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>The SafeAreaEdges enum provides granular control:
None: edge-to-edge content with no safe area paddingSoftInput: always pad for keyboardContainer: flow under keyboard, stay out of bars and notchDefault: platform default behaviorAll: obey all safe area insets
This approach uses the Window Insets API at runtime, making it compatible with Android 16 where manifest-level opt-outs no longer work.
MVVM with CommunityToolkit.Mvvm: Eliminating Boilerplate
The CommunityToolkit.Mvvm source generator eliminates roughly 80% of MVVM ceremony. No manual INotifyPropertyChanged implementation, no command wrappers: attributes drive the code generation.
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;
}
}
}The XAML binds directly to the generated properties and commands:
<!-- 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>The x:DataType attribute enables compiled bindings, which are faster than reflection-based bindings and produce compile-time errors when a binding path is wrong.
Ready to ace your .NET interviews?
Practice with our interactive simulators, flashcards, and technical tests.
XAML Source Generator in .NET 10
.NET MAUI 10 introduces a XAML source generator that compiles XAML at build time rather than parsing it at runtime. This improves startup performance and catches XAML errors during compilation.
To enable XAML source generation, add the property to your project file:
<PropertyGroup>
<MauiXamlInflator>SourceGen</MauiXamlInflator>
</PropertyGroup>.NET 10 Preview 5 also introduced implicit XML namespaces that eliminate boilerplate xmlns declarations. A GlobalXmlns.cs file can aggregate multiple namespaces:
[assembly: XmlnsDefinition(
"http://schemas.microsoft.com/dotnet/maui/global",
"MyApp.Views")]
[assembly: XmlnsDefinition(
"http://schemas.microsoft.com/dotnet/maui/global",
"MyApp.Controls")]With this setup, XAML files become cleaner:
<!-- Before -->
<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>
<!-- After (with global 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: Bridging Native and Web
HybridWebView enables embedding web content inside a MAUI app while maintaining bidirectional communication between C# and JavaScript. .NET 10 adds three capabilities: fire-and-forget JavaScript invocation, initialization events for platform-specific configuration, and web request interception.
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 thrown during InvokeJavaScriptAsync are now automatically forwarded to .NET as exceptions, eliminating silent failures. Web request interception allows modifying headers or supplying local responses:
webView.WebResourceRequested += (s, e) =>
{
if (e.Uri.ToString().Contains("api/secure"))
{
e.Handled = true;
e.SetResponse(200, "OK", "application/json", GetCustomStream());
}
};Deprecated APIs and Migration Path
.NET MAUI 10 deprecates several APIs. Applications using these should migrate to the recommended alternatives.
ListView and related cells: ListView, EntryCell, ImageCell, SwitchCell, TextCell, and ViewCell are deprecated. Use CollectionView instead, which has better performance and stability with the new iOS/Mac Catalyst handlers.
MessagingCenter: Made internal in .NET 10. Replace with WeakReferenceMessenger from CommunityToolkit.Mvvm.
Animation methods: FadeTo, RotateTo, ScaleTo, and similar methods are deprecated. Use the async equivalents: FadeToAsync, RotateToAsync, ScaleToAsync.
TableView: Deprecated in favor of CollectionView.
DisplayAlert/DisplayActionSheet: Replaced with DisplayAlertAsync and DisplayActionSheetAsync.
Migrating from Xamarin.Forms to .NET MAUI
Xamarin.Forms reached end of support in May 2024. Migrating to MAUI involves structural changes beyond a namespace swap. Here is a migration checklist based on real-world project conversions:
Xamarin.Forms has been unsupported since May 2024. Applications still running on Xamarin carry security and compatibility risks. .NET MAUI 10 (LTS, supported through November 2028) is the designated migration target.
- Project structure: Convert from platform-specific projects to the MAUI single-project model. Move shared code to the root, platform code under
Platforms/. - Namespaces: Replace
Xamarin.FormswithMicrosoft.Maui.ControlsandXamarin.EssentialswithMicrosoft.Maui.Essentials(now built into MAUI). - Renderers to Handlers: Custom renderers must be rewritten as handlers. The handler API is simpler but the mapping logic differs.
- Startup: Replace
App.xaml.csinitialization withMauiProgram.csusing the builder pattern. - NuGet packages: Many Xamarin-era packages have MAUI equivalents. Verify compatibility before upgrading.
- Dependency injection: MAUI uses
Microsoft.Extensions.DependencyInjectionnatively. Replace any third-party DI containers orDependencyServicecalls.
The .NET Upgrade Assistant automates parts of steps 1-2, but handlers (step 3) and business logic adjustments require manual work.
Top .NET MAUI Interview Questions for 2026
These questions reflect what hiring teams ask in 2026, based on the current .NET 10 ecosystem. For more C# and .NET interview preparation, see the complete .NET interview guide.
How does the MAUI handler architecture differ from Xamarin.Forms renderers?
Renderers in Xamarin.Forms were tightly coupled to both the cross-platform control and the native view, creating a bidirectional dependency. Handlers in MAUI are stateless mappers: they receive property change notifications and apply them to the native view through a mapper dictionary. This decoupling means handlers are easier to test, extend, and reuse. The PropertyMapper and CommandMapper dictionaries replace the OnElementPropertyChanged override pattern, making customization explicit rather than buried in switch statements.
What are the DI lifetime pitfalls specific to MAUI?
MAUI supports Singleton, Transient, and Scoped lifetimes, but Scoped behaves differently than in ASP.NET Core. There is no natural scope boundary (like an HTTP request). A Scoped service registered in MAUI acts like a Singleton unless custom scopes are created manually. Common mistakes: registering a ViewModel as Singleton when it holds page-specific state (stale data across navigation), or registering a database connection as Transient (connection pool exhaustion). The rule of thumb: ViewModels are Transient, services are Singleton, and Scoped is avoided unless the scope lifecycle is managed explicitly.
When answering DI questions, demonstrate understanding of how MAUI's lifecycle differs from ASP.NET Core's request-scoped model. Interviewers look for awareness of memory leaks and stale state issues specific to long-running mobile apps.
How does compiled binding differ from reflection-based binding in MAUI?
Reflection-based bindings resolve property paths at runtime using System.Reflection, which is slow and produces runtime errors for typos. Compiled bindings, enabled with x:DataType, resolve binding paths at compile time. The compiler generates direct property access code, skipping reflection entirely. This improves startup time, reduces memory allocations, and catches binding errors during build. In .NET 10, the new XAML source generator further optimizes this by compiling XAML at build time rather than parsing it at runtime.
What strategies exist for sharing code between a MAUI app and an ASP.NET Core backend?
The recommended approach uses a shared class library containing DTOs, validation logic, and business rules. Both the MAUI app and the ASP.NET Core backend reference this library. .NET 10 reinforces this pattern with the new .NET Aspire integration for MAUI, which provides service discovery and telemetry across mobile and backend projects. Shared contracts using System.Text.Json source generators ensure serialization consistency. The key constraint: the shared library must target net10.0 (not platform-specific TFMs) to remain portable.
How does HybridWebView differ from BlazorWebView in MAUI?
BlazorWebView hosts a full Blazor application inside the MAUI app. Razor components render into an embedded WebView, but the .NET runtime executes natively (not via WebAssembly). HybridWebView is lighter: it loads static HTML/CSS/JS content and provides C#-to-JavaScript interop without the Blazor framework overhead. The choice depends on the use case. BlazorWebView suits teams with existing Blazor components who want code reuse. HybridWebView suits scenarios where existing web content (dashboards, maps, editors) needs native integration without a full framework.
Practice more .NET interview questions on SharpSkill to solidify these concepts with interactive exercises.
Start practicing!
Test your knowledge with our interview simulators and technical tests.
Sources
- What's new in .NET MAUI for .NET 10 — official documentation covering all .NET 10 MAUI features
- .NET MAUI GitHub Releases — service release notes for 10.0.x versions
- Edge-to-Edge Is Now Mandatory in Android 16 — migration guide for Android 16 requirements
- MAUI GitHub Discussion #34171 — community feedback on .NET MAUI 10 stability
What .NET MAUI 10 Developers Should Remember
- .NET MAUI 10 is an LTS release (November 2028 support) focused on stability and performance, making it a reliable choice for production cross-platform apps
- Android 16 makes edge-to-edge mandatory: add
SafeAreaEdges="Container"as a global style in App.xaml to restore .NET 9 behavior - The XAML source generator (
MauiXamlInflator=SourceGen) compiles XAML at build time, improving startup performance and catching errors earlier - ListView, TableView, and MessagingCenter are deprecated: migrate to CollectionView and WeakReferenceMessenger
- The handler architecture replaces Xamarin renderers with stateless mappers, improving testability through
PropertyMapperandCommandMapper - CommunityToolkit.Mvvm source generators remove most MVVM boilerplate:
[ObservableProperty]and[RelayCommand]attributes replace manual implementations - HybridWebView in .NET 10 adds fire-and-forget JavaScript calls, initialization events, and request interception for native-web integration
- Interview preparation should focus on handler vs. renderer architecture, DI lifetime pitfalls in long-running apps, compiled bindings, and HybridWebView vs. BlazorWebView trade-offs
Can you spot the bug in .NET?
One real snippet, one hidden bug, one attempt a day. No account needed to try.

Written by
Anthony Fillion-MailletFounder of SharpSkill
Full-stack developer for over 10 years. Runs SharpSkill and answers for everything published here.
Updated on September 14, 2026
Tags
Share
Related articles

Advanced C# LINQ in 2026: Operators, Performance and Interview Questions
Master advanced LINQ operators, deferred execution, and performance optimization. Covers GroupBy, SelectMany, query optimization, and common interview questions for .NET developers.

.NET 10 in 2026: New Features, Native AOT and C# 14 for Interview Preparation
.NET 10 ships as a long-term support release with Native AOT improvements, C# 14 extension members, the field keyword, and file-based apps. A complete guide covering new features, performance gains, and interview-ready knowledge for .NET developers in 2026.

C# and .NET Interview Questions: Complete Guide 2026
The 25 most common C# and .NET interview questions. LINQ, async/await, dependency injection, Entity Framework and best practices with detailed answers.