Proper way to implement ReactiveCommand.

What is it?

ReactiveCommand is a Reactive Extensions and asynchronous aware implementation of the ICommand interface and can be executed either synchronously or asynchronously.

What is it for?

It turns a method into an observable. Hence, we can bind it to any event, can observe it, get its result and do anything further.

Creating

Executing

There are many ways to execute a method, we can directly execute it or turn it into a command. Furthermore, the command also has many ways to let us execute it.

Hence, we need to know what we expect from the method:

  • If it is just a method in view model, view doesn’t care about it, we just directly execute it.
  • If the view need to observe it:
    1. For fire and forget: use “1” from Executing part
    2. For a command that needs checking use “2” from Executing part
    3. There is a sequence of commands like: A -> B -> C -> D and View only care about A and D we need to call B inside A by using “3” from Executing part

Sample code of implementation for a set of commands that need to be run in order: A -> B -> C -> D:

Performance in order from fastest to slowest:

  • Directly call
  • Await Execute()
  • Execute().Subcribe()
  • Invoke

Side Effects:

Actually, the binding is not real real-time like we think it is.

Just check out the following code:
command 2 and command 3 are supposed to be called after command 1 finished.

But, the result is not what we expected:

Command 2 was not called, why?

  • As we can see, command 2 and command 3 only can be executed when command 1 is finished.
  • When command 1 is finished, its IsExecuting changed to False to enable command 2 and command 3. But, at that time, this IsExecuting was not bound to CanExecute, so it won’t let us execute command2.
  • For command3, we got the Delay, after a short time (likes 100ms), everything was bound and had the expected value, so the command3 can be executed.

So, to avoid it, we have 3 options:

  1. Use delay (which is the worst).
  2. Use directly IsExecuting from the command without any binding.
  3. Call the needed command inside the executing command. (Recommended)