Xamarin.Forms Fundamentals: MVVM

In my previous post we started with a blank Xamarin.Forms app and added manual data-binding.   That is, when a button was pressed, we assigned the value in an entry control to the text property of a label. 

Yuck.

Today we’ll look at a better way of doing that.  But hold on to your hat, and fasten your seat belt, because we’re going to dive into the deep end.   

You may want to create a new Blank Xamarin.Forms app, as there will be a lot of new material in this example.  Once your app is created, add three folders to the solution:  Model, View and ViewModel.

You already have a MainPage.xaml.  Drag it up into the View folder.  Add a label and a button. 

<Label
    Text="{Binding WelcomeText}" 
    HorizontalOptions="Center"
    VerticalOptions="Center" />

<Button Text="Change" Command="{Binding ButtonClickedCommand}" />

Notice that the Text property of the label says that it is bound to WelcomeText.  WelcomeText will be the name of a property in the corresponding ViewModel. 

By convention, the ViewModel class will have the same name as the View class, but with the ending ViewModel appended.  Thus, the View is MainPage and the ViewModel is MainPageViewModel.

Data Binding

By binding the control to a property, we tell Xamarin.Forms: “When this property changes, update this control.” 

Let’s create a new class in the ViewModel folder named MainPageViewModel.cs, and add the property we want to bind to.

private string welcomeText = "Hello world"; 
public string WelcomeText
 {
    get => welcomeText;
    set => SetValue( ref welcomeText, value );
 }

There is a lot to see here.  WelcomeText is a property and thus has a setter and a getter. 

In order for databinding to work you need four ingredients:

  • The Binding keyword in the XAML
  • A BindingContext
  • The property to bind to
  • Implementation of INotifyPropertyChanged

We’ve seen the binding keyword.

The BindingContext is just a way to tell Xamarin.Forms where to find the properties you are binding to.  In this case, the BindingContext is MainPageViewModel, which we indicate in MainPage.xaml.cs

 public MainPage()
 {
    InitializeComponent();
    var vm = new MainPageViewModel();
    BindingContext = vm;
 }

INotifyPropertyChanged

The property to bind to is in the ViewModel (as we saw) and then we need to implement INotifyPropertyChanged.  This interface is implemented in each of your ViewModel classes, which becomes tedious, so we move it up to the base view model. 

The base view model I like does a little fancy footwork: it creates the SetValue method to make binding even easier.  Here is the base view model:

 public abstract class BaseViewModel : INotifyPropertyChanged
 {
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged( 
           [CallerMemberName] string propertyName = null )
    {
       PropertyChanged?.Invoke( 
               this, new PropertyChangedEventArgs( propertyName ) );
    }

    protected void SetValue<T>( ref T   backingField,
          T       value,
          [CallerMemberName] string propertyName = null )
    {
       if (EqualityComparer<T>.Default.Equals( 
                    backingField, value )) return;
       backingField = value;
       OnPropertyChanged( propertyName );
    }
}

The first line declares the (required) event PropertyChanged, which is defined by the interface.  

Next we have a pretty standard handler for that event named OnPropertyChanged.  This checks to see if anyone has registered with the event, and if so it fires off the event with the name of the property that was updated.

Finally, we have SetValue.  This is a helper method designed to make setting the property easier.  For now, you can just take this one on faith, or if you are comfortable with generics you can study it for a bit to see how it works.  

Binding at work

Let’s trace the binding.  If something (say the button handler) sets the WelcomeText value in the ViewModel, The underlying backing variable (welcomeText) will be updated and NotifyPropertyChanged will be raised.  Since the view has registered for that (by setting the binding context), the control bound to that property (the label) will be updated.  Magic.

Commands

But wait! There’s more!

In the previous example, we used an event handler for the button, and handled the event in code behind.  This is icky because it is hard to write unit tests against views.  So we want to move the event handling to the View Model.  To do that, we use a Command,

 <Button Text="Change" Command="{Binding ButtonClickedCommand}"

A command is like a property, in that you can bind to it, as we have done here.  In the view model, we declare the command as a property,

public ICommand ButtonClickedCommand { get; set; }

and then, in the View Model constructor, we instantiate the command, providing it the name of the method that will handle the command.

public MainPageViewModel()
{
   ButtonClickedCommand = new Command(OnButtonClicked);
}

This says that when the button is clicked, the command will fire and the method OnButtonClicked will  be called.  

private void OnButtonClicked()
{
   WelcomeText = "Hello Bound Command!!";
}

Notice that in OnButtonClicked we set the text for the WelcomeText property.  We do not set the label’s text directly.  By setting the WelcomeText property, the NotifyChanged property is fired and the label rebinds its text to the text in the property.  Boom! that text is displayed.

That’s a lot of moving parts, so read this all again.  We’ll continue building out this app in coming blog posts.

About Jesse Liberty

Jesse Liberty is the Principal Mobile Developer with IFS Core. He has three decades of experience writing and delivering software projects. He is the author of 2 dozen books and a couple dozen Pluralsight & LinkedIn Learning courses, and has been 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 Xamarin Certified Mobile Developer and a Xamarin MVP and a Microsoft MVP.
This entry was posted in Essentials. Bookmark the permalink.

3 Responses to Xamarin.Forms Fundamentals: MVVM

  1. Morgan Vermef says:

    Rich,

    The base class BaseViewModel goes in the ViewModel folder. Now using inheritance MagePageViewModel uses the code in BaseViewModel with having to write the exact code again and again. Because of the inheritance SetValue(); will now work and not be an error.

    public class MagePageViewModel : BaseViewModel
    {
    }

  2. Rich Osborne says:

    Jesse, I need help. Being a beginner, I follow your instructions to the letter and here is what I encounter:
    Your instructions say “add three folders to the solution” But what happened when you add folders to the solution – problems! What I think you meant to say is “add three folders to the shared project” which is the course I took.
    When I create the new class in the ViewModel folder copying you code, I get an error with SetValue, ” the name does not exist in the current context.” OK, I press on hoping you will address this.
    So now I see your instruction, “Here is the BaseViewModel” But, where did it come from? Do I add a class? If so, where, which folder, and do I name it BaseViewModel?
    Not understanding what to do now, I add a class to the MagePageViewModel name ot BaseViewModel and copy your code. Now I run into many error lines and give up.

    I don’t think experienced coders realize how difficult it is for beginners. So often, I see the that instructors expects us to know what s/he meant. It feels like you and they wants to figure it out as part of the learning. Unfortunately, we are learning and don’t know what you meant or want and it is frustrating.

    Your lesson is right on point to what I want and need to learn. Please work with me through some basics so I can get it right. Thank you.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.