MVVM (Model View ViewModel)
This example illustrates the Maui Shop sample with Data Binding ported to one using the MVVM (Model View View Model) pattern.
Model View ViewModel is a software pattern that separates the user interface code with the back end business logic (or data) code. This sounds familiar to what Code Behind is used for solving. If you recall, our previous sample, introduces Data Binding where we can sync the user interface and model data easily.
<ScrollView>
<Grid Margin="25">
<Grid.RowDefinitions>
<RowDefinition Height="50"></RowDefinition>
<RowDefinition Height="200"></RowDefinition>
<RowDefinition Height="50"></RowDefinition>
<RowDefinition Height="50"></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"
Grid.Column="0"
Grid.Row="1"
Grid.ColumnSpan="2"
Source="{Binding ImageUrl}"
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 Grid.Row="2"
Grid.Column="1"
Text="{Binding ProductName, Mode=TwoWay}"
Style="{StaticResource RegularEntry}"
VerticalOptions="Center"></Entry>
<Label Text="Price"
Grid.Row="3"
Grid.Column="0"
FontSize="Small"
VerticalOptions="Center"></Label>
<Entry Grid.Row="3"
Grid.Column="1"
Text="{Binding Price, Mode=TwoWay}"
FontSize="Small"
HorizontalOptions="FillAndExpand"
VerticalOptions="Center"></Entry>
<Label Text="Description"
Grid.Row="4"
Grid.Column="0"
FontSize="Small"></Label>
<Editor Grid.Row="4"
Grid.Column="1"
Text="{Binding Description, Mode=TwoWay}"
FontSize="Small"
HorizontalOptions="FillAndExpand"
VerticalOptions="Center"></Editor>
<Label Text="Offer End Date"
Grid.Row="5"
Grid.Column="0"
FontSize="Small"
VerticalOptions="Center"></Label>
<DatePicker Grid.Row="5"
Grid.Column="1"
Date="{Binding OfferEndDate, Mode=TwoWay}"
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>
The Code Behind Code now set the Binding Context to the ProductViewModel instead of the Model directly.
public partial class MainPage : ContentPage
{
public Product MyProduct { get; set; }
public List MyProducts { get; set; }
public static ProductViewModel ProductViewModel { get; set; } = new ProductViewModel();
public MainPage()
{
InitializeComponent();
this.BindingContext = ProductViewModel.Product;
}
private void SaveProductButton_OnClicked(object sender, EventArgs e)
{
Console.WriteLine("Save Command");
}
}
The ProductViewModel code is shown below.
public class ProductViewModel : INotifyPropertyChanged
{
public ProductViewModel()
{
Product = 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(2022, 2, 10),
ProductName = "Apple",
Price = 2.80
};
}
public Product Product { get; set; }
public string UserName { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Download