Data Binding in .NET MAUI

Learn how to effectively use data binding to create responsive and dynamic user interfaces in .NET MAUI applications.

Introduction to Data Binding

.NET MAUI (Multi-platform App UI) provides a powerful data binding system that allows you to connect the UI elements of your application to your data models. This approach decouples the presentation layer from the business logic, leading to more maintainable, testable, and scalable code. Data binding simplifies common UI patterns such as:

Core Concepts

At its heart, data binding involves two primary components:

INotifyPropertyChanged

For data binding to work effectively and for the UI to update automatically when the underlying data changes, the binding source object must implement the INotifyPropertyChanged interface. This interface defines a single event: PropertyChanged. When a property's value changes, the object raises this event, notifying any listeners (including the data binding system) that the property has changed.

Here's a simple C# example:


public class MyDataModel : 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));
    }
}
        

Binding Modes

Data binding supports different modes that control the direction and behavior of data synchronization between the source and target.

Creating Bindings in XAML

The primary way to define data bindings in .NET MAUI is through XAML. You use the {Binding} markup extension.

Simple Property Binding

To bind the Text property of a Label to the Message property of a MyDataModel:


<!-- Assume MyDataModel is set as the BindingContext -->
<Label Text="{Binding Message}" />
        

Setting the Binding Context

For the binding to work, the UI element needs a BindingContext. This is typically set to your ViewModel or data model instance.


<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:YourApp.ViewModels"
             x:Class="YourApp.Views.MyPage">

    <ContentPage.BindingContext>
        <local:MyViewModel /> 
    </ContentPage.BindingContext>

    <!-- ... rest of your page content ... -->
</ContentPage>
        

Two-Way Binding

To allow user input in an Entry to update a property in your ViewModel:


<Entry Text="{Binding UserName, Mode=TwoWay}" />
        

Note that the property in your ViewModel (UserName in this case) must also raise PropertyChanged when it changes.

Binding to Collections

Data binding is also crucial for displaying collections of data, such as lists or grids.

ItemsSource Binding

Use the ItemsSource property of controls like ListView, CollectionView, or CarouselView to bind to a collection.


<ListView ItemsSource="{Binding Items}" />
        

For the collection itself to notify the UI about additions or removals of items, it should implement INotifyCollectionChanged or inherit from ObservableCollection<T>.

ObservableCollection<T>

ObservableCollection<T> is a built-in .NET collection that implements INotifyCollectionChanged, making it ideal for binding to UI lists.


public class MyViewModel : INotifyPropertyChanged
{
    private ObservableCollection<string> _items = new ObservableCollection<string>();
    public ObservableCollection<string> Items
    {
        get => _items;
        set
        {
            if (_items != value)
            {
                _items = value;
                OnPropertyChanged(nameof(Items));
            }
        }
    }

    // ... INotifyPropertyChanged implementation ...
}
        

Commands

Commands provide a way to bind actions (like button clicks) to methods in your ViewModel, further enhancing the separation of concerns.

ICommand Interface

Implement the ICommand interface in your ViewModel. A common implementation pattern is to use RelayCommand or DelegateCommand (often found in MVVM helper libraries) or to implement it manually.


public class MyViewModel : INotifyPropertyChanged
{
    // ... other properties ...

    public ICommand SaveCommand { get; }

    public MyViewModel()
    {
        SaveCommand = new Command(ExecuteSave, CanExecuteSave);
    }

    private void ExecuteSave()
    {
        // Logic to save data
        System.Diagnostics.Debug.WriteLine("Data Saved!");
    }

    private bool CanExecuteSave()
    {
        // Logic to determine if the command can be executed
        return true; // Or based on some condition
    }

    // ... INotifyPropertyChanged implementation ...
}
        

Binding Commands in XAML


<Button Text="Save" Command="{Binding SaveCommand}" />
        

The Command property of controls like Button, MenuItem, etc., can be bound to an ICommand instance.

Advanced Binding Scenarios

Binding Path

You can navigate through object graphs using the Path property in your binding.


<!-- Assuming a ViewModel with a property 'User' which has a 'Name' property -->
<Label Text="{Binding User.Name}" />
        

StringFormat

Format the bound string value using StringFormat.


<Label Text="{Binding Price, StringFormat='{0:C2}'}" /> 
<Label Text="{Binding DateTime, StringFormat='{0:yyyy-MM-dd HH:mm}'}" />
        

Converters

When you need to transform data before displaying it or to convert it for binding, use IValueConverter.

Example: A converter to turn a boolean into a visible/hidden state.


public class BoolToVisibilityConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is bool boolValue)
        {
            return boolValue ? Visibility.Visible : Visibility.Collapsed;
        }
        return Visibility.Collapsed;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is Visibility visibilityValue)
        {
            return visibilityValue == Visibility.Visible;
        }
        return false;
    }
}
        

Register the converter in your XAML and use it:


<ContentPage.Resources>
    <local:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
</ContentPage.Resources>

<!-- ... -->
<StackLayout IsVisible="{Binding IsLoading, Converter={StaticResource BoolToVisibilityConverter}}" />
        

Best Practices

Note: Data binding is a fundamental feature of .NET MAUI. Mastering it will significantly improve your development efficiency and the quality of your applications.