Home .NET Introduction to ReactiveUI: pumping properties in ViewModel

Introduction to ReactiveUI: pumping properties in ViewModel

by admin

In my C# projects, I often use the ReactiveUIframework in my GUI implementations.
ReactiveUI – A complete MVVM framework: bindings, routing, message bus, commands and other words that are in the description of almost every MVVM framework are here too.It can be used almost anywhere with .NET: WPF, Windows Forms, UWP, Windows Phone 8, Windows Store, Xamarin.
Of course, if you already have experience with it, you’re unlikely to find anything new here. In this article we’ll get acquainted with its basic features related to properties in ViewModel and hopefully in the future we’ll get to other more interesting and complex features.

Introduction

ReactiveUI is built around a reactive programming model and uses Reactive Extensions (Rx). However, I am not going to write a guide on reactive programming. I will only explain how things work when necessary. You will soon see for yourself that to use the basic features you don’t even need to know a lot about reactive programming. Although you are already familiar with it, this is exactly what it is. Usually even in the places where "reactive" occurs it is quite easy to read the code and understand what will happen. Of course, if you use the library (and Reactive Extensions) to its fullest extent, you’ll have to get seriously familiar with the reactive model, but for now we’ll go with the basics.
What I personally like about ReactiveUI is its unobtrusive nature: you can use only some subset of its features without paying attention to others and without modifying your application to the framework. Even, for example, use it side by side with other frameworks without incompatibilities. Pretty handy.
There is also a fly in the ointment. Its name is documentation. It’s very bad. There is something here , but many of the pages are just stubs, and everything is very dry. There is documentation here but the problem is the same: stubs, some copypastes from the developers chat, links to examples of applications in different sources, descriptions of features of the future version and so on. The developers are pretty active in answering questions on StackOverflow, but many questions would be absent if there were normal documentation. However, what we don’t have, we don’t have.

What we are going to talk about

Let’s move on to specifics. In this article, let’s talk about a typical problem with properties in ViewModels, and how it’s solved in ReactiveUI. Of course, this problem is the INotifyPropertyChanged interface; a problem that is solved in one way or another in different ways.
Let’s look at the classic implementation :

private string _firstName;public string FirstName{get { return _firstName; }set{if (value == _firstName) return;_firstName = value;OnPropertyChanged();}}public event PropertyChangedEventHandler PropertyChanged;protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null){PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));}

What’s the problem? I don’t think so. Well, three lines in the setter, no big deal. I usually write an autoproperty and do auto-refactoring with resharper in the given form, minimum of fuss.
But there are still problems. What if you need to synchronize FullName property when changing FirstName? There are two options: either this is a calculated property and you just need to generate an event about its change, or it needs to be implemented similar to FirstName and you need to change it. In the first case, the FirstName property setter will generate the required notification :

set{if (value == _firstName) return;_firstName = value;OnPropertyChanged();OnPropertyChanged(nameof(FullName));}

The second one will call the property update and it will generate a notification by itself :

set{if (value == _firstName) return;_firstName = value;OnPropertyChanged();UpdateFullName();}private void UpdateFullName(){FullName = $"{FirstName} {LastName}";}

It still looks relatively simple, but it’s a road to hell. There’s also LastName, which should also change FullName. Then we’ll add a search by typed name, and things will get even more complicated. And then some more and some more… And we end up in a situation where the code is full of generating events, a lot of actions are run from setters, some errors occur because not all possible execution paths are taken into account or something is called in the wrong order, and other nightmares.
And anyway, why does the FirstName property know that there is a FullName somewhere, and that you have to run a search by name? That’s not its concern. It should change and report that. Yes, you can do that, and for calling additional actions you can hook into your own PropertyChanged event, but there’s little joy in doing that – manually sorting out those events with the name of the changed property coming in the string.
And the simple implementation given in the beginning gets annoying anyway: almost the same code which I still have to read, where an error can creep in…

What does ReactiveUI offer us?

Declarability and bringing dependencies into order.
Let’s install it from Nuget. Search for "reactiveui", I put the current version 6.5.0. Now go to the list of available updates and update Splat there to the latest version (currently 1.6.2). Without it, I had everything crashed at one point.
Now that we’ve installed the framework, let’s try to improve our first example a bit. First, we inherit from ReactiveObject and rewrite the property setters :

public class PersonViewModel : ReactiveObject{private string _firstName;public string FirstName{get { return _firstName; }set{this.RaiseAndSetIfChanged(ref _firstName, value);UpdateFullName();}}private string _lastName;public string LastName{get { return _lastName; }set{this.RaiseAndSetIfChanged(ref _lastName, value);UpdateFullName();}}private string _fullName;public string FullName{get { return _fullName; }private set{this.RaiseAndSetIfChanged(ref _fullName, value);}}private void UpdateFullName(){FullName = $"{FirstName} {LastName}";}}

Not a lot so far. This kind of RaiseAndSetIfChanged could have been written by hand. But it’s worth saying right away that ReactiveObject implements more than just INPC:
Introduction to ReactiveUI: pumping properties in ViewModel
Here we see in particular the implementation of INotifyPropertyChanged, INotifyPropertyChanging and some three IObservable<> .

Read more about jet model

It’s worth saying a few words here about what these IObservable are. They are reactive (push-based) notification providers. The principle is quite simple: in the classic pull-based model we run to the data providers and poll them for updates. In reactive model we subscribe to this notification channel and don’t worry about polling, all updates will come to us by themselves:

public interface IObservable<out T>{IDisposable Subscribe(IObserver<T> observer);}

We act as IObserver<> -observer :

public interface IObserver<in T>{void OnNext(T value);void OnError(Exception error);void OnCompleted();}

OnNext is called when the next notification appears. OnError – if an error occurs. OnCompleted – when the notifications are over.
At any time you can unsubscribe from new notifications: for this method Subscribe returns some IDisposable. Call Dispose and no new notifications come in.
Now if we subscribe to Changed and change the FirstName, the OnNext method will be called and the parameters will have the same information as in the PropertyChanged event (i.e. the sender reference and property name).
And also here we have a lot of methods at our disposal, some of which come from LINQ. Select we have already tried. What else can we do? You can filter the notification stream using Where, make a Distinct of repeated notifications or DistinctUntilChanged to avoid consecutive identical notifications, use Take, Skip and other LINQ methods.
Let’s look at an example of using Rx

var observable = Enumerable.Range(1, 4).ToObservable();observable.Subscribe(Observer.Create<int> (i => Console.WriteLine(i), e => Console.WriteLine(e), () => Console.WriteLine("Taking numbers: complete")));//1//2//3//4//Taking numbers: completeobservable.Select(i => i*i).Subscribe(Observer.Create<int> (i => Console.WriteLine(i), e => Console.WriteLine(e), () => Console.WriteLine("Taking squares: complete")));//1//4//9//16//Taking squares: completeobservable.Take(2).Subscribe(Observer.Create<int> (i => Console.WriteLine(i), e => Console.WriteLine(e), () => Console.WriteLine("Taking two items: complete")));//1//2//Taking two items: completeobservable.Where(i => i % 2 != 0).Subscribe(Observer.Create<int> (i => Console.WriteLine(i), e => Console.WriteLine(e), () => Console.WriteLine("Taking odd numbers: complete")));//1//3//Taking odd numbers: complete

Here’s here You can move all these notifications around in time and see how things work.
It’s pretty short, but I think that’s enough for now. You can read more, for example, here Or here

Linking properties using ReactiveUI

Let’s go back to improving our problem code. Let’s tidy up the dependencies :

public class PersonViewModel : ReactiveObject{private string _firstName;public string FirstName{get { return _firstName; }set { this.RaiseAndSetIfChanged(ref _firstName, value); }}private string _lastName;public string LastName{get { return _lastName; }set { this.RaiseAndSetIfChanged(ref _lastName, value); }}private string _fullName;public string FullName{get { return _fullName; }private set { this.RaiseAndSetIfChanged(ref _fullName, value); }}public PersonViewModel(string firstName, string lastName){_firstName = firstName;_lastName = lastName;this.WhenAnyValue(vm => vm.FirstName, vm => vm.LastName).Subscribe(_ => UpdateFullName());}private void UpdateFullName(){FullName = $"{FirstName} {LastName}";}}

See, the properties no longer contain anything superfluous, all dependencies are described in one place : in the constructor. Here we say to subscribe to changes of FirstName and LastName, and when something changes – call UpdateFullName(). By the way, you can do it a little differently :

public PersonViewModel(...){...this.WhenAnyValue(vm => vm.FirstName, vm => vm.LastName).Subscribe(t => UpdateFullName(t));}private void UpdateFullName(Tuple<string, string> tuple){FullName = $"{tuple.Item1} {tuple.Item2}";}

The notification parameter is the tuple where the current property values lie. We can pass them to our full name update method. Although the update method can be omitted altogether and made like this :

this.WhenAnyValue(vm => vm.FirstName, vm => vm.LastName).Subscribe(t => { FullName = $"{t.Item1} {t.Item2}"; });

Now let’s look at FullName again:

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

Why do we need a supposedly modifiable property, when in fact it should depend entirely on parts of the name and be read-only? Let’s fix this :

private readonly ObservableAsPropertyHelper<string> _fullName;public string FullName => _fullName.Value;public PersonViewModel(...){..._fullName = this.WhenAnyValue(vm => vm.FirstName, vm => vm.LastName).Select(t => $"{t.Item1} {t.Item2}").ToProperty(this, vm => vm.FullName);}

ObservableAsPropertyHelper<> helps implement output properties. Inside is an IObservable, the property becomes read-only, but notifications are generated when changes are made.
By the way, besides what came from LINQ, there are other interesting methods for IObservable<> , such as Throttle:

_fullName = this.WhenAnyValue(vm => vm.FirstName, vm => vm.LastName).Select(t => $"{t.Item1} {t.Item2}").Throttle(TimeSpan.FromSeconds(1)).ToProperty(this, vm => vm.FullName);

This is where notifications are discarded if they are followed by a second. That is, as long as the user is typing something in the name input field, the FullName will not change. When he stops for at least a second, the FullName will update.

Result

Total code

using System.Reactive.Linq;namespace ReactiveUI.Guide.ViewModel{public class PersonViewModel : ReactiveObject{private string _firstName;public string FirstName{get { return _firstName; }set { this.RaiseAndSetIfChanged(ref _firstName, value); }}private string _lastName;public string LastName{get { return _lastName; }set { this.RaiseAndSetIfChanged(ref _lastName, value); }}private readonly ObservableAsPropertyHelper<string> _fullName;public string FullName => _fullName.Value;public PersonViewModel(string firstName, string lastName){_firstName = firstName;_lastName = lastName;_fullName = this.WhenAnyValue(vm => vm.FirstName, vm => vm.LastName).Select(t => $"{t.Item1} {t.Item2}").ToProperty(this, vm => vm.FullName);}}}

We got a ViewModel in which relationships between properties are described declaratively, in one place. I think this is a cool feature: no need to dig through all the code trying to figure out what happens when you change certain properties. No side-effects, everything is pretty obvious. Of course, the result of all these manipulations is some performance degradation. Although seriously, this problem should not arise: it is not the kernel of the system which is supposed to be as productive as possible, but the ViewModel layer.
I hope someone will find this article useful and interesting and you will try to use the described techniques in your projects. In the future I hope to describe things like reactive collections and commands and then get to more complex examples that show the interaction between View and ViewModel layers, routing and interaction with the user.
Thank you for your attention!

You may also like