Reactive MVVM on the .NET Platform

Implementing the MVVM pattern with ReactiveUI and Fody

A portable and maintainable codebase is important, especially in large-scale and cross-platform .NET implementations. On XAML-based platforms, such as Windows Presentation Foundation (WPF), Universal Windows Platform (UWP), Xamarin Forms, and AvaloniaUI you can achieve maintainability goals by implementing the MVVM pattern.

The MVVM pattern in a nutshell.

MVVM stands for Model-View-ViewModel, where Model represents services, data transfer objects, and database entities related to the application domain, View is the UI and ViewModel’s responsibility is to tie these two layers together in a convenient way. ViewModel encapsulates interaction with Model, exposing properties and commands for XAML UI to bind to.

Traditional MVVM Implementation

To make bindings work a typical ViewModel should implement the INotifyPropertyChanged interface and call the PropertyChanged event when any of ViewModel’s properties change. A straightforward implementation may look like this:

With the following XAML describing our UI:

Works like a charm. When a user types their name into the text box, the text block placed below displays: “Hello, %username%!”. Values of these two controls stay synchronized — when the text box’s content changes, the text block updates itself immediately. Button clears the text box.

A simple demo app built on Universal Windows Platform

But wait! Our UI only needs two synchronized observable properties and one command, why do we have to write more than 20 lines of code to achieve that? What will happen, if we decide to add more properties representing ViewModel state? The code will bloat, becoming increasingly harder to understand and maintain!

Recipe #1. Observables. Shorter Getters And Setters. ReactiveUI

Well, the property change notifications boilerplate code issue is not new, and there are several solutions. Let’s take a look at ReactiveUI. It is a cross-platform, composable, functional reactive MVVM framework that brings the power of Reactive Extensions for the .NET platform. It also provides an INotifyPropertyChanged base class named ReactiveObject and a bunch of extension methods. Let’s modify our code snippet and see, how its reactive version looks like.

This snippet does exactly the same as the previous one but is shorter, more predictable, easier to understand and maintain. Property relations are described in one place using declarative ReactiveUI syntax. But this code is still quite verbose — we have to implement getters, setters, and backing fields explicitly.

Recipe #2. Boilerplate Code Encapsulation. Reactive Property

Another solution is to use reactive bindings from the ReactiveProperty library. This package provides wrapper classes responsible for sending notifications to the UI. Here ViewModel does not need to implement any interfaces, instead, each property implements INotifyPropertyChanged itself. Such properties also are observables — they can be mapped, filtered, combined, and so on. Let’s rewrite our sample using ReactiveProperty.

We only need to declare and initialize reactive properties and describe relations among them. No boilerplate code needed, except for property initializers. But this approach has a drawback — we should modify our XAML markup to make these bindings work as expected. Reactive properties themselves are wrappers, so UI needs to bind to each wrapper’s own property.

Recipe #3. Assembly Weaving. Fody + ReactiveUI

In a typical ViewModel, each property should send notifications to the UI when its value changes. With PropertyChanged.Fody package, a developer doesn’t have to take care of this. The only requirement is a ViewModel being marked with AddINotifyPropertyChangedInterface attribute — and code raising the property change event will be injected into setters automatically during the project build. If we need to turn our properties into observables, we can always use the WhenAnyValue extension method from ReactiveUI. Let’s rewrite our snippet again and see, how concise our code will become!

Fody manipulates the IL of an assembly at build time. PropertyChanged.Fody add-in searches for all classes implementing the INotifyPropertyChanged interface or marked with AddINotifyPropertyChangedInterface attribute, and modifies those classes’ property setters.

While this approach is great and allows us to write clean and simple code, outdated .NET Framework versions, including 4.5.1 and older ones, are no longer supported. This means you can actually use Fody with outdated versions but at your own risk while keeping in mind that any bugs found won’t ever get fixed. .NET Core versions are supported according to the .NET Core support policy.

Recipe #4. Assembly Weaving. ReactiveUI.Fody

Yet another option is to use the ReactiveUI.Fody package, which is now fully compatible with .NET Core. It works similarly to PropertyChanged.Fody, but uses the opt-in approach — you need to mark all properties with ReactiveUI.Fody attributes explicitly to have INotifyPropertyChanged boilerplate code injected into them at compile time. Additionally, this approach allows you to create get-only properties based on ObservableAsPropertyHelper that will always contain the latest value from an observable stream. Using readonly OAPHs in your codebase for describing computed properties allows you to benefit from compile-time checks that help you to ensure that your computed properties always contain the latest value from a certain IObservable<T> stream.

Hope this article helps you get started with implementing the MVVM pattern via Reactive Programming and keeping your code clean and concise. See the next chapter for more examples. If you are willing to learn ReactiveUI, check out the Getting Started tutorial and the ReactiveUI Handbook.

Full-stack developer, masters student, digital designer twitter.com/worldbeaterdev

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store