Data Binding Sample
Data binding is a process where a connection between a user interface and the data it displays is established. After which, when we interact with the user interface, the updates we made are reflected in the data. And when the data changes its value, the user interface will automatically reflect the changes.
In our XAML code below, we are setting up an edit form for a fruit product. The structure of the user interface code is similar to our sample using Code Behind. The interesting to note are the elements with the Binding keyword. For example, in our ProductName Entry we define a binding to the ProductName property of our model.
Text="{Binding ProductName, Mode=TwoWay}"
We are using a two-way binding where you can modify the data through the user interface and have that data updated in the model. If the model changes, the view will be automatically updated.
In the XAML code below, we have also defined Data Binding for the ProductPrice Entry, ProductDescription Editor, and ProductOfferEndDate DatePicker.
<ScrollView>
<Grid Margin="25">
<Grid.RowDefinitions>
<RowDefinition Height="50"></RowDefinition>
<RowDefinition Height="200"></RowDefinition>
<RowDefinition Height="50"></RowDefinition>
<RowDefinition Height="80"></RowDefinition>
<RowDefinition Height="100"></RowDefinition>
<RowDefinition Height="50"></RowDefinition>
<RowDefinition Height="50"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=".3*"></ColumnDefinition>
<ColumnDefinition Width=".7*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Label x:Name="TitleLabel"
Text="Edit Product"
Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="2"
FontSize="Large"></Label>
<Image x:Name="ProductImage"
Source="{Binding ImageUrl, Mode=TwoWay}"
Grid.Column="0"
Grid.Row="1"
Grid.ColumnSpan="2"
Margin="10"
WidthRequest="200"
HeightRequest="200"
VerticalOptions="Center"></Image>
<Label Text="Product name"
Grid.Row="2"
Grid.Column="0"
FontSize="Small"
VerticalOptions="Center"></Label>
<Entry x:Name="ProductName"
Text="{Binding ProductName, Mode=TwoWay}"
Grid.Row="2"
Grid.Column="1"
VerticalOptions="Center"></Entry>
<Label Text="Price"
Grid.Row="3"
Grid.Column="0"
FontSize="Small"
VerticalOptions="Center"></Label>
<StackLayout
Grid.Row="3"
Grid.Column="1">
<Label
Margin="5,0,0,0"
TextColor="Blue"
Text="{Binding Price, Mode=OneWay}"
FontSize="Small"
VerticalOptions="Center"></Label>
<Entry x:Name="ProductPrice"
Text="{Binding Price, Mode=TwoWay}"
FontSize="Small"
HorizontalOptions="FillAndExpand"
VerticalOptions="Center"></Entry>
</StackLayout>
<Label
Text="Description"
Grid.Row="4"
Grid.Column="0"
FontSize="Small"></Label>
<Editor x:Name="ProductDescription"
Text="{Binding Description, Mode=TwoWay}"
Grid.Row="4"
Grid.Column="1"
FontSize="Small"
HorizontalOptions="FillAndExpand"
VerticalOptions="Center"></Editor>
<Label Text="Offer End Date"
Grid.Row="5"
Grid.Column="0"
FontSize="Small"
VerticalOptions="Center"></Label>
<DatePicker x:Name="ProductOfferEndDate"
Date="{Binding OfferEndDate, Mode=TwoWay}"
Grid.Row="5"
Grid.Column="1"
VerticalOptions="Center"></DatePicker>
<Button x:Name="SaveProductButton"
Clicked="SaveProductButton_OnClicked"
Text="Save Product"
Grid.Row="6"
Grid.Column="0"
Grid.ColumnSpan="2"></Button>
</Grid>
</ScrollView>
After defining how each control in the user interface is tied (data bind) to a property in our model, we need to provide a final hook for linking our model. We can do this with a BindingContext property.
this.BindingContext = MyProduct;
With Data Binding, we no longer require the code to load and save data which we commented out below:
public partial class MainPage : ContentPage
{
public Product MyProduct { get; set; }
public MainPage()
{
InitializeComponent();
MyProduct = new Product
{
Id = 1,
Description = "Apple, Malus domestica, is one of the most widely cultivated tree fruits with a fleshy and edible surrounding tissue.",
ImageUrl = "https://mauiman.dev/mauishopimages/red-apple-isolated.jpg",
OfferEndDate = new DateTime(2025, 2, 10),
ProductName = "Apple",
Price = 2.80
};
this.BindingContext = MyProduct;
/*
ProductImage.Source = MyProduct.ImageUrl;
ProductName.Text = MyProduct.ProductName;
ProductPrice.Text = MyProduct.Price.ToString();
ProductDescription.Text = MyProduct.Description;
ProductOfferEndDate.Date = MyProduct.OfferEndDate;
*/
}
private async void SaveProductButton_OnClicked(object sender, EventArgs e)
{
/*
MyProduct.ImageUrl = ProductImage.Source.ToString();
MyProduct.ProductName = ProductName.Text;
MyProduct.Price = double.Parse(ProductPrice.Text);
MyProduct.Description = ProductDescription.Text;
MyProduct.OfferEndDate = ProductOfferEndDate.Date;
*/
await DisplayAlert("Success", "Product saved", "Done");
}
}
The final step is to add some plumbing code in our Product model class to provide property-change notification so that Data Binding knows when to refresh the user interface. To do this, we implement the INotifyPropertyChanged interface in our Product class and raise a PropertyChanged event when a property such as the Description of our Product changes.
public class Product : INotifyPropertyChanged
{
private int id;
private string productName;
private string description;
private double price;
private string imageUrl;
private DateTime offerEndDate;
public int Id
{
get => id;
set
{
id = value;
RaisePropertyChanged(nameof(Id));
}
}
public string ProductName
{
get => productName;
set
{
productName = value;
RaisePropertyChanged(nameof(ProductName));
}
}
public string Description
{
get => description;
set
{
description = value;
RaisePropertyChanged(nameof(Description));
}
}
public double Price
{
get => price;
set
{
price = value;
RaisePropertyChanged(nameof(Price));
}
}
public string ImageUrl
{
get => imageUrl;
set
{
imageUrl = value;
RaisePropertyChanged(nameof(ImageUrl));
}
}
public DateTime OfferEndDate
{
get => offerEndDate;
set
{
offerEndDate = value;
RaisePropertyChanged(nameof(OfferEndDate));
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Download
This sample will be further evolved to one with a MVVM (Model View ViewModel) pattern.