In this blog post, we'll share seven tips to help you create high-speed .NET MAUI applications and deliver user experiences that amaze. The following tips will leverage standard .NET MAUI options alongside capabilities included in our .NET MAUI product line.
1. Test Your Project in Release Configuration
While switching from the Debug to Release configuration may not be that noticeable in desktop projects (WinFroms, WPF), this option offers huge performance benefits in .NET MAUI applications.
![Switching to Release Configuration in Visual Studio](https://community.devexpress.com:443/blogs/mobile/20231907-MAUI-Performance-Tips/MAUI-Release-On.png)
Changing configuration achieves three main things:
- The Linker starts using the trimming mechanism to reduce the size of deployed assemblies. The Linker inspects source code and removes all unused branches from the assemblies. You can learn more about trimming in the following article: Trim self-contained deployments and executables.
- The compiler performs optimizations when generating intermediate language (IL) code.
- Visual Studio Debugger is detached, which means you won’t see any logs in the Output window during app execution. Detaching the debugger helps reduce costs produced through communication between the app and tracing mechanism.
2. Use DXCollectionView Instead of Standard CollectionView
Although both collection views use virtualization mechanisms, DXCollectionView includes additional optimizations to maintain excellent scrolling speed even when you use complex item templates.
One of the optimizations is called Cascade Updates. When users rapidly scroll DXCollectionView, they often don't have sufficient time to read each item as it appears on screen. DXCollectionView uses this reality and doesn’t draw all items simultaneously: it loads them one by one and plays an animation as data is retrieved. This feature is extremely helpful if you need to display complex content for DXCollectionView items. The following animation demonstrates the difference in scrolling speed between the standard CollectionView and DevExpress DXCollectionView.
In usage scenarios with simpler item templates, you may disable Cascade Updates via the AllowCascadeUpdate property - scrolling experience should remain perfect.
GitHub Example: Replicate a Single-Column Kanban View
Our recent release (v23.1), includes new scrolling optimizations for the DXCollectionView and Data Grid. The optimization rate varies depending on target device, settings and other factors. We achieved the most significant results in the Data Grid on iOS, where vertical scrolling is up to 70% faster than previous versions. Therefore, if you are using v22.2 or older, you can consider updating to v23.1 to speed up scroll operations.
3. Call DevExpress Initializers on Application Startup
When an application shows a control for the first time, .NET MAUI loads assemblies, parses XAML resources, and calls static constructors. These operations may cause a noticeable delay when users navigate from one view to another. DevExpress components give you a way to enable/execute all initialization steps when the application is being loaded. To do this, simply call Initializer.Init in the CreateMauiApp method:
public static MauiApp CreateMauiApp() {
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp()
.UseDevExpress();
DevExpress.Maui.Charts.Initializer.Init();
DevExpress.Maui.CollectionView.Initializer.Init();
DevExpress.Maui.Controls.Initializer.Init();
DevExpress.Maui.Editors.Initializer.Init();
DevExpress.Maui.DataGrid.Initializer.Init();
DevExpress.Maui.Scheduler.Initializer.Init();
return builder.Build();
According to our tests, moving initialization to the CreateMauiApp method doesn’t materially affect application startup, but significantly decreases view switching time.
4. Follow Standard Mobile UI Patterns to Simplify Layouts
This section is especially important if previously worked on a desktop application. Mobile applications rarely require sophisticated interfaces and it might be challenging to rethink the user flow to eliminate desktop UI patterns. Doing so, however, will help you achieve better performance and overall user experience.
In general, you don’t need to fit all information on one small mobile screen. This may confuse users and make touch interactions more difficult. A better option is to provide more space for UI elements and display additional information upon request.
One technique is to logically split information and user tasks across multiple pages. For example, if you are implementing CRUD operations in a list, you can create the following pages:
- A main view with CollectionView with search and navigation.
- A detail view to display more information about a clicked Item.
- An editing view to allow users modify or create items.
GitHub Example: CollectionView for .NET MAUI - Incorporate CRUD Operations
Our DXCollectionView and Data Grid offer APIs to help you implement this flow. You can use default detail/editing views or specify custom pages. Once you do, DXCollectionView/DataGrid will automatically navigate to them as needed. BindingContext in these pages contain information and commands that may require custom logic.
Another technique is to display detail information on the same page - when a user selects an element. Our Bottom Sheet is a great choice for such a usage scenario.
GitHub Example: BottomSheet with Maps
GitHub Example: Master-Detail View with BottomSheet
5. Use the Shimmer Control for Data Loaded Asynchronously
When users switch a view, the application often starts loading data. You can maintain UI responsiveness during this process and display an element informing users about load operations. While you can use a simple activity indicator, it doesn’t give users an idea of the UI structure. You may find it more intuitive to use DevExpress ShimmerControl to help users understand where UI elements are located. This allows users to decide with what part of the UI they will be interacting once loading completes.
6. Load Large Data Sources on Demand
In large lists, users typically don't need to access all data records simultaneously. They usually need to view either the most relevant data items or items that meet a certain filter criterion.
The first technique implies the following flow:
- You sort your data items based on relevance (update date, item price etc.),
- You load a small initial portion of data.
- You load more items when a user scrolls to the end of the screen.
The simplest way to implement this flow is to use Infinite Scrolling available in DXCollectionView and Data Grid:
To achieve this, simply set IsLoadMoreEnabled to true and handle the LoadMore event or LoadMoreCommand command:
<dxcv:DXCollectionView IsRefreshing="{Binding IsLoading, Mode=TwoWay}"
IsLoadMoreEnabled="True"
LoadMoreCommand="{Binding LoadMoreCommand}">
<!--...-->
</dxcv:DXCollectionView>
public class MainViewModel {
public ICommand LoadMoreCommand { get; set; }
public MainViewModel() {
//...
LoadMoreCommand = new Command(LoadMore, CanLoadMore);
}
public void LoadMore() {
//Load data from a service
}
}
GitHub Example: CollectionView for .NET MAUI - Infinite Scrolling
Another usage scenario is accessing records based on search text, item values and other filter conditions. You can request rows from the database based on a user filter to minimize the amount of loaded records. For example, if you are using Entity Framework, you can incorporate a user filter into a LINQ expression. Please refer to the following Microsoft help topic for additional information: Expressions in LINQ to Entities Queries
7. Use DataType to Enable Compiled Bindings
As you may know, default .NET MAUI bindings use Reflection the access properties by their names. This isn’t cost-effective and may affect views with many bindings.
.NET MAUI offers a mechanism that allows you to resolve bindings at compile time. It’s sufficient to set the x:DataType attribute to the type of object stored in BindingContext. For example, if you bound DXCollectionView to a collection of contacts, ItemTemplate will contain an instance of the Contact class in its BindingContext. Therefore, you need to set x:DataType to “model:Contact” where “model” is the namespace where the Contact class is defined:
<dxcv:DXCollectionView.ItemTemplate>
<DataTemplate x:DataType="model:Contact">
<Label Text="{Binding FirstName}"/>
</DataTemplate>
</dxcv:DXCollectionView.ItemTemplate>
Let's take a brief look at how compiled bindings compare to classic bindings:
- Bindings with property change notifications are resolved eight times faster
- Bindings without property-change notifications (i.e. OneTime bindings) are resolved approximately twenty times faster
- Setting BindingContext on a binding with property change notifications is approximately five times faster
- Setting BindingContext on a binding without property change notifications is approximately seven times faster
Please refer to the following Microsoft help topic to learn more: Compiled bindings.
Free DevExpress Products - Get Your Copy Today
The following free DevExpress product offers remain available. Should you have any questions about the free offers below, please submit a ticket via the
DevExpress Support Center at your convenience. We'll be happy to follow-up.