试图防止多次快速按下按钮,但是按钮没有正确禁用

时间:2018-10-29 09:44:01

标签: c# xaml xamarin.forms

我遇到一种情况,试图阻止用户向按钮发送垃圾邮件,为此,我的命令将两个函数用作参数。第一个是确定按下哪个按钮然后执行适当导航操作的命令。现在,当您按下按钮时,会出现短暂的延迟,我认为是在加载数据的同时,然后按钮会在加载和显示新页面之前禁用毫秒。我希望他们在按下按钮后立即将其禁用,以使它们不会被发送垃圾邮件并加载多个相同类型的页面。

我要解决的此特定按钮按下操作使Page1 ViewModel从Web服务中检索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 :(得分:2)

我曾经遇到过这个问题。我的解决方法如下:

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"/>

希望这会有所帮助!

答案 1 :(得分:0)

这是最接近您的初始代码解决方案的地方:

    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值更改时,它将通知Button IsBusy已更改。并且它将忽略通过的点击。

通常,您不应在ViewModel ctor中进行任何长时间运行的操作,以使其尽可能简单。而是使用Page.OnAppearing通知ViewModel它可以开始加载。