Попытка предотвратить несколько быстрых нажатий кнопок, но кнопки не отключаются должным образом - PullRequest
0 голосов
/ 29 октября 2018

У меня есть ситуация, когда я пытаюсь запретить пользователю спамить кнопку, и для этого у меня есть команда, принимающая две функции в качестве параметров. Первая - это команда, которая определяет, какая кнопка была нажата, а затем выполняет соответствующую навигационную операцию. В настоящее время, когда вы нажимаете кнопку, существует небольшая задержка, я предполагаю, что пока загружаются данные, а затем кнопки отключаются за миллисекунду до загрузки и представления новой страницы. Я хотел бы, чтобы они отключались сразу после нажатия кнопки, чтобы они не могли спамить, и загружали несколько страниц одного типа.

При нажатии этой конкретной кнопки, которую я пытаюсь разрешить, PageM ViewModel извлекает таблицу SQL из веб-службы. Вызов этого находится в конструкторе Page1ViewModel.

    NavigateAsyncCommand = new RelayCommandAsync<object>(NavigateAsync, CanClickButton);

    public async Task NavigateAsync(object parameter)
    {
        IsBusy = true;

        Xamarin.Forms.Button b = parameter as Xamarin.Forms.Button;
        string page = b.Text;

        switch (page)
        {
            case "Page1":
                await App.MainNavigation.PushAsync(new Views.Page1(), true);
                IsBusy = false;
                return;

            //More cases here
        }
    }

Вторая функция просто проверяет состояние IsBusy и возвращает обратное.

    public bool CanClickButton(object parameter)
    {
        return !IsBusy;
    }

В моем XAML мои кнопки реализованы следующим образом

        <Button x:Name="StartButton" 
             Command="{Binding NavigateAsyncCommand}" 
             CommandParameter="{Binding Source={x:Reference StartButton}}"
             Text="{Binding StartText}"
             Grid.Row="1"/>

Ответы [ 2 ]

0 голосов
/ 29 октября 2018

Я столкнулся с этим вопросом один раз. Я решил это следующим образом:

1) Я создал «обратный логический преобразователь»

public class ReverseBooleanConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        try
        {
            bool myValue = (bool)value;
            return !myValue ; 
        }
        catch { return true; } // or false
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return Convert(value, targetType, parameter, culture);
    }
}

2) Я ссылался на конвертер в заголовок xaml

xmlns:converters="clr-namespace:MyNamespace.Converters"

3) Я добавил конвертер в словарь ресурсов

<ResourceDictionary>
     <converters:ReverseBooleanConverter x:Key="ReverseBool" />
</ResourceDictionary>

4) На последнем шаге я связал IsEnabled со свойством IsBusy модели представления, используя приведенный выше преобразователь.

<Button x:Name="StartButton" 
    IsEnabled="{Binding IsBusy, Converter={StaticResource ReverseBool}}" 
    ...
    Grid.Row="1"/>

Надеюсь, это поможет!

0 голосов
/ 29 октября 2018

Вот наиболее близкий к вашему исходному решению код:

    NavigateCommand = new RelayCommandAsync<object>(NavigateAsync, CanNavigate);  

    ...
    private async Task NavigateAsync(object parameter)
    {
        if (IsBusy)
            return Task.CompletedTask;

        IsBusy = true;
        NavigateCommand.OnCanExecuteChanged();

        var page = (string) parameter;

        switch (page)
        {
            case "Page1":
                await App.MainNavigation.PushAsync(new Views.Page1(), true);

            //More cases here
        }

        IsBusy = false;
        NavigateCommand.OnCanExecuteChanged();
    }

    private bool CanNavigate(object parameter) => !IsBusy;

    ...
    <Button Command="{Binding NavigateCommand}" 
            CommandParameter="{Binding StartText}"
            Text="{Binding StartText}"
            Grid.Row="1"/>

Он будет информировать кнопку о том, что CanExecute меняется каждый раз, когда изменяется значение IsBusy. И он будет игнорировать клики, которые проходят через.

В общем, вы не должны запускать какие-либо длительные операции в ViewModel ctor, сохраняя их как можно более простыми. Вместо этого используйте Page.OnAppearing, чтобы сообщить ViewModel, что он может начать загрузку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...