The Model-View-ViewModel (MVVM) pattern is a popular architectural pattern for building user interfaces, especially in frameworks like .NET MAUI. It promotes a clear separation of concerns, making applications more maintainable, testable, and scalable.
MVVM is an architectural pattern that separates UI logic from business logic. It consists of three main components:
Represents the application's data and business logic. It is independent of the UI and contains no knowledge of the View or ViewModel. The Model notifies observers (typically the ViewModel) when its state changes.
Represents the User Interface (UI). In .NET MAUI, this is typically implemented using XAML. The View is responsible for displaying data from the ViewModel and forwarding user input to the ViewModel. The View should be as "dumb" as possible, containing minimal logic.
Acts as an intermediary between the Model and the View. It exposes data from the Model to the View in a format that is easily consumable by the UI, and it handles user input from the View, updating the Model accordingly. The ViewModel implements the presentation logic and exposes commands and properties that the View can bind to.
.NET MAUI embraces MVVM through its powerful data binding system. XAML is used to define the View, and C# classes serve as ViewModels and Models.
Data binding is the core mechanism that connects the View and the ViewModel. It allows UI elements in the View to reflect data from the ViewModel and allows user interactions in the View to update data in the ViewModel.
To enable data binding, ViewModels typically implement the INotifyPropertyChanged interface. This interface allows the ViewModel to notify the View when a property's value has changed, ensuring that the UI stays up-to-date.
public class MyViewModel : INotifyPropertyChanged
{
private string _message;
public string Message
{
get => _message;
set
{
if (_message != value)
{
_message = value;
OnPropertyChanged(nameof(Message));
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
User actions, such as button clicks, are handled in the ViewModel using the ICommand interface. This further decouples the View from the logic.
public ICommand SaveCommand { get; }
public MyViewModel()
{
SaveCommand = new Command(ExecuteSaveCommand);
}
private void ExecuteSaveCommand()
{
// Logic to save data
System.Diagnostics.Debug.WriteLine("Save command executed!");
}
In the XAML View, you would bind a button's Command property to this SaveCommand.
using System.ComponentModel;
using System.Windows.Input;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
public partial class MainPageViewModel : ObservableObject
{
[ObservableProperty]
private string _userName;
[ObservableProperty]
private string _greetingMessage;
public ICommand GreetCommand { get; }
public MainPageViewModel()
{
GreetCommand = new RelayCommand(PerformGreeting);
}
private void PerformGreeting()
{
GreetingMessage = $"Hello, {UserName}!";
}
}
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:viewmodels="clr-namespace:YourApp.ViewModels"
x:Class="YourApp.Views.MainPage"
x:DataType="viewmodels:MainPageViewModel">
<StackLayout Padding="20" Spacing="15">
<Entry Placeholder="Enter your name"
Text="{Binding UserName, UpdateSourceTrigger=PropertyChanged}" />
<Button Text="Greet Me"
Command="{Binding GreetCommand}" />
<Label Text="{Binding GreetingMessage}"
FontSize="Large"
HorizontalOptions="Center" />
</StackLayout>
</ContentPage>