Skip to main content

.NET MAUI Tutorial 2026: Build Cross-Platform Apps in C#

Learn .NET MAUI in 2026 to build iOS, Android, Windows & Mac apps from one C# codebase. Start this cross-platform tutorial with code examples today.

.NET MAUI (Multi-platform App UI) is Microsoft's framework for building native iOS, Android, Windows, and macOS apps from a single C# codebase. If you've ever wanted to ship a mobile app without learning Swift, Kotlin, and Win32 separately, this .NET MAUI tutorial for 2026 is your starting point. In this guide you'll learn what .NET MAUI is, why it matters for cross-platform app development in C#, and how to build your first working app — with runnable code examples and the best practices senior engineers actually use in production.

What Is .NET MAUI and Why Use It in 2026?

.NET MAUI is the evolution of Xamarin.Forms, fully integrated into the modern .NET runtime. With one project and one language — C# — you target four platforms. The framework compiles to native UI controls on each device, so a button on iOS renders as a real UIButton and on Android as a real MaterialButton. You aren't shipping a web view; you're shipping native performance.

Here's why .NET MAUI dominates cross-platform app development in C# in 2026:

  • One codebase, four platforms: Write your UI, business logic, and data access once. Microsoft estimates 90%+ code reuse across targets.
  • Native performance and look: Unlike hybrid frameworks, MAUI maps to platform-native controls through handlers.
  • Single project system: Fonts, images, splash screens, and app icons live in one place and are resized automatically per platform.
  • Hot Reload: Edit XAML or C# and see changes live without rebuilding.
  • .NET ecosystem: Use NuGet, dependency injection, async/await, and the same libraries you use on the server.

For .NET developers in the USA, UK, Canada, and Australia, MAUI means you can extend your existing C# skills into mobile and desktop without onboarding an entirely new tech stack.

.NET MAUI vs Xamarin: What Changed?

If you searched "MAUI vs Xamarin," here's the short answer: Xamarin reached end of support in May 2024, and .NET MAUI is its official successor. The key differences:

  • Single project: Xamarin required separate head projects per platform. MAUI uses one unified project with multi-targeting.
  • Handlers instead of renderers: MAUI's handler architecture is decoupled and faster, making custom controls far easier to write.
  • Modern .NET: MAUI runs on the latest .NET (.NET 9/10 in 2026), giving you performance improvements, AOT compilation, and trimming for smaller app sizes.

If you maintain a legacy Xamarin.Forms app, migrating to MAUI is the recommended path in 2026 — security updates and new OS support only land in MAUI.

How to Set Up Your First .NET MAUI App

To get started with .NET MAUI, install the latest .NET SDK and the MAUI workload. Open a terminal and run:

// Install the MAUI workload
dotnet workload install maui

// Create a new MAUI app
dotnet new maui -n HelloMaui

// Build and run on Windows
cd HelloMaui
dotnet build -t:Run -f net10.0-windows10.0.19041.0

In Visual Studio 2026, you can simply choose File → New → .NET MAUI App and pick your target device from the debug dropdown (Android emulator, iOS simulator, Windows machine). For iOS builds you'll need a Mac on the network or a cloud Mac build agent, since Apple requires its toolchain for compilation and signing.

Understanding the Project Structure

A new MAUI project gives you a few key files. MauiProgram.cs is your app's entry point and where you configure dependency injection. App.xaml holds global resources and styles. The Platforms/ folder contains the small amount of platform-specific code you'll occasionally need.

Building Your First UI with XAML and C#

.NET MAUI uses XAML — a declarative markup language — to define UI, with C# handling logic. Let's build a simple counter app. Here's the XAML for the main page:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="HelloMaui.MainPage">
    <VerticalStackLayout Spacing="20" Padding="30" VerticalOptions="Center">
        <Label x:Name="CounterLabel"
               Text="Current count: 0"
               FontSize="24"
               HorizontalOptions="Center" />
        <Button Text="Click Me"
                Clicked="OnCounterClicked"
                HorizontalOptions="Center" />
    </VerticalStackLayout>
</ContentPage>

And the C# code-behind that handles the button click:

namespace HelloMaui;

public partial class MainPage : ContentPage
{
    private int _count = 0;

    public MainPage()
    {
        InitializeComponent();
    }

    private void OnCounterClicked(object sender, EventArgs e)
    {
        _count++;
        CounterLabel.Text = $"Current count: {_count}";
        SemanticScreenReader.Announce(CounterLabel.Text); // accessibility
    }
}

This is the basics — but tightly coupling UI and logic in code-behind doesn't scale. For real apps, you'll want the MVVM pattern.

Best Practices: Using MVVM for Cross-Platform Apps in C#

The Model-View-ViewModel (MVVM) pattern is the gold standard for .NET MAUI development. It separates your UI (View) from your logic and state (ViewModel), making your code testable and maintainable. The CommunityToolkit.Mvvm NuGet package removes nearly all the boilerplate using source generators.

Here's a clean ViewModel using the toolkit:

using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;

namespace HelloMaui.ViewModels;

public partial class CounterViewModel : ObservableObject
{
    [ObservableProperty]
    private int count;

    [ObservableProperty]
    private string message = "Current count: 0";

    [RelayCommand]
    private void Increment()
    {
        Count++;
        Message = $"Current count: {Count}";
    }
}

The [ObservableProperty] attribute generates the full property with change notification, and [RelayCommand] generates an ICommand automatically. Bind it in XAML like this:

<VerticalStackLayout Spacing="20" Padding="30" VerticalOptions="Center">
    <Label Text="{Binding Message}" FontSize="24" />
    <Button Text="Click Me" Command="{Binding IncrementCommand}" />
</VerticalStackLayout>

Wire the ViewModel up through dependency injection in MauiProgram.cs — this is the modern, recommended approach:

public static MauiApp CreateMauiApp()
{
    var builder = MauiApp.CreateBuilder();
    builder
        .UseMauiApp<App>()
        .ConfigureFonts(fonts =>
        {
            fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
        });

    // Register ViewModels and Pages for DI
    builder.Services.AddSingleton<CounterViewModel>();
    builder.Services.AddTransient<MainPage>();

    return builder.Build();
}

Why this matters: By injecting the ViewModel rather than newing it up, you can swap in mock services for unit tests and keep platform-specific implementations behind interfaces. This is how production teams structure C# mobile app development at scale.

Calling APIs and Handling Data

Most real apps fetch data from a backend. .NET MAUI uses the standard HttpClient with async/await, just like any .NET app. Always register HttpClient via IHttpClientFactory to avoid socket exhaustion:

public class WeatherService
{
    private readonly HttpClient _http;

    public WeatherService(HttpClient http) => _http = http;

    public async Task<Forecast?> GetForecastAsync(string city)
    {
        try
        {
            return await _http.GetFromJsonAsync<Forecast>(
                $"https://api.example.com/weather/{city}");
        }
        catch (HttpRequestException ex)
        {
            // Log and handle network failure gracefully
            Console.WriteLine($"Request failed: {ex.Message}");
            return null;
        }
    }
}

public record Forecast(string City, double TempCelsius, string Summary);

Notice the try/catch around the network call. On mobile, connectivity is unreliable — always assume requests can fail and design your UI to show a friendly error or retry option.

Common Pitfalls in .NET MAUI Development

Even experienced developers hit these issues. Avoid them from the start:

  • Blocking the UI thread: Never call .Result or .Wait() on async code. It freezes the app and can deadlock. Always await.
  • Updating UI from a background thread: Marshal back to the main thread with MainThread.BeginInvokeOnMainThread(() => { ... }) when updating bound properties from a non-UI thread.
  • Memory leaks from event handlers: Unsubscribe from events and avoid strong references between long-lived ViewModels and Pages, or use weak event patterns.
  • Ignoring platform differences: Test on real iOS and Android devices, not just Windows. Safe areas, back-button behavior, and permissions differ.
  • Oversized images: Use the single-project image resizing and SVG sources rather than shipping huge PNGs that bloat your app and slow startup.

Advanced .NET MAUI: Performance and AOT

For senior engineers optimizing production apps, .NET MAUI in 2026 supports Native AOT compilation on iOS and Mac Catalyst, plus full trimming. These reduce app size and dramatically improve startup time. Enable trimming and check for warnings in your .csproj:

<PropertyGroup Condition="'$(Configuration)' == 'Release'">
    <PublishTrimmed>true</PublishTrimmed>
    <TrimMode>full</TrimMode>
    <MtouchLink>Full</MtouchLink>
</PropertyGroup>

Other advanced techniques include using CollectionView with virtualization instead of ListView, compiled bindings (x:DataType) to avoid reflection-based binding overhead, and the handler architecture to customize native controls without subclassing. Compiled bindings alone can deliver a measurable performance boost in data-heavy screens.

Conclusion: Key Takeaways for .NET MAUI in 2026

.NET MAUI is the most productive way to build cross-platform apps in C# in 2026, letting you ship native iOS, Android, Windows, and macOS apps from one codebase. Here are the takeaways to remember:

  • One codebase, native results: .NET MAUI compiles to real native controls — not a web view — across all four platforms.
  • Use MVVM with CommunityToolkit.Mvvm: It keeps your code testable, maintainable, and free of boilerplate.
  • Lean on dependency injection for ViewModels and services to structure apps like the pros.
  • Respect the platform: Always await async work, marshal UI updates to the main thread, and test on real devices.
  • Optimize for release with trimming, AOT, compiled bindings, and virtualized collections.

If you're coming from Xamarin or starting fresh, now is the time to learn .NET MAUI. Start with the counter app above, refactor it to MVVM, then connect a real API — you'll have the foundation for production C# mobile app development. Bookmark this .NET MAUI tutorial and build something this week.

About csharp-coder.com
Your go-to resource for C#, .NET, and modern software development. Follow along for daily tutorials, tips, and real-world examples.

Comments

Popular posts from this blog

Angular 14 CRUD Operation with Web API .Net 6.0

How to Perform CRUD Operation Using Angular 14 In this article, we will learn the angular crud (create, read, update, delete) tutorial with ASP.NET Core 6 web API. We will use the SQL Server database and responsive user interface for our Web app, we will use the Bootstrap 5. Let's start step by step. Step 1 - Create Database and Web API First we need to create Employee database in SQL Server and web API to communicate with database. so you can use my previous article CRUD operations in web API using net 6.0 to create web API step by step. As you can see, after creating all the required API and database, our API creation part is completed. Now we have to do the angular part like installing angular CLI, creating angular 14 project, command for building and running angular application...etc. Step 2 - Install Angular CLI Now we have to install angular CLI into our system. If you have already installed angular CLI into your system then skip this step.  To install angular CLI ope...

Angular 14 : 404 error during refresh page after deployment

In this article, We will learn how to solve 404 file or directory not found angular error in production.  Refresh browser angular 404 file or directory not found error You have built an Angular app and created a production build with ng build --prod You deploy it to a production server. Everything works fine until you refresh the page. The app throws The requested URL was not found on this server message (Status code 404 not found). It appears that angular routing not working on the production server when you refresh the page. The error appears on the following scenarios When you type the URL directly in the address bar. When you refresh the page The error appears on all the pages except the root page.   Reason for the requested URL was not found on this server error In a Multi-page web application, every time the application needs to display a page it has to send a request to the web server. You can do that by either typing the URL in the address bar, clicking on the Me...

Send an Email via SMTP with MailKit Using .NET 6

How to Send an Email in .NET Core This tutorial show you how to send an email in .NET 6.0 using the MailKit email client library. Install MailKit via NuGet Visual Studio Package Manager Console: Install-Package MailKit How to Send an HTML Email in .NET 6.0 This code sends a simple HTML email using the Gmail SMTP service. There are instructions further below on how to use a few other popular SMTP providers - Gmail, Hotmail, Office 365. // create email message var email = new MimeMessage(); email.From.Add(MailboxAddress.Parse("from_address@example.com")); email.To.Add(MailboxAddress.Parse("to_address@example.com")); email.Subject = "Email Subject"; email.Body = new TextPart(TextFormat.Html) { Text = "<h1>Test HTML Message Body</h1>" }; // send email using var smtp = new SmtpClient(); smtp.Connect("smtp.gmail.com", 587, SecureSocketOptions.StartTls); smtp.Authenticate("[Username]", "[Password]"); smtp.Se...