This post is a continuation on the UI Command Pattern : Part I where I go through different approaches for
ICommand
implementation with pros and cons.
I left out MvvmCross Command implementation in that post but now I have updated the sample application with
MvxAsyncCommand
. You can follow along with the same project from here: https://github.com/keozx/CleanRx/tree/master/src/samples/Commands
Comparison
Since my winner from last post is ReactiveCommand I present a framework command comparison including
ReactiveCommand
,
AsyncCommand
and
MvxAsyncCommand
given that to my surprise, MvvmCross has a very nice implementation of the Command, though still lacking of course the great versatility of
ReactiveCommand
but nonetheless a good option.
Feature | Async | MvxAsync | Reactive |
---|---|---|---|
Executes a simple bindable Action | ✔️ | ✔️ | ✔️ <T> |
Create from Task<T> (not async void) | ✔️ | ✔️ | ✔️ |
Retrieve unhandled exceptions | ✔️ | ❌ | ✔️ |
Observes boolean changes for "CanExecute" behavior through INPC (not RaiseCanExecute) | ❌ | ❌ | ✔️ *WhenAnyValue |
Observes IObservable ticks for "CanExecute" behavior | ❌ | ❌ | ✔️ |
Guards against double execution (double tap) | ❌ | ✔️ | ✔️ |
Returns a <T> result at end of execution | ❌ | ❌ | ✔️ |
Accessible "CanExecute" state | ❌ | ❌ | ✔️ |
Accessible "IsExecuting" state | ❌ | ❌ | ✔️ |
Subscribe to Completion and executes handler for <T> result | ❌ | ❌ | ❌ |
Cons
The biggest downside of
MvxCommand
is the lack of handling errors like
AsyncCommand
does, so if we want to handle unhandled exceptions we have to wrap it ourselves.
Pros
There is an overload constructor that takes a
CancellationToken
for the function being executed so you can cancel the task at a later point, this token is autogenerated so to cancel it from a button for example I think is not straightforward, still, this is not as interesting as the way
ReactiveCommand
handles cancellation in a functional state pulling way.
One of the great things of
MvxCommand
and
MvxAsyncCommand
is the ability to pass a boolean on instantiation, to indicate whether or not concurrent execution is allowed for a given command, this mimics
ReactiveCommand
double tap protection. Unfortunately that's all the advantage we have over
AsyncCommand
.
Conclusion
The ICommand implementation still has a winner in
ReactiveCommand
even though all the features are only accessible through the base and not only the interface, I think all is moving away from ICommand anyway, just look at how things are going in MAUI + MVU for example, is time for new UI paradigms and more efficient patterns. This is an exciting time for innovation, in the meantime let's make it all reactive!