Xamarin MVVM double click executes command twice and IsBusy doesnt work

Viewed 635

So I have a button which is bound to a Login command

    private ICommand loginCommand;
    public ICommand LoginCommand
    {
        get
        {
            if (loginCommand == null)
            {
                loginCommand = new Command(login, CanExecuteCommand);
            }
            return loginCommand;
        }
    }

The CanExecuteCommand action returns !IsBusy

In the login() action I start with IsBusy = true and end with IsBusy = false; In the setter of IsBusy I also call the ChangeCanExecute() method like this:

((Command)comm).ChangeCanExecute();

When I am debugging ChangeCanExecute is really called on the command instance at the start and end of the method. However, if I double click the button, it still calls the command twice. Why is that? What's the cleanest way to disable double clicks using MVVM... By the way, on another VM I use the same approach and it works totally fine but there in the executed command I call an async method so I use await. Maybe that's why it works there? In the login case I call a void method in the command so if I double click the button the calls simply get queued? I still don't understand why ChangeCanExecute+IsBusy is not enough.

P.S. While my commands are defined in the VM, IsBusy, CanExecuteCommand and the raising of the ChangeCanExecute event happen in the BaseViewModel.

Edit 1: In login() I have code like this: { IsBusy = true; DoSomething(); IsBusy = false;} This has the unexpected functionality I explained and it gets called twice. However, if I change this to be in a Task like I have it in my working VM, double tap is not possible, any clues? IsBusy = true; Task.Run(() => { DoSomething(); }).SafeFireAndForget(); IsBusy = false;

I looked through answers regarding this and they don't seem to use the MVVM approach and they offer solutions using TapGestureRecognizer / some other things which don't seem like a best MVVM practice.

1 Answers

In my opinion, what you described is the normal behavior based on the code you using. I think whether the command will be called twice is depending on the duration between your two click events.

For example, let's say your DoSomething(); takes 2 seconds(just an example) to finish. Then if the duration between your two click events less than 2 seconds, the command will only executed at one time and that's want you want. If the duration is more than 2 seconds, the command will be called twice.

It's the same even if you make the method async and await it.

If you want to prevent the double click in a period of time, you can just add await Task.Delay(1000); after DoSomething(); to prevent the double click in one second.

Related