12

I have this code and I am wanting to move it into a view model:

resetButton.Clicked += async (sender, e) =>
{
   if (App.totalPhrasePoints < 100 || await App.phrasesPage.DisplayAlert(
                "Reset score",
                "You have " + App.totalPhrasePoints.ToString() + " points. Reset to 0 ? ", "Yes", "No"))
      App.DB.ResetPointsForSelectedPhrase(App.cfs);
};

I realize I will need to set up something like this:

In my XAML code;

<Button x:Name="resetButton" Text="Reset All Points to Zero" Command="{Binding ResetButtonClickedCommand}"/>

And in my C# code:

private ICommand resetButtonClickedCommand;

public ICommand ResetButtonClickedCommand
{
   get
   {
      return resetButtonClickedCommand ??
      (resetButtonClickedCommand = new Command(() =>
      {

      }));

    }

But how can I fit the async action into a command?

Wilson Vargas
  • 2,841
  • 1
  • 19
  • 28
Alan2
  • 23,493
  • 79
  • 256
  • 450

5 Answers5

27

You can try something like this:

(resetButtonClickedCommand = new Command(async () => await SomeMethod()));

async Task SomeMethod()
{
    // do stuff
}
Wilson Vargas
  • 2,841
  • 1
  • 19
  • 28
MaticDiba
  • 895
  • 1
  • 11
  • 19
  • Code slightly simpler if use the command subclass designed for this: `resetButtonClickedCommand = new AsyncCommand(SomeMethod);` – ToolmakerSteve Jan 16 '20 at 21:55
  • @Neil - sorry, my mistake. I thought it was a built-in subclass of `ICommand`, but I see that it is in my company's code base. [I have added an answer that defines `class AsyncCommand`](https://stackoverflow.com/a/63514672/199364). – ToolmakerSteve Aug 20 '20 at 23:56
11

And to expand on already provided answer, if you need to pass a parameter to the command, you can use something like

(resetButtonClickedCommand = new Command<object>(async (o) => await SomeMethod(o)));

async Task SomeMethod(object o)
{
    // do stuff with received object
}

You could replace object above by anything you want as well.

pixel
  • 9,653
  • 16
  • 82
  • 149
3

On further testing, this class may be overkill for most uses.

Despite the downvotes, chawala's answer works fine in my tests.

Importantly, the presence of async on the method declaration is sufficient to avoid blocking UI thread. Therefore, chawala's answer is "not broken"; does not merit those downvotes, imho.

To be clear: the explicit async => await answers are of course perfectly fine, without any issue. Use them if that gives you more confidence.

My answer was intended to make the call site cleaner. HOWEVER, maxc's first comment is correct: what I have done is no longer "identical" to the explicit async => await. So far, I haven't found any situation where that matters. Whether with or without async/await inside new Command, if you click a button several times quickly, all the clicks get queued. I've even tested with SomeMethod switching to a new page. I have yet to find any difference whatsoever to the explicit async/await. All answers on this page have identical results, in my tests.

async void works just as well as async Task, if you aren't using the Task result anyway, and you aren't adding any code to do something useful with any exceptions that occur during this method.

In this class code, see my comment "TBD: Consider adding exception-handling logic here.".

Or to put it another way: most devs are writing code where it makes no difference. If that's a problem, then its going to equally be a problem in their new Command(await () => async SomeMethod()); version.


Below is a convenience class. Using it simplifies combining commands with async.

If you have an async method like this (copied from accepted answer):

async Task SomeMethod()
{
    // do stuff
}

Without this class, using that async method in a Command looks like this (copied from accepted answer):

resetButtonClickedCommand = new Command(async () => await SomeMethod());

With the class, usage is streamlined:

resetButtonClickedCommand = new AsyncCommand(SomeMethod);

The result is equivalent to the slightly longer code line shown without using this class. Not a huge benefit, but its nice to have code that hides clutter, and gives a name to an often-used concept.


The benefit becomes more noticeable given a method that takes a parameter:

async Task SomeMethod(object param)
{
    // do stuff
}

Without class:

yourCommand = new Command(async (param) => await SomeMethod(param));

With class (same as the no-parameter case; compiler calls the appropriate constructor):

yourCommand = new AsyncCommand(SomeMethod);

Definition of class AsyncCommand:

using System;
using System.ComponentModel;
using System.Threading.Tasks;
using System.Windows.Input;

namespace MyUtilities
{
    /// <summary>
    /// Simplifies using an "async" method as the implementor of a Command.
    /// Given "async Task SomeMethod() { ... }", replaces "yourCommand = new Command(async () => await SomeMethod());"
    /// with "yourCommand = new AsyncCommand(SomeMethod);".
    /// Also works for methods that take a parameter: Given "async Task SomeMethod(object param) { ... }",
    /// Usage: "yourCommand = new Command(async (param) => await SomeMethod(param));" again becomes "yourCommand = new AsyncCommand(SomeMethod);".
    /// </summary>
    public class AsyncCommand : ICommand
    {
        Func<object, Task> _execute;
        Func<object, bool> _canExecute;

        /// <summary>
        /// Use this constructor for commands that have a command parameter.
        /// </summary>
        /// <param name="execute"></param>
        /// <param name="canExecute"></param>
        /// <param name="notificationSource"></param>
        public AsyncCommand(Func<object,Task> execute, Func<object, bool> canExecute = null, INotifyPropertyChanged notificationSource = null)
        {
            _execute = execute;
            _canExecute = canExecute ?? (_ => true);
            if (notificationSource != null) 
            {
                notificationSource.PropertyChanged += (s, e) => RaiseCanExecuteChanged();   
            }
        }

        /// <summary>
        /// Use this constructor for commands that don't have a command parameter.
        /// </summary>
        public AsyncCommand(Func<Task> execute, Func<bool> canExecute = null, INotifyPropertyChanged notificationSource = null)
            :this(_ => execute.Invoke(), _ => (canExecute ?? (() => true)).Invoke(), notificationSource)
        {
        }

        public bool CanExecute(object param = null) => _canExecute.Invoke(param);

        public Task ExecuteAsync(object param = null) => _execute.Invoke(param);

        public async void Execute(object param = null)
        {
            // TBD: Consider adding exception-handling logic here.
            // Without such logic, quoting https://learn.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming
            // "With async void methods, there is no Task object, so any exceptions thrown out of an async void method will be raised directly on the SynchronizationContext that was active when the async void method started."
            await ExecuteAsync(param);
        }

        public event EventHandler CanExecuteChanged;

        public void RaiseCanExecuteChanged()
        {
            CanExecuteChanged?.Invoke(this, EventArgs.Empty);
        }
    }

}

Re comments below about async void Execute. Both class Command and interface ICommand have method void Execute. Being compatible with those, means having the same method signature - so the usually recommended async Task MethodName() is not an option here. See links in my comments for discussion of the implications of having void here.

ToolmakerSteve
  • 18,547
  • 14
  • 94
  • 196
  • Most disliked answer in this question is one that suggests just using async void instead if async Task. And your answer is essentially that one, but with extra steps. It wraps my action in your class, and than executes it inside async void method (async void Execute). So what's the difference? Wouldn't it be easier just to make the action async void in the first place and just use new Command(SomeAction) – maxc137 Oct 03 '20 at 15:07
  • @МаксимКошевой - that is an excellent question. My imperfect understanding is: *if that method is **only** used within an event handler, then yes that is fine to do*. I was taking the conservative approach of having the method return a Task, just in case it became used elsewhere. In [best practices guide](https://learn.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming), *Figure 1 Summary of Asynchronous Programming Guidelines* regarding guidance "Avoid async void", we see *exception* "Event handlers". – ToolmakerSteve Oct 04 '20 at 19:04
  • @МаксимКошевой - Also, possibly relevant [SO discussion here](https://stackoverflow.com/questions/45447955/why-exactly-is-void-async-bad). Reading that, I realize that my answer is *incomplete*: there is no logic to cope with **exceptions** that happen during `await ExecuteAsync(param);`. Such logic added around/after that call gives programmer an opportunity to do something different with exceptions. Just be aware (from that guide): *"... exceptions thrown out of an async void method will be raised directly on the SynchronizationContext that was active when the async void method started."* – ToolmakerSteve Oct 04 '20 at 19:21
  • @maxc137 - On further testing, I have not found any situation where [chawala's downvoted answer](https://stackoverflow.com/a/46116067/199364) causes problems. Looks to me like XAML Command handlers are inherently "fire-and-forget", so the lack of async/await vs. `Command(async () => await ...` seems moot to me. I'd be very interested in any evidence to the contrary. Bottom line: my AsyncCommand class seems unnecessary. chawala's answer seems entirely workable. `async void` does ensure that UI is not blocked, which is what matters here. – ToolmakerSteve Oct 28 '21 at 02:38
1

To instance AsyncCommand with a parameter, is correct this approach:

this.SaveCommand = new AsyncCommand((o) => SaveCommandHandlerAsync (o));

or is need

Arghya Sadhu
  • 41,002
  • 9
  • 78
  • 107
  • The compiler will do this for you automatically, if the parameter is type `object`. So given declaration `Task SaveCommandHandlerAsync(object someParamName) { ... }`, the simpler usage `new AsyncCommand(SaveCommandHandlerAsync);` works also. NOTE for anyone else reading this: `AsyncCommand` is *not a built-in framework class*. Either use some MVVM framework that defines it, or write your own (as in my answer). – ToolmakerSteve Oct 04 '20 at 20:12
  • There is no AsyncCommand in Xamarin Forms. – Ângelo Polotto Jun 29 '21 at 19:04
  • 1
    @ÂngeloPolotto - you are right; I was the one who first mistakenly suggested it was built in. Please [see my answer](https://stackoverflow.com/a/63514672/199364) for an implementation. – ToolmakerSteve Oct 28 '21 at 01:57
-3

you can write this also:-

(resetButtonClickedCommand = new Command(DoSomething));

async void DoSomething()
{
    // do something
}

Note :- It shows warning at SomeMethod.

  • Despite the downvotes, I have not found any situation in which this causes problems. Interestingly, the latest C# compiler no longer gives a warning at `new Command(DoSomething))`. See the links on my comments on [my answer](https://stackoverflow.com/a/63514672/199364) for discussion of `async void`. The only consequence of the missing `await` vs `Command(async () => await ...)` is that `Command` returns before `DoSomething` completes. For a Command Handler, this is irrelevant, AFAIK. Command usage with XAML is inherently a "fire-and-forget" operation. – ToolmakerSteve Oct 28 '21 at 02:33