Data Binding in .NET MAUI MVVM
Data binding is a core concept in the Model-View-ViewModel (MVVM) architectural pattern. It establishes a connection between properties of your ViewModels and the UI elements in your Views, allowing for automatic synchronization of data. This tutorial will guide you through the fundamentals of data binding in .NET MAUI.
What is Data Binding?
Data binding is a mechanism that connects two objects, such as a ViewModel property and a UI element property, so that they can communicate. When one property changes, the other is automatically updated. This significantly reduces boilerplate code for updating the UI manually.
In .NET MAUI, data binding is declarative and is typically defined in XAML.
Binding Modes
Data binding supports various modes to control the direction and timing of data synchronization:
- OneWay: Changes in the source property update the target property. This is the default mode.
- TwoWay: Changes in the source property update the target property, and changes in the target property update the source property.
- OneTime: The target property is initialized with the source property's value once. No further updates occur.
- OneWayToSource: Changes in the target property update the source property.
Basic Data Binding
The most common scenario is binding a UI element's property to a property in your ViewModel. Let's say you have a ViewModel with a Message
property and you want to display it in a Label
.
ViewModel Code (Example)
public class MainViewModel : 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));
}
public MainViewModel()
{
Message = "Hello from MVVM!";
}
}
XAML View Code (Example)
<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">
<ContentPage.BindingContext>
<viewmodels:MainViewModel />
</ContentPage.BindingContext>
<StackLayout VerticalOptions="Center" HorizontalOptions="Center">
<Label Text="{Binding Message}" />
</StackLayout>
</ContentPage>
In this example:
- We set the
BindingContext
of theContentPage
to an instance ofMainViewModel
. - The
Label's
Text
property is bound to theMessage
property of theBindingContext
using{Binding Message}
. - The ViewModel implements
INotifyPropertyChanged
, which is crucial for the UI to be notified of property changes.
Two-Way Binding
Two-way binding is useful when you want user input in a UI element (like an Entry
) to update a ViewModel property, and vice-versa.
XAML View Code (Example)
<!-- ... inside your StackLayout ... -->
<Entry Text="{Binding UserName, Mode=TwoWay}" Placeholder="Enter your name" />
<Label Text="Welcome, {Binding UserName}!" />
<!-- ... -->
Here, the Entry's
Text
property is bound to the UserName
property of the ViewModel using Mode=TwoWay
. Any text entered into the Entry will update the UserName
property, and if the UserName
property is changed programmatically, the Entry's text will also update.
Binding to Collections
Data binding is also used to display lists of data. You'll typically bind a CollectionView
or ListView
to an ObservableCollection
in your ViewModel.
ViewModel Code (Example)
public class ItemViewModel : INotifyPropertyChanged
{
public string Name { get; set; }
// ... other properties
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); }
}
public class ListViewModel : INotifyPropertyChanged
{
private ObservableCollection<ItemViewModel> _items;
public ObservableCollection<ItemViewModel> Items
{
get => _items;
set
{
if (_items != value)
{
_items = value;
OnPropertyChanged(nameof(Items));
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); }
public ListViewModel()
{
Items = new ObservableCollection<ItemViewModel>
{
new ItemViewModel { Name = "Apple" },
new ItemViewModel { Name = "Banana" },
new ItemViewModel { Name = "Cherry" }
};
}
}
XAML View Code (Example)
<!-- ... inside your page content ... -->
<CollectionView ItemsSource="{Binding Items}">
<CollectionView.ItemTemplate>
<DataTemplate>
<Label Text="{Binding Name}" Padding="10" />
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<!-- ... -->
The CollectionView
's ItemsSource
is bound to the Items
ObservableCollection
. The ItemTemplate
defines how each item in the collection is displayed, binding to properties of the ItemViewModel
.
Common Binding Issues & Tips
INotifyPropertyChanged
and that you correctly call OnPropertyChanged
whenever a bound property's value changes.
Null References
If a binding results in a null reference exception, double-check:
- The
BindingContext
is set correctly. - The property names in your XAML match your ViewModel exactly (case-sensitive).
- The ViewModel properties are public.
Binding Converters
Sometimes you need to transform data before it's displayed or sent back to the ViewModel. Binding converters allow you to do this. For example, converting a boolean to a string representation or formatting a date.
Example: Using a Boolean to String Converter
ViewModel:
public bool IsActive { get; set; } = true;
Converter (Conceptual):
public class BooleanToStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is bool boolValue)
{
return boolValue ? "Active" : "Inactive";
}
return "N/A";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is string stringValue)
{
return stringValue.Equals("Active", StringComparison.OrdinalIgnoreCase);
}
return false;
}
}
XAML (with converter registered and applied):
<!-- In your ResourceDictionary or Page.Resources -->
<local:BooleanToStringConverter x:Key="BoolConverter" />
<!-- In your UI -->
<Label Text="{Binding IsActive, Converter={StaticResource BoolConverter}}" />
Conclusion
Data binding is a powerful feature in .NET MAUI that, when used with the MVVM pattern, leads to cleaner, more maintainable, and testable applications. By understanding binding modes, collection binding, and converters, you can effectively manage data flow between your UI and your ViewModels.