Your First MAUI App
The fastest way to build a first MAUI app is dotnet new maui -n HelloMaui, which scaffolds the default 'click counter' template: a MainPage.xaml with a Label and a Button, and MainPage.xaml.cs with an OnCounterClicked handler that increments a private field and updates the Label's Text. Running it with dotnet build -t:Run -f net8.0-android (or pressing F5 in Visual Studio with an Android emulator or Windows Machine selected as the debug target) deploys and launches the app, giving you a working baseline to modify before writing anything custom.
Cricket analogy: Scaffolding with dotnet new maui is like a net session where the coach sets up stumps and a bowling machine before you've even picked up a bat, giving you a working baseline (the click-counter template) to start practicing from immediately.
Wiring Up Events and Modifying the UI
The default template's OnCounterClicked event handler shows the fundamental pattern used throughout MAUI: a XAML control's Clicked (or Tapped, TextChanged, etc.) attribute references a method in the code-behind by name, and that method runs on the UI thread where it can safely mutate control properties directly (CounterBtn.Text = $"Clicked {count} times"). Extending this into something more useful — say, adding an Entry for user input and a second Button that navigates to a details page — means adding controls to the XAML, wiring their events or bindings, and, once the app grows beyond a page or two, registering additional routes in AppShell.xaml so Shell.Current.GoToAsync("details") can navigate between pages.
Cricket analogy: Wiring Clicked="OnCounterClicked" to a method is like a fielding call ('mine!') triggering a specific pre-drilled response from a fielder, where the XAML attribute names exactly which code-behind method fires when the button is pressed.
// MainPage.xaml.cs
public partial class MainPage : ContentPage
{
int count = 0;
public MainPage()
{
InitializeComponent();
}
private void OnCounterClicked(object sender, EventArgs e)
{
count++;
CounterBtn.Text = count == 1
? "Clicked 1 time"
: $"Clicked {count} times";
SemanticScreenReader.Announce(CounterBtn.Text);
}
private async void OnGoToDetailsClicked(object sender, EventArgs e)
{
await Shell.Current.GoToAsync($"details?count={count}");
}
}Debugging and Hot Reload
MAUI supports XAML Hot Reload, which pushes XAML markup changes to a running app instance without a full rebuild — useful for adjusting layout, spacing, or colors while the app stays running on the emulator or device — though changes to code-behind C# logic still require a rebuild since Hot Reload only applies to XAML. Setting breakpoints in code-behind or ViewModel code works exactly like any .NET debugging session (step-over, watch windows, the Immediate window), and the Output/Debug window's platform-specific logs (logcat filtering for Android, the Xcode-equivalent device log for iOS) are essential when a native crash occurs outside managed code that the .NET debugger alone can't explain.
Cricket analogy: XAML Hot Reload updating layout live is like adjusting a fielding position mid-over without stopping play, while a code-behind change needing a rebuild is like a bowling action change that requires leaving the field to be re-certified first.
Press Ctrl+Shift+Alt+Enter (Windows) or Cmd+Alt+Enter (Mac) in Visual Studio while debugging to force an immediate XAML Hot Reload apply if a change doesn't trigger automatically.
Hot Reload cannot apply structural changes like adding a brand-new named control that code-behind references (x:Name="NewButton" used in a new event handler) — those require a full rebuild, since the generated .g.cs partial class fields are only regenerated at build time.
dotnet new maui -n <ProjectName>scaffolds a runnable click-counter starter app with a Label and Button.dotnet build -t:Run -f net8.0-android(or F5 in Visual Studio) builds, deploys, and launches the app on an emulator or device.- XAML's Clicked attribute wires a control's event directly to a named method in the paired code-behind class.
- Growing beyond one page means adding routes in AppShell.xaml and using Shell.Current.GoToAsync to navigate.
- XAML Hot Reload applies markup changes to a running app instantly but does not apply C# code-behind logic changes.
- Adding a new named control that code-behind references requires a full rebuild, not just Hot Reload.
- Platform-specific device logs (Android logcat, iOS device console) are essential for diagnosing native crashes the .NET debugger can't explain.
Practice what you learned
1. What does the default `dotnet new maui` template scaffold?
2. How does a XAML Button trigger a method in the code-behind file?
3. What is a key limitation of XAML Hot Reload?
4. Which method is used to navigate to another page registered as a route in AppShell.xaml?
5. Which command runs a MAUI app on the Android target from the command line?
Was this page helpful?
You May Also Like
XAML Basics
The essentials of MAUI's XAML syntax — layouts, controls, data binding, and markup extensions — for declaring a page's UI separately from its code-behind logic.
The MAUI Project Structure
A tour of a default .NET MAUI project's folders and startup files — Platforms/, Resources/, MauiProgram.cs, App.xaml, and AppShell.xaml — and what each one controls.
What Is .NET MAUI?
An introduction to .NET MAUI, Microsoft's cross-platform UI framework for building native Android, iOS, Windows, and macOS apps from a single C#/XAML codebase.
Setting Up the MAUI Environment
A practical walkthrough of installing the .NET SDK, the MAUI workload, and the Android, iOS, and Windows prerequisites needed to build MAUI apps.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics