-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Extend Command to handle Tasks #1857
Comments
The Mvx implementation is pretty good with support for Cancellation and locking against multiple calls of the same Command |
Just my 2 cents: it's easy to add an utility class class which creates an |
@andreinitescu can you provide a more complete example of that? :-) . Thanks! |
The implementation within |
The NuGet package Nito.Mvvm.Async supports this too - Mvvm.Async
|
I think this is something best left out of Xamarin.Forms. An "async command" is misleading at best. In fact it gives you a false impression that you did your code correctly, while actually it provides you no guarantees. With an async command you start some asynchronous process in your application which executes independently of the main (GUI) thread of the program. This is no different from starting a Task in a fully synchronous IComman.Execute method. How this asynchronous process interacts with the rest of the program is fully dependent on the particular details of the methods and data structures and the async command cannot add anything to it. This will also create many confusing issues in unit tests depending on if you defined the command being tested as ICommand methods should be considered events (even MS docs say so). The elements that invoke a command will not invoke them in an async manner nor await their results. You will be writing much uglier code trying to implement an "async command' than either having an asyc void, or calling await in the delegate declaration itself. It is very characteristic what @StephenCleary ended up with in his "Patterns for Asynchronous MVVM Applications: Commands" blog post:
Actually the positive value of Mr. Cleary's approach is observable (bindable) Task properties, and this is not the same as async command per se. This is a much deeper conversation than just "add an async command". You're asking for a support nightmare if you add this to the Xamarin.Forms codebase. My 2 cents |
@brianlagunas well said. My example above was just for the sake of it. I personally never quite understood the reason for async commands |
This doesn't really belong in core but in a community project. Forms does not ship an MVVM toolkit, but instead strives to work with MVVM toolkits in general. |
@jassmith agreed, and there are already a number of OSS projects that have this. Nito.Mvvm.Async being a great option. |
I have re-phrased my original proposal and idea here a bit more. |
@jamesmontemagno You definitely can't modify the existing Command to implement async calls. This is definitely a no go. If you did this, then the ICommand.Execute would be an
That test validates that trying to extend Command to execute a Task when calling ICommand.Execute is not going to be an option. Essentially, what it looks lie you want to do, is make the COmmand API somewhat easier so that you can just supply a Task as a deegate and just have it work as if you had an
Would that be a fair representation? |
I do believe that this is closer to what I am looking for, however if we do implement a form of this AsyncCommand is it possible to improve this type of experience. Does the AsyncCommand need to handle things better async type of stuff? Or is what we are saying is the way to do it totally is: UpdateLocationCommand = new Command(async () => await ExecuteUpdateLocationCommand()); But with this helper command we would just make the API prettier and not change the functionality at all? |
I think if you were to provide a class called AsyncCommand, you would inherently open it up for many more async type features such a cancelling, possible dispatching of data from one thread to the UI, determining task completion, exception handling, managing what happens if the button is clicked more than once, etc. At that point, your at some fully baked async command infrastructure like Mr. Cleary's. From my point of view, having to write 17 more characters in order to have a Task based Execute method is not a show stopper considering the possible side-effects of having a separate AsyncCommand implementation. As I think about code sharing across platforms, being able to rely on ICommand.Execute behaving in a predictable and consistent way is extremely important. For what it's worth, Prism's guidance has been your supplied code snippet, or to have an async void Execute method, ever since we dropped our AsyncCommand implementation. ICommand methods are viewed as events, and having async void on an event handler is a required practice. |
Don't. No. Really bad idea. Especially in the core project. |
We also use a AsyncCommand for correctly handling long taking actions with a common errorhandling. |
@lightwaver Can you give an example what you use the async command for? Do you bind a Button's Command to an async command for example? Because in this situation the async doesn't help, XF just calls Execute on the command, which is not async. |
I actually agree with keeping this out of Xamarin.Forms, too. One of the problems with AsyncCommand is that it can mean a lot of different things to different |
Asynchronous Commands can not be implemented as a stable feature from Xamarin Forms team, until a lot of asynchronous support will be provided from the .Net. |
@andreinitescu We a common implementation, that allowes to execute async calls (most of the times REST-calls to the backend) that are not directly transparent to the ViewModel, because it's wrapped through business logic classes. To have a easy and common binding and exeption handling we created a AsyncCommand that implements ICommand. It simply sets the CanExecute to false (and calls the CanExecuteChanged event) before executing the Task and when the Task is Finished it re-enables CanExecuteAgain. I attached an simple implementation of it. Another more App specific Version also invokes a CommonBusyIndicator. Its a very simple version of it but it works :) - for most of the cases. And if you implement async/multithreaded things without care - you will end up in weird exceptions and locks... |
The basic problem with async commands in current .NET is that you have to start them at some point with an |
Yes that's what I meant... |
@jamesmontemagno i don't know if this solve 100% of your problem... But you can extend the Command and do this: https://github.com/pictos/AsyncCommand/blob/master/Asc/AsC/Helpers/AsyncCommand.cs I took the implementation of the hotel as a reference. So I can call a task in Command like that: MyCommand = new AsyncCommand(ExecuteMyCommand); |
@brianlagunas points ( |
This is a good outcome. |
Yippie... when will this feature be released ? |
@lightwaver It's not. It was closed becuase it will not be implemented. |
Ok, sorry was a bit confused by the baclog and done state ;) |
I have updated my issue here to be a bit more verbose.
Description
Today, the Xamarin.Forms implementation of ICommand only takes in a Action as the method to execute:
This works great when we are only working with simple methods that don't have to worry about async/await and Tasked based development. Once this comes into play as a developer we create some testable code and update the return value to a Task:
However, now that we have testable Task based code we can no longer use the constructor that exists and have to leverage hacky workarounds to execute our code:
The request here is to either enhance the existing Command that exists inside of Xamarin.Forms to handle this situation. Yes, I know that ICommands are events and we shouldn't do this stuff, but we have to in this day and age of development to be honest. This will help on-boarding when writing such code and seems to be what 80% of my Commands do today to be honest.
If we do not wish to modify the existing command we could introduce a new AsyncCommand, but it should still implement ICommand.
Discuss below.
The text was updated successfully, but these errors were encountered: