Home > Software engineering >  Running `INavigation.PushModalAsync` synchronously in `Xamarin.Forms`
Running `INavigation.PushModalAsync` synchronously in `Xamarin.Forms`

Time:03-03

How to run INavigation.PushModalAsync synchronously?

By synchronously, I mean I want to block UI interactions when opening a modal page (e.g. disallowing opening two pages when tapping fast twice).

CodePudding user response:

There are two ways for your reference:

  1. There is an IsEnabled property in Button, you can first set IsEnabled to false when entering the method. This will make the Button unclickable. This prevents multiple clicks.

  2. You can lock inside your method. In this way, your logic code will only be executed once. Prevent the code from being executed multiple times due to multiple clicks.

    For information on how to use Lock, please refer to: lock statement.

CodePudding user response:

As Wen xu Li mentioned in his answer, disabling the UI when an operation is running is the best practice. Here's what that might look like in practice:

MainViewModel.cs

using MvvmHelpers;
using MvvmHelpers.Commands;

public class MainViewModel : ObservableObject {

    private readonly object longWorkLock = new object();

    private bool _isBusy;
    public bool IsBusy{
        get => _isBusy;
        set => SetProperty(ref _isBusy, value);
    }

    public ICommand DoLongWorkCommand { get; }
    public ICommand DoLongWorkAlternativeWithLock { get; }

    public MainViewModel(){
        DoLongWorkCommand = new AsyncCommand(DoLongWorkAsync);
        DoLongWorkAlternativeWithLock = new AsyncCommand(DoLongWorkAlternativeWithLockAsync);
    }

    private async Task DoLongWorkAsync(){
        if(IsBusy){
            return;
        }
        IsBusy = true;

        //simulate long running work
        await Task.Delay(1234);

        IsBusy = false;
    }

    private async Task DoLongWorkAlternativeWithLockAsync(){
        lock(longWorkLock){
            IsBusy = true;

            //simulate long running work
            await Task.Delay(1234);

            IsBusy = false;
        }
    }
}

MyPage.xaml

<Button
    Text="Do long work"
    Command="{Binding DoLongWorkCommand}"
    IsEnabled="{Binding IsBusy, Converter={StaticResource InvertBooleanConverter}}" />

<Button
    Text="Do long work (alternative with lock)"
    Command="{Binding DoLongWorkAlternativeWithLockCommand}"
    IsEnabled="{Binding IsBusy, Converter={StaticResource InvertBooleanConverter}}" />

Note that I'm using the MvvmHelpers library in this example.

  • Related