MAUI Patterns API
Explore the architectural patterns and design principles recommended for building robust and maintainable .NET MAUI applications.
Common Architectural Patterns
These patterns help structure your MAUI application for scalability, testability, and maintainability.
Model-View-ViewModel (MVVM)
MVVM is a UI design pattern that separates application development in three distinct components:
- Model: Represents the data and business logic of the application. It is completely UI-agnostic.
- View: Represents the UI and the user interface elements. It should be as passive as possible, and its primary responsibility is to display data and forward user input to the ViewModel.
- ViewModel: Acts as an intermediary between the Model and the View. It exposes data from the Model to the View and handles user interactions forwarded by the View. ViewModels typically do not have a reference to the View.
Key features of MVVM in MAUI:
- Data Binding: MAUI's powerful data binding engine is central to MVVM, enabling seamless synchronization between View and ViewModel properties.
- Commands: Used to encapsulate actions, allowing the View to trigger actions in the ViewModel without direct event handlers.
- Dependency Injection: Often used to provide dependencies to ViewModels, enhancing testability.
Model-View-Presenter (MVP)
MVP is another UI architectural pattern, similar to MVVM but with a slightly different interaction model.
- Model: Same as in MVVM.
- View: Passive, implementing an interface that the Presenter uses to update the UI.
- Presenter: Acts as the mediator. It retrieves data from the Model and formats it for display in the View. It also handles user input from the View and updates the Model accordingly. The Presenter often holds a reference to the View interface.
While MVVM is more prevalent in MAUI due to its strong binding support, MVP can be a viable alternative in certain scenarios.
Design Patterns
These are general design patterns that are highly beneficial when developing with .NET MAUI:
Dependency Injection (DI)
DI is crucial for building loosely coupled, testable, and maintainable applications. .NET MAUI has built-in support for DI, making it easy to manage services and dependencies.
Key concepts:
- Registering services (e.g.,
IMessagingService,IConnectivity) with a service container. - Resolving services through constructors or property injection.
// Example: Registering a service
builder.Services.AddSingleton<IMessagingService, MessagingService>();
// Example: Injecting a service into a ViewModel
public class MyViewModel : INotifyPropertyChanged
{
private readonly IMessagingService _messagingService;
public MyViewModel(IMessagingService messagingService)
{
_messagingService = messagingService;
}
// ...
}
Command Pattern
The Command pattern encapsulates a request as an object, allowing for parameterization of clients with different requests, queuing or logging of requests, and support for undoable operations.
In MAUI, this is primarily implemented using ICommand, often via RelayCommand (from Community Toolkit) or custom implementations.
public ICommand SaveCommand { get; }
public MyViewModel()
{
SaveCommand = new Command(async () => await SaveAsync());
}
private async Task SaveAsync()
{
// Save logic here
}
Singleton Pattern
Ensures that a class has only one instance and provides a global point of access to it. Useful for services that should only have one instance throughout the application's lifetime.
Observer Pattern
Also known as the Publisher-Subscriber pattern. Useful for event handling and communication between objects where one object (the subject) maintains a list of its dependents (observers) and notifies them automatically of any state changes.
MAUI's INotifyPropertyChanged interface is a prime example of the Observer pattern in action, used extensively with data binding.
Service Location vs. Dependency Injection
While both patterns help access services, Dependency Injection is generally preferred in modern application development for its benefits in testability and decoupling.
- Service Location: An object asks for a service from a central registry. This can lead to hidden dependencies.
- Dependency Injection: Dependencies are "injected" into an object by an external source (the DI container). This makes dependencies explicit.
.NET MAUI's built-in DI container promotes the latter.