ReactiveUI Tutorial for Xamarin: The ViewModel

Introduction

The documentation about ReactiveUI is getting better, but sometimes another point of view can make the click in your head. It took me a while before I could get my head around ReactiveUI. One of the reasons was that I couldn’t find my way in the framework. I already wrote a post about ReactiveUI cf Getting started with Xamarin Forms and ReactiveUI, but I didn’t go into much details. With this post I hope to give you a better understanding of the framework.

ReactiveUI isn’t an all or nothing framework. It can help you out with small things. ReactiveUI can be used with Xamarin.Android, Xamarin.iOS and Xamarin.Forms. Although Xamarin.iOS and Xamarin.Android don’t have the binding concept out of the box, ReactiveUI lets you define it via code (MVVMCross does it as well).

The beginning

In this tutorial we start small and use ReactiveUI only in our ViewModel. A ViewModel contains 2 basic concepts:

  • Bindable properties
  • Commands

This blogpost is all about taming those two concepts in ReactiveUI.

Meet SwapiRui

Last I discovered a public REST API with Star Wars info. I’ll be using that API to work with some data. The API can be found on SWAPI - The Star Wars API. A mix of that API with ReactiveUI simply became SwapiRui.

Setup XForms solution

To force using the MVVM pattern, I’ve created a UI project which will contain all our views and a Core project which will contain our logic/viewmodels. The UI project can have a reference to the Core project because views may know about the viewmodels (the other way around is not true).

Default Xamarin way of bindings

We’ll create an easy page to recap how we use to bind our views to our viewmodels.

<ContentPage.Content>
    <StackLayout HorizontalOptions="CenterAndExpand" 
			VerticalOptions="CenterAndExpand" 
			Padding="30">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="2*" />
		      </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
               <RowDefinition Height="*" />
               <RowDefinition Height="*" />
               <RowDefinition Height="*" />
               <RowDefinition Height="*" />
               <RowDefinition Height="*" />
		      </Grid.RowDefinitions>

            <Label Text="FirstName" />
            <Entry Text="{Binding FirstName}" Grid.Column="1" />

            <Label Text="LastName" Grid.Row="1" />
            <Entry Text="{Binding LastName}" Grid.Row="1" Grid.Column="1" />

				<Label Text="{Binding FullName}" Grid.Row="2" Grid.Column="1" />

            <Button Command="{Binding SaveCommand}" Text="Save" Grid.Row="3" Grid.ColumnSpan="2" />

            <Label Text="{Binding Result}" Grid.Row="4" Grid.ColumnSpan="2" />
        </Grid>
    </StackLayout>
</ContentPage.Content>

The goal is very simple: provide a first name and a last name. When you click on the button you get a message with “Saved firstname lastname”

In the code behind we just need to set the BindingContext to our ViewModel

public OldPage()
{
    InitializeComponent();
    this.BindingContext = new OldViewModel();
}

Our OldViewModel needs to implement the INotifyPropertyChanged interface so our Views can get notified when something changes in our ViewModel.

public event PropertyChangedEventHandler PropertyChanged = delegate { };
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}

Now we can set up our FirstName, LastName and Result property in a way we notify subscribers when the value is changed

private string firstName = "";
public string FirstName
{
    get { return firstName; }
    set
    {
        if (EqualityComparer<string>.Default.Equals(firstName, value))
            return;
        firstName = value;
        OnPropertyChanged();
    }
}

private string lastName = "";
public string LastName
{
    get { return lastName; }
    set
    {
        if (EqualityComparer<string>.Default.Equals(lastName, value))
            return;
        lastName = value;
        OnPropertyChanged();
    }
}

private string result = "";
public string Result
{
    get { return result; }
    set
    {
        if (EqualityComparer<string>.Default.Equals(result, value))
            return;
        result = value;
        OnPropertyChanged();
    }
}

We can bind our button via a command. To make use of commands we need to reference to the Xamarin.Forms lib. Although we avoided referencing our views by splitting the UI in another project, now we need to reference Xamarin.Forms (which contains a lot of views). It doesn’t feel really wrong, but it doesn’t feel good either.

The command implementation in the OldViewModel looks like:

private ICommand saveCommand;
public ICommand SaveCommand
{
    get { return saveCommand ?? (saveCommand = new Command(() => ExecuteSaveCommand())); }
}

private void ExecuteSaveCommand()
{
    Result = $"Saved {FirstName} {LastName}";
}

Facing complexity where things should be easy

Say you want to visualise the FullName of the person. How can we set the Result directly? Well, you need to update the Result when changing the FirstName or LastName

private string firstName = "";
public string FirstName
{
    get { return firstName; }
    set
    {
        if (EqualityComparer<string>.Default.Equals(firstName, value))
            return;
        firstName = value;
        OnPropertyChanged();
        Result = FirstName + " " + LastName;
    }
}

private string lastName = "";
public string LastName
{
    get { return lastName; }
    set
    {
        if (EqualityComparer<string>.Default.Equals(lastName, value))
            return;
        lastName = value;
        OnPropertyChanged();
        Result = FirstName + " " + LastName;
    }
}

Yes, you can also create a method to update the Result, but the problem stays the same: you’ll face complexity very fast. And it’s kind of ugly to change the code in your properties to describe what needs to happen. And if you thing about the checks you need to implement to verify if the user may click on the button, you better start writing some unit tests.

Meet ReactiveUI

ReactiveUI is a framework that can help us out with writing our code in a more declarative way. So what does that mean? Well, you write your statements in such a way that you tell what you want to achieve as a result. So it’s less about how you want it to be done (=imperative style). For all this, ReactiveUI makes use of Reactive Extensions (Rx).

ReactiveUI vs Reactive Extensions

Can’t we just use Rx? You can, but when creating UI apps ReactiveUI makes it easier to use Rx. ReactiveUI provides a lot of helper methods and easy ways to combine your UI and UI logic with observables. For example: with default Rx, you can’t just bind to an Observable, but with ReactiveUI it becomes simple.

Getting started

To start with ReactiveUI we’ll rework the example above and use RxUI instead of the default Xamarin implementation. First add the ReactiveUI NuGet package to your projects.

I’ve created a PersonPage that is exactly the same as the OldPage. Only in the code behind the binding context is set to a PersonViewModel

public PersonPage()
{
    InitializeComponent();
    this.BindingContext = new PersonViewModel();
}

ReactiveObject

ReactiveObject is a base class for your ViewModels. The PersonViewModel doesn’t implement the INotifyPropertyChanged interface but inherits from ReactiveObject. ReactiveObject gives you a nice way to implement a property and let subscribers know that the property was changed

In RxUI you make a distinction between read-only properties and read-write properties.

Read-write property

Our FirstName and LastName are read-write properties. When the property is set we call the RxUI RaiseAndSetIfChanged method. Behind the scenes RxUI backs your property with an observable. That means that every change on your property is an event in a sequence.

private string firstName;
public string FirstName
{
    get { return firstName; }
    set { this.RaiseAndSetIfChanged(ref firstName, value); }
}

Read-only property (= output property)

Unique to the RxUI framework is a readonly property. When working with Rx you end up using observables. But observables aren’t properties you can bind to. With an output property you can take an observable and make it appear like a property. As a result, when you access the property you get the last value that fired of the observable. So it is like a Rx behavior subject that holds on to the latest value and wraps it in a property.

What we want is that the FullName appears in a label as we type the FirstName and LastName. When typing the FirstName, we get an event with each character we type. It’s a stream of events. The same is true for LastName. So what we want is combine those two streams into a new stream and output the new stream into our FullName property.

Our read-only property looks like:

private readonly ObservableAsPropertyHelper<string> fullName;
public string FullName
{
    get { return fullName.Value; }
}

Now we need to create an observable that listens to the changes of our FirstName and LastName property. ReactiveUI helps you out with WhenAnyValue (it becomes available when inheriting from ReactiveObject)

public PersonViewModel()
{
    fullName = this.WhenAnyValue(vm => vm.FirstName,
				          vm => vm.LastName,
			              (first, last) => $"{first} {last}")
			          .ToProperty(this, vm => vm.FullName, out fullName);
}
  • vm => vm.FirstName takes the FirstName property of our ViewModel
  • vm => vm.LastName takes the LastName property of our ViewModel
  • (first, last) => $”{first} {last}”) takes the previous two and defines a Func, in our case the first and last name with a space between
  • ToProperty transforms the sequence into the output property.

The relationship between WhenAny and ToProperty

So we’ve seen the use of WhenAny and ToProperty. You can conclude that those two are opposites: WhenAny transforms a property into an observable and ToProperty transforms an observable into a property

The code that setup that relationship will most of the time live in the constructor of your ViewModel.

Commands

We can bind button clicks to a default ICommand, but ReactiveUI has a smarter implementation called ReactiveCommand. I you think about what your user does before clicking a button, you know the context is changing constantly. And that is a perfect candidate for an observable of bool. ReactiveCommand uses it to know whether you’re allowed to trigger a command. ReactiveCommand also helps you with async stuff. If, for example, you call a web service, you don’t want the user to click the button again while your call is still ongoing. With ICommand you can add all kind of IsBusy checks, but if your UI becomes more complex, the IsBusy checks will quickly become a hassle.

A basic ReactiveCommand is:

public PersonViewModel()
{
    SaveCommand = ReactiveCommand.CreateFromTask(async () =>
	  {
	      await Task.Delay(2000);
    });
}
public ReactiveCommand<Unit, Unit> SaveCommand { get; private set; }

If you bind it to your button you’ll notice that the Save button will be disabled for 2 seconds. Even more, notice that your UI is still responsive. So ReactiveUI seamlessly swaps between the background thread (where your Task.Delay is executed) and the UI thread. Like I said, it’s an improved implementation of ICommand.

You can subscribe to a ReactiveCommand and pass in an observer so you get notified every time the command is executed, an error occurred or the observable ends (which won’t happen on a button). Now if we want to give a message to the user that our name was saved we can subscribe to the ReactiveCommand. This sounds like a good option for a readonly property, don’t you think? Well, we can make use of the ToProperty extension method:

public PersonViewModel()
{
    SaveCommand = ReactiveCommand.CreateFromTask(async () =>
    {
        await Task.Delay(2000);
        return DateTime.UtcNow;
    });
    SaveCommand.Select(x => "Saved on " + x.ToString()).ToProperty(this, vm => vm.Result);
}

public ReactiveCommand<Unit, DateTime> SaveCommand { get; private set; }

private readonly ObservableAsPropertyHelper<string> result;
public string Result
{
    get { return result.Value; }
}

All the power of Rx

Now we know how to create the observables, we can make use of all the power Rx gives us.

Conclusion

You can get started with ReactiveUI in an easy way. It’s a matter of transforming your stuff into observables or transform observables into properties or commands. You can use ReactiveUI to describe relationships and as a result work in a more declarative way.

Download

Download the code from my GitHub. Checkout the tag ViewModel on the Master branch.