What’s new in ReactiveUI: Refactoring MVVM commands

One of my Xamarin projects uses ReactiveUI as MVVM framework. Since version 7 of ReactiveUI is roughly a year old by now, I recently (finally) scheduled some time to clean up my code base and migrate everything to use the latest Reactive features. When I had initially updated all the ReactiveUI references to 7.0, I was a bit shocked about the amount of build errors this caused – it seemed to me that a lot of breaking changes had been introduced in the new version because nearly every class in the projects had multiple lines marked as erroneous. Fortunately, importing the ReactiveUI.Legacy namespace solved the problem for the moment, but it was obvious that I’d have to step through all these code lines now marked as obsolete and fix the issue in a more robust way.

The good news is:

  • After examining the issue in detail, it turned out that 7.x does not contain as many breaking changes as it seemed initially, but rather a few smaller ones (some of them not even breaking the build but changing the functionality of the app, but this is a separate story I’ll cover in another blog post) and only one major change: As stated in the official documentation, the implementation of ReactiveCommand has been rewritten, which obviously affects most ViewModel and many View classes.
  • The new way of declaring MVVM commands is much more flexible and can produce more robust code, so it makes sense to thoroughly refactor projects that reference ReactiveUI and handle each command on its own – this way, it is possible to decide which instantiation technique is best suited for each individual MVVM command.

What has changed in detail? I think the easiest way of discussing the changes is by looking at an example. In my old code base, most commands looked somewhat similar to the following snippet (note that most ViewModels obviously are a lot more complex, but for this sample I omitted everything that is not directly connected to the command for the sake simplicity):

public class MyViewModel
{
	public ReactiveCommand<Unit> SimpleCommand { get; }
	
	public ReactiveCommand<bool> AdvancedCommand { get; }
	
	public MyViewModel()
	{
		SimpleCommand = ReactiveCommand.CreateAsyncTask(_ => SimpleCommandImpl());
		
		AdvancedCommand = ReactiveCommand.CreateAsyncTask(this.WhenAnyValue(x => x.IsBusy).Select(x => !x),
			AdvancedCommandImpl);
	}
	
	private async Task SimpleCommandImpl()
	{
		// do something
	}
	
	private async Task<bool> AdvancedCommandImpl(object param)
	{
		// do something and return
	}
}	

A few things that I don’t like about this code (and, in fact, that always bothered me when working with ReactiveUI in the past):

  • All commands need to have a return type – if they actually do not return anything (fire and forget), the return type must be set to the Reactive-specific System.Reactive.Unit.
  • Commands may only receive parameters of type object. (I remember a section of the old documentation stating you shouldn’t use command parameters at all, presumable because of this limitation.)
  • The execution method of a command must be marked async Task, even if the method does not invoke any asynchronous business logic, and therefore it cannot directly be passed to CreateAsyncTask but a lambda must be used (although I have to admit there is a static Create method that can be used instead of CreateAsyncTask, but this one does not allow directly passing in an execution method, which is rather annoying).

In contrast, the same ViewModel using the ReactiveUI 7.x way of life looks quite different:

public class MyViewModel
{
	public ReactiveCommand<Unit, Unit> SimpleCommand { get; }
	
	public ReactiveCommand<int, bool> AdvancedCommand { get; }
	
	public MyViewModel()
	{
		SimpleCommand = ReactiveCommand.Create(SimpleCommandImpl);
		
		AdvancedCommand = ReactiveCommand.CreateFromTask(AdvancedCommandImpl,
			this.WhenAnyValue(x => x.IsBusy).Select(x => !x));
	}
	
	private void SimpleCommandImpl()
	{
		// do something
	}
	
	private async Task<bool> AdvancedCommandImpl(int param)
	{
		// do something and return
	}
}	

In summary, the following things have changed:

  • The static method for registering asynchronous methods to commands has changed its name to CreateFromTask, which is much more readable and self-explanatory in my opinion.
  • There is a separate static method for registering synchronous execution methods to commands, simply called Create. This means no more async methods that actually run synchronously.
  • All of the static registration methods (Create...) expect an (optional) canExecute condition as the second parameter, thus being consistent with other components of ReactiveUI and ensuring the execution method is always passed first.
  • ReactiveCommand declarations always contain two generic parameters: one for the input parameter passed into the command, one for the return type. If one of them is not provided, we use System.Reactive.Unit.
  • As a direct consequence of the former, command parameters can (and should!) be strongly types – this is actually the most useful change of the whole ReactiveCommand refactoring in my opinion!

Oh, and one more thing: In case you want to execute a command directly without binding it you’d call its ExecuteAsync method – this one is now just called Execute!