- Lazy Service Resolution: Defer instantiation of heavy services to improve initial app responsiveness.
// MauiProgram.cs registration
builder.Services.AddTransient<HeavyService>();
builder.Services.AddTransient<Lazy<IHeavyService>>(p =>
new Lazy<IHeavyService>(() => p.GetRequiredService<HeavyService>()));
// Consumption in ViewModel
public MainViewModel(Lazy<IHeavyService> lazyService) => _service = lazyService;
public void OnLoaded() => _service.Value.Initialize(); - Compiled Bindings: Use
x:DataTypeto bypass reflection and catch binding errors at compile-time.
<ContentPage xmlns:vm="clr-namespace:MyApp.ViewModels" x:DataType="vm:MainViewModel">
<Label Text="{Binding UserName}" />
</ContentPage>
- Custom Handlers: Use Handlers over legacy Renderers to keep the visual tree slim and reduce mapping overhead.
public partial class MyEntryHandler : Microsoft.Maui.Handlers.EntryHandler {
protected override void ConnectHandler(Microsoft.Maui.Platform.MauiEditText platformView) {
base.ConnectHandler(platformView);
}
}- Dependency Injection Scoping: Use
AddSingletonfor state-heavy services andAddTransientfor lightweight ViewModels to manage memory lifecycle effectively.
- Layout Flattening: Minimize visual tree depth. A single
Gridis significantly faster than nestedStackLayoutsduring Measure/Arrange passes.
<Grid ColumnDefinitions="100, *" RowDefinitions="Auto, Auto">
<Image Grid.RowSpan="2" Source="icon.png" />
<Label Grid.Column="1" Text="Header" />
<Label Grid.Column="1" Grid.Row="1" Text="Description" />
</Grid>
- UI Virtualization: Use
CollectionViewwith incremental loading for large datasets to recycle native UI elements.
<CollectionView ItemsSource="{Binding Items}"
RemainingItemsThreshold="5"
RemainingItemsCommand="{Binding LoadMoreCommand}">
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="vm:ItemVM">
<Grid>...</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
- Resource Optimization: Define common styles in
App.xamlto avoid redundant object instantiation per page. - Stop Overdraw: Use
IsVisibleinstead ofOpacity="0"to ensure the rendering engine ignores the element entirely.
- Device Capability Detection: Gracefully degrade visuals for older hardware.
bool isLowEnd = DeviceInfo.Current.Platform == DevicePlatform.Android && DeviceInfo.Current.Version.Major < 11;
if (isLowEnd) {
// Disable shadows or heavy animations
MyVisualElement.Shadow = null;
}- Adaptive Layouts: Leverage platform-specific values for desktop vs. mobile.
<Button Text="Submit"
WidthRequest="{OnPlatform WinUI=250, Android=-1}"
FontSize="{OnIdiom Phone=12, Desktop=18}" />
- Memory Leak Prevention: Unsubscribe from events or use
WeakReferenceMessengerto allow the GC to reclaim memory.
// Cleanup in OnDisappearing
protected override void OnDisappearing() {
base.OnDisappearing();
WeakReferenceMessenger.Default.Unregister<MyMessage>(this);
BindingContext = null;
}- Batch Collection Updates: Use
ObservableRangeCollectionto fire a single UI notification for bulk changes.
// Prevents 100+ UI refreshes (one per item)
Items.AddRange(newLargeList); - Asynchronous Offloading: Never block the UI thread; use
Task.Runfor heavy computational logic.
public async Task LoadAsync() {
IsBusy = true;
var data = await Task.Run(() => _processor.HeavyCompute());
Items.ReplaceRange(data);
IsBusy = false;
}- ValueTask for Sync-Path Methods: Reduce heap allocations for methods that frequently return cached data.
public ValueTask<string> GetDataAsync() {
return _cache != null ? new ValueTask<string>(_cache) : new ValueTask<string>(FetchAsync());
}- Context Preservation: Use
.ConfigureAwait(false)in library and service layers to avoid unnecessary thread switching.
Place this in the solution root to apply performance-centric build settings globally.
<Project>
<PropertyGroup>
<NetMauiContextCachingEnabled>true</NetMauiContextCachingEnabled>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<PublishTrimmed>true</PublishTrimmed>
<TrimMode>full</TrimMode>
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
<RunAOTCompilation Condition="'$(TargetFramework)' == 'net8.0-android'">true</RunAOTCompilation>
<AndroidEnableProfiledAot>true</AndroidEnableProfiledAot>
<AndroidStripILAfterAOT>true</AndroidStripILAfterAOT>
<EnableLLVM Condition="'$(TargetFramework)' == 'net8.0-android'">true</EnableLLVM>
<MtouchLink>SdkOnly</MtouchLink>
<RuntimeIdentifier Condition="'$(TargetFramework)' == 'net8.0-ios'">ios-arm64</RuntimeIdentifier>
</PropertyGroup>
</PropertyGroup>
</Project>
| Optimization | Startup | Fluidity | Memory | Priority |
|---|---|---|---|---|
| Compiled Bindings | Low | High | Medium | Critical |
| Grid vs Stack | Medium | High | Low | High |
| AOT Compilation | High | Low | Low | High |
| Lazy Services | High | Low | Medium | Medium |
| ObservableRange | Low | High | Low | Medium |