Let’s pick up where we left off in the previous blog post, but it is time to clean up the app to use MVVM. First step: create a ViewModel folder and in that put two files:
- MainViewModel
- ViewModelBase
MainViewModel is going to supply the list we’ll bind to in MainPage, which now looks like this:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
x:Class="LearningMaui_Part7.MainPage"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:model="clr-namespace:LearningMaui_Part7.Model"
Title="Learning .NET MAUI - 7">
<CollectionView ItemsSource="{Binding ResultList}">
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="model:Result">
<VerticalStackLayout>
<HorizontalStackLayout
Padding="10"
Spacing="4"
VerticalOptions="Center">
<Label VerticalOptions="Center">
<Label.Text>
<MultiBinding StringFormat="{}{0} | {1}">
<Binding Path="state" />
<Binding Path="zip" />
</MultiBinding>
</Label.Text>
</Label>
<Image
Margin="5,0,5,5"
Aspect="Fill"
HeightRequest="25"
Source="{Binding image}"
WidthRequest="25" />
</HorizontalStackLayout>
</VerticalStackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</ContentPage>
Much cleaner. The CollectionView binds to a property in the ViewModel named ResultList. That is, of course, in MainViewModel. Here is that file in full:
using LearningMaui_Part7.Model;
namespace LearningMaui_Part7.ViewModel
{
internal class MainViewModel : ViewModelBase
{
public MainViewModel()
{
CreateList();
}
private List<Result> _resultList;
public List<Result> ResultList
{
get => _resultList;
set => SetProperty(ref _resultList, value);
}
public void CreateList()
{
ResultList = new List<Result>();
Result result = new Result
{
image = "https://upload.wikimedia.org/wikipedia/commons/thumb/2/22/Seal_of_New_York_%28state%29.svg/150px-Seal_of_New_York_%28state%29.svg.png",
state = "NY",
zip = "07748"
};
ResultList.Add(result);
ResultList.Add(new Result
{
image = "https://upload.wikimedia.org/wikipedia/commons/thumb/4/49/Flag_of_Vermont.svg/188px-Flag_of_Vermont.svg.png",
state = "VT",
zip = "05143"
});
ResultList.Add(new Result
{
image = "https://upload.wikimedia.org/wikipedia/commons/thumb/9/96/Flag_of_Connecticut.svg/188px-Flag_of_Connecticut.svg.png",
state = "CT",
zip = "06457"
});
ResultList.Add(new Result
{
image = "https://upload.wikimedia.org/wikipedia/commons/thumb/9/96/Flag_of_Connecticut.svg/188px-Flag_of_Connecticut.svg.png",
state = "CT",
zip = "06457"
});
}
}
}
In time we’ll want to get the list from the Zip service, but for now at least it is encapsulated here. Notice that the ResultList property uses this construct: set => SetProperty(ref _resultList, value); This is defined in the ViewModelBase:
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace LearningMaui_Part7.ViewModel;
public class ViewModelBase : INotifyPropertyChanged
{
protected ViewModelBase() { }
protected bool SetProperty<T>(ref T backingStore, T value, [CallerMemberName] string propertyName = null)
{
if (Equals(backingStore, value)) return false;
backingStore = value;
OnPropertyChanged(propertyName);
return true;
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
Among other things, notice that the namespace declaration has changed in MAUI: you now just name the namespace followed by a semi-colon and there is no need for braces.
There are no other changes from the previous version, but we are now ready to move forward with our .NET MAUI project, which we will do in the next blog post.
The source code for this version is here.