Summary of Chapter 18. MVVM
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.
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.)
INotifyPropertyChanged interface declares a single event named
PropertyChanged that indicates the property that has changed.
A ViewModel clock
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
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:
ICommand(defined in the
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
ICommand interface declares two methods and one event:
Executemethod with an argument of type
CanExecutemethod with an argument of type
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
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 can be easily replaced with
TapGestureRecognizer objects in XAML with no code changes.
A calculator, almost
The AddingMachine sample makes use of both the
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
CanExecute identifies the particular key.
ViewModels and the application lifecycle
AdderViewModel used in the AddingMachine sample also defines two methods named
RestoreState. These methods are called from the application when it goes to sleep and when it starts up again.