Use compiled bindings, simplify and flatten layouts, reuse pages and ViewModels safely, enable AOT/IL trimming for Release, and verify improvements by profiling UI-thread stacks on real devices.
PermalinkUse compiled bindings, simplify and flatten layouts, reuse pages and ViewModels safely, enable AOT/IL trimming for Release, and verify improvements by profiling UI-thread stacks on real devices.
PermalinkShow a lightweight, useful UI immediately, defer non-essential services and heavy loads until after the first frame, and use skeletons or placeholders so users see immediate feedback.
PermalinkDevices differ in CPU, GPU, memory, and renderers. Test on low-, mid-, and high-tier devices and collect per-platform traces so you can prioritize fixes that matter to your users.
PermalinkDebug builds add useful checks and instrumentation that slow startup and rendering. For realistic performance testing, use Release builds with AOT/linker trimming; keep using hot-reload to iterate fast during development.
PermalinkDo not decode full-resolution bitmaps unless you need them. Provide appropriately sized assets, downsample or rescale at load time, load and cache images asynchronously (or use platform-native loaders) so the UI can show quickly.
PermalinkDeep nesting forces repeated measure/layout passes. Flatten the visual tree, prefer Grid or FlexLayout when appropriate, give frequent items fixed sizes, and reduce bindings inside rapidly updating visuals so the UI measures less and renders faster.
PermalinkWhen background work finishes, make your UI changes on the main thread, and use MainThread.InvokeOnMainThreadAsync for awaited updates (or the Begin/Invoke variants for fire-and-forget). That keeps UI updates safe and predictable.
PermalinkFrequent creation and disposal of large objects increases garbage-collection work and can cause brief pauses. To keep navigation feeling smooth, prefer reusing or pooling heavy resources (bitmaps, renderers) and cache resized copies so you do not repeat expensive work.
PermalinkUnsubscribe events, avoid capturing UI in long-lived closures, use WeakEventManager/WeakReference or IDisposable patterns for resource-holding ViewModels.
Unsubscribe example:
protected override void OnDisappearing()
{
base.OnDisappearing();
publisher.SomeEvent -= OnSomeEvent;
}
PermalinkThey allocate native resources; instantiate lazily and dispose/unload in OnDisappearing.
PermalinkSlow scrolling usually means each row is expensive to measure or render. Make templates lighter, prefer fixed item sizes or set ItemSizingStrategy=”MeasureFirstItem” so items are not measured repeatedly, enable recycling by using CollectionView, and downsample or cache images and heavy controls so the UI can reuse views smoothly.
PermalinkDo not block OnAppearing. Start the work, keep the task reference for cancellation/observation, and update the UI when the task completes.
PermalinkBecause the UI thread is being blocked: synchronous I/O, heavy CPU work, .Result/.Wait(), expensive constructors or property getters, large image decoding, or synchronous DI resolution can all run on the UI thread and prevent the first frame from rendering.
Fixes: make I/O truly async (await network/file calls), offload CPU-bound work to a background thread, start async loads in OnAppearing without blocking the method, and show incremental UI (placeholders) while data loads. Avoid .Result/.Wait() and async void (except event handlers); use ConfigureAwait(false) only inside library code.
PermalinkFor profiling .NET MAUI navigation, pick the tool that matches where you test and what you need: