-1

If I have this...

<ContentPage.ToolbarItems>
    <ToolbarItem  Text = "Done" Clicked="Done_Clicked" />
    <ToolbarItem Text = "Cancel" Clicked="Cancel_Clicked" Priority="1" />
</ContentPage.ToolbarItems>

In the code behind...

async void Cancel_Clicked(object sender, EventArgs e)
{
    await Navigation.PopModalAsync();
}

How does the tool bar item know that its handler is asynchronous?

Ian Warburton
  • 15,170
  • 23
  • 107
  • 189

2 Answers2

2

Cancel_Clicked handler returns void so your toolbar item (UI Thread) can't know if your method is asynchronous.

Edit:
Inner method PopModalAsync() will run asynchronously - it will finish work in some time in the future. Cancel_Clicked() will return immediately, and for UI thread it is synchronous operation.

Thowk
  • 386
  • 4
  • 15
1

It doesn't, you need to use a 3rd party library that provides async commands. Personally I like Nito.Mvvm.Async, it gives you a AsyncCommand you can use and bind your functions to. The button will be disabled while the async function runs and will re-enable once the function is complete.

<ContentPage.ToolbarItems>
    <ToolbarItem Text = "Done" Command="{Binding DoneCommand}" />
    <ToolbarItem Text = "Cancel" Command="{Binding CancelCommand}" Priority="1" />
</ContentPage.ToolbarItems>

in your view moodel.

public MyViewModel()
{
    CancelCommand = new AsyncCommand(ExecuteCancel);
}

public AsyncCommand CancelCommand {get;}

async Task ExecuteCancel()
{
    await Navigation.PopModalAsync();
}

Here is a more complex version that disables the cancel option unless the Done option is currently running.

<ContentPage.ToolbarItems>
    <ToolbarItem Text = "Done" Command="{Binding DoneCommand}" />
    <ToolbarItem Text = "Cancel" Command="{Binding CancelCommand}" Priority="1" />
</ContentPage.ToolbarItems>

in your view moodel.

    public MyViewModel()
    {
        DoneCommand = new AsyncCommand(ExecuteDone);
        CancelCommand = new CustomAsyncCommand(ExecuteCancel, CanExecuteCancel);
        PropertyChangedEventManager.AddHandler(DoneCommand, (sender, e) => CancelCommand.OnCanExecuteChanged(), nameof(DoneCommand.IsExecuting));
        PropertyChangedEventManager.AddHandler(CancelCommand, (sender, e) => CancelCommand.OnCanExecuteChanged(), nameof(CancelCommand.IsExecuting));
    }

    private bool CanExecuteCancel()
    {
        return DoneCommand.IsExecuting && !CancelCommand.IsExecuting;
    }

    public AsyncCommand DoneCommand { get; }
    public CustomAsyncCommand CancelCommand { get; }

    async Task ExecuteDone()
    {
        await ... //Do stuff

    }

    async Task ExecuteCancel()
    {
        await Navigation.PopModalAsync();
    }
Scott Chamberlain
  • 124,994
  • 33
  • 282
  • 431