Learning .NET MAUI – Part 7

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.

About Jesse Liberty

Jesse Liberty has three decades of experience writing and delivering software projects and is the author of 2 dozen books and a couple dozen online courses. His latest book, Building APIs with .NET will be released early in 2025. Liberty is a Senior SW Engineer for CNH and he was a Senior Technical Evangelist for Microsoft, a Distinguished Software Engineer for AT&T, a VP for Information Services for Citibank and a Software Architect for PBS. He is a Microsoft MVP.
This entry was posted in Essentials and tagged , . Bookmark the permalink.