Setting up a ReactiveUI ViewModel
Introduction
In this article, we will be setting up our first ViewModel to bind to the ListView that we created in the previous article. We'll be using the ReactiveUI framework for implementing our ViewModel and bindings.
Installing ReactiveUI Packages
Let's start by adding the ReactiveUI NuGet packages. The NuGet packages that we need to install are "reactiveui-xamforms":
https://www.nuget.org/packages/reactiveui-xamforms/.
This will install all the dependencies required to start using ReactiveUI in our app.
You will also need to install the "reactiveui" package into both the FormsTutor.iOS and FormsTutor.Droid projects as well.
Creating the ViewModel
To get started we'll add a new folder called "ViewModels" to our FormsTutor project, and add a class called ArticlesViewModel.
The first thing we need to do to our new ArticlesViewModel is to define a base class of type ReactiveObject.
using ReactiveUI;
namespace FormsTutor
{
public class ArticlesViewModel : ReactiveObject
{
}
}
Now we'll add a property to our view model that will contain our list of articles that will be bound to our ListView. For now, we will set this up as a ReactiveList of strings.
using ReactiveUI;
namespace FormsTutor.ViewModels
{
public class ArticlesViewModel : ReactiveObject
{
ReactiveList<string> _articles;
public ReactiveList<string> Articles
{
get => _articles;
set => this.RaiseAndSetIfChanged(ref _articles, value);
}
public ArticlesViewModel()
{
Articles = new ReactiveList<string> { "Article 1", "Article 2", "Article 3", "Article 4" };
}
}
}
As you can see we first start by creating a private member called _articles, this will be used to store the article objects. We then add a property called Articles, the main purpose of setting up this property is to call the RaiseAndSetIfChanged extension method, to notify any bound views that the _articles object has been modified.
The RaiseAndSetIfChanged extension method fires both the PropertyChanged and PropertyChanging events.
You'll notice that we are using an ReactiveList, this is so that the bound view is notified of any changes to the items stored in the _articles member. If we just used a regular generic collection, any bound views would not be aware that the content of the collection had changed. See https://docs.reactiveui.net/en/user-guide/lists/
Binding the View
Now that we have created our ViewModel, we can now bind it to our view. There are two ways we can achieve this, one is by setting the BindingContext of the view and placing our binding instructions in our XAML, or by simply defining them in the code behind file for the view.
For this application we are going to use option two and define our bindings in the code behind.
We can now remove the static content in our ListView as per below example:
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="FormsTutor.ArticlesPage">
<ContentPage.Content>
<ListView x:Name="Articles"/>
</ContentPage.Content>
</ContentPage>
Before we define our binding we need to take care of some house keeping. Because of the way view lifecycles work we want to ensure that any of the bindings we set up are disposed of correctly when a view disappears.
The System.Reactive.Disposables namespace provides us with a class called CompositeDisposable to help us achieve this without having to keep track of all our bindings manually.
The below example code shows how we setup our view to use the CompositeDisposable class.
using System.Reactive.Disposables;
using Xamarin.Forms;
namespace FormsTutor
{
public partial class ArticlesPage : ContentPage
{
readonly CompositeDisposable _bindingsDisposable = new CompositeDisposable();
public ArticlesPage()
{
InitializeComponent();
}
protected override void OnDisappearing()
{
base.OnDisappearing();
_bindingsDisposable.Clear();
}
}
You'll see in the OnDisappearing method that we call _bindingsDisposable.Clear(), this disposes of any disposable objects that you have registered with the _bindingsDisposable object.
We now need to instantiate our ViewModel.
using System.Reactive.Disposables;
using Xamarin.Forms;
using ReactiveUI;
namespace FormsTutor
{
public partial class ArticlesPage : ContentPage, IViewFor<ArticlesViewModel>
{
readonly CompositeDisposable _bindingsDisposable = new CompositeDisposable();
public ArticlesPage()
{
InitializeComponent();
}
protected override void OnAppearing()
{
base.OnAppearing();
ViewModel = new ArticlesViewModel();
}
protected override void OnDisappearing()
{
base.OnDisappearing();
_bindingsDisposable.Clear();
}
#region ViewModel Setup
public ArticlesViewModel ViewModel { get; set; }
object IViewFor.ViewModel
{
get { return ViewModel; }
set { ViewModel = (ArticlesViewModel)value; }
}
#endregion
}
}
To bind our ViewModel to our view we need to implement the IViewFor interface and instantiate it when the view appears.
Once we have done the above, we just need to define our binding for the Articles ListView.
protected override void OnAppearing()
{
base.OnAppearing();
ViewModel = new ArticlesViewModel();
this.OneWayBind(ViewModel, vm => vm.Articles, v => v.Articles.ItemsSource).DisposeWith(_bindingsDisposable);
}
You'll notice in above that we use the extension method DisposeWith, this registers our binding with the _bindingsDisposable object so that it is disposed when the view disappears.
The final result will look something like this:
Summary
In this article we went through the basics of setting up your first ReactiveUI ViewModel, and binding it to your Xamarin.Forms view. I highly recommend reading this post on creating ViewModels with ReactiveUI http://log.paulbetts.org/creating-viewmodels-with-reactiveobject/.
Full source code for this post can be found here:
https://github.com/jamilgeor/FormsTutor/tree/master/Lesson03
References
ObservableCollection<T> Class
https://msdn.microsoft.com/en-us/library/ms668604(v=vs.110).aspx
CompositeDisposable Class
https://msdn.microsoft.com/en-us/library/system.reactive.disposables.compositedisposable(v=vs.103).aspx
Basic Property Binding
https://docs.reactiveui.net/en/user-guide/binding/
Creating ViewModels with ReactiveObject
http://log.paulbetts.org/creating-viewmodels-with-reactiveobject/