Summary of Chapter 18. MVVM
Note
This book was published in the spring of 2016, and has not been updated since then. There is much in the book that remains valuable, but some of the material is outdated, and some topics are no longer entirely correct or complete.
One of the best ways to architect an application is by separating the user interface from the underlying code, which is sometimes called the business logic. Several techniques exist, but the one that is tailored for XAML-based environments is known as Model-View-ViewModel or MVVM.
MVVM interrelationships
An MVVM application has three layers:
- The Model provides underlying data, sometimes through files or web accesses
- The View is the user interface or presentation layer, generally implemented in XAML
- The ViewModel connects the Model and the View
The Model is ignorant of the ViewModel and the ViewModel is ignorant of the View. These three layers generally connect to each other using the following mechanisms:
In many smaller programs (and even larger ones), often the Model is absent or its functionality is integrated into the ViewModel.
ViewModels and data binding
To engage in data bindings, a ViewModel must be capable of notifying the View when a property of the ViewModel has changed. The ViewModel does this by implementing the INotifyPropertyChanged
interface in the System.ComponentModel
namespace. This is part of .NET rather than Xamarin.Forms. (Generally ViewModels attempt to maintain platform independence.)
The INotifyPropertyChanged
interface declares a single event named PropertyChanged
that indicates the property that has changed.
A ViewModel clock
The DateTimeViewModel
in the Xamarin.FormsBook.Toolkit library defines a property of type DateTime
that changes based on a timer. The class implements INotifyPropertyChanged
and fires the PropertyChanged
event whenever the DateTime
property changes.
The MvvmClock sample instantiates this ViewModel and uses data bindings to the ViewModel to display updated date and time information.
Interactive properties in a ViewModel
Properties in a ViewModel can be more interactive, as demonstrated by the SimpleMultiplierViewModel
class, which is part of the
SimpleMultiplier sample. The data bindings provide multiplicand and multiplier values from two Slider
elements and display the product with a Label
. However, you can make extensive changes to this user interface in XAML with no consequent changes to the ViewModel or the code-behind file.
A Color ViewModel
The
ColorViewModel
in the Xamarin.FormsBook.Toolkit library integrates the RGB and HSL color models. It is demonstrated in the HslSliders sample:
Streamlining the ViewModel
The code in ViewModels can be streamlined by defining an OnPropertyChanged
method using the CallerMemberName
attribute, which obtains the calling property name automatically. The ViewModelBase
class in the Xamarin.FormsBook.Toolkit library does this and provides a base class for ViewModels.
The Command interface
MVVM works with data bindings, and data bindings work with properties, so MVVM seems to be deficient when it comes to handling a Clicked
event of a Button
or a Tapped
event of a TapGestureRecognizer
. To allow ViewModels to handle such events, Xamarin.Forms supports the command interface.
The command interface manifests itself in the Button
with two public properties:
Command
of typeICommand
(defined in theSystem.Windows.Input
namespace)CommandParameter
of typeObject
To support the command interface, a ViewModel must define a property of type ICommand
that is then data bound to the Command
property of the Button
. The ICommand
interface declares two methods and one event:
- An
Execute
method with an argument of typeobject
- A
CanExecute
method with an argument of typeobject
that returnsbool
- A
CanExecuteChanged
event
Internally, a ViewModel sets each property of type ICommand
to an instance of a class that implements the ICommand
interface. Through the data binding, the Button
initially calls the CanExecute
method, and disables itself if the method returns false
. It also sets a handler for the CanExecuteChanged
event and calls CanExecute
whenever that event is fired. If the Button
is enabled, it calls the Execute
method whenever the Button
is clicked.
You might have some ViewModels that predate Xamarin.Forms, and these might already support the command interface. For new ViewModels intended to be used only with Xamarin.Forms, Xamarin.Forms supplies a Command
class and a Command<T>
class that implement the ICommand
interface. The generic type is the type of the argument to the Execute
and CanExecute
methods.
Simple method executions
The PowersOfThree sample demonstrates how to use the command interface in a ViewModel. The PowersViewModel
class defines two properties of type ICommand
and also defines two private properties that it passes to the simplest Command
constructor. The program contains data bindings from this ViewModel to the Command
properties of two Button
elements.
The Button
elements can be easily replaced with TapGestureRecognizer
objects in XAML with no code changes.
A calculator, almost
The AddingMachine sample makes use of both the Execute
and CanExecute
methods of ICommand
. It uses an AdderViewModel
class in the Xamarin.FormsBook.Toolkit library. The ViewModel contains six properties of type ICommand
. These are initialized from the Command
constructor and Command
constructor of Command
and the Command<T>
constructor of Command<T>
. The numeric keys of the adding machine are all bound to the property that is initialized with Command<T>
, and a string
argument to Execute
and CanExecute
identifies the particular key.
ViewModels and the application lifecycle
The AdderViewModel
used in the AddingMachine sample also defines two methods named SaveState
and RestoreState
. These methods are called from the application when it goes to sleep and when it starts up again.