Yes, animations that force layout are expensive. Prefer transformations that are GPU-accelerated (translate or scale) and avoid layout-affecting property animations during navigation.
PermalinkYes, animations that force layout are expensive. Prefer transformations that are GPU-accelerated (translate or scale) and avoid layout-affecting property animations during navigation.
PermalinkAny 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");
PermalinkSynchronous I/O or CPU work in constructors blocks the first frame. Move heavy work into an async initializer or start loading in OnAppearing and show incremental UI updates.
PermalinkGoToAsync 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 */ }
PermalinkSimplify UIs, use compiled bindings, enable virtualization, defer heavy-native controls, avoid heavy work in constructors or OnAppearing, and prefer GPU-friendly transforms for animations.
PermalinkUse dotnet-trace or dotnet-counters, PerfView, Visual Studio Profiler, Android Systrace, and Xcode Instruments. Capture CPU samples and UI-thread call stacks to find the blocking work.
PermalinkMAUI 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.
PermalinkDifferent CPUs/GPUs, memory, and platform renderers cause different behavior. Profile on representative devices and collect platform-specific traces.
PermalinkYes, resolving a lot of services or expensive services synchronously at navigation time slows rendering. Use Lazy<T>, Func<T>, or factories to defer expensive resolves until you need them.
PermalinkOften due to race conditions, incorrect absolute (//route) instead of relative routes, or duplicate registrations. Use explicit absolute routes when needed and avoid overlapping navigations.
PermalinkA 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
}
PermalinkAvoid .Wait() and .Result. Prefer async Task (not async void, except for event handlers). Use ConfigureAwait(false) inside libraries so callers do not capture the UI context accidentally.
PermalinkStutter often comes from layout recalculations, heavy list rendering, image decoding on the UI thread, or GC pauses. Downsample images, load them asynchronously, flatten visual trees, and enable virtualization in lists.
PermalinkTypical 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");
PermalinkBecause 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.
PermalinkNavigation 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