.NET MAUI FAQ - Navigation

Find answers for the most frequently asked questions
Expand All Collapse All

Any UI update from a background thread must run on the main thread. Prefer MainThread.InvokeOnMainThreadAsync when you need to await completion.

MainThread example: 

await MainThread.InvokeOnMainThreadAsync(() => label.Text = "Updated");
Permalink

GoToAsync has no built-in CancellationToken. You can time out your await with Task.WaitAsync (recent .NET), but that cancels only your wait; it does not abort the underlying navigation unless that code observes cancellation. For true cancellation, make your page/ViewModel operations cancellation-aware.

Time-out example:

using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5)); 

try 

{ 

    await Shell.Current.GoToAsync("route").WaitAsync(cts.Token); 

} 

catch (OperationCanceledException) { /* timeout handling */ }
Permalink

MAUI Shell does not cache pages automatically. Cache pages only if creation cost is high and you can manage the lifecycle (unsubscribe events, free resources). If you cache, implement cleanup in OnDisappearing and consider IDisposable on resource-holding ViewModels.

Permalink

A blank screen usually means async initialization is still running or an exception occurred. Log exceptions, verify Page.Content, and show a lightweight placeholder while background initialization runs.

Start async work without blocking rendering:

protected override void OnAppearing()
{
    base.OnAppearing();
    _loadTask = LoadDataAsync(); // do not await here
}
Permalink

Typical causes: unregistered or duplicate routes, wrong absolute versus relative URIs, passing complex objects via query strings, concurrent GoToAsync calls, or exceptions during page or ViewModel construction. Register routes and pass IDs or use a shared service to hand over complex data.

Register and navigate:

Routing.RegisterRoute("details", typeof(DetailsPage));
await Shell.Current.GoToAsync("details?itemId=123");
Permalink

Because something heavy ran on the UI thread: constructors, synchronous I/O, .Result or .Wait(), long event handlers, or expensive property getters. Make everything asynchronous (async/await), avoid blocking calls, and use ConfigureAwait(false) in library code that does not need the UI context.

Permalink

Navigation can be slow when the page or ViewModel does heavy work during construction, DI resolves expensive services, fonts or images decode for the first time, or native controls initialize. Profile first, then defer or move heavy work off the UI thread. Use compiled bindings (x:DataType) to reduce binding overhead.

Offload synchronous CPU work:

Var result = await Task.Run(() => DoHeavyWork());

Permalink

Share with

Couldn't find the FAQs you're looking for?

Please submit your question and answer.