简体   繁体   English

单击 Xamarin Forms 后如何暂时禁用按钮?

[英]How to temporarily disable button after click in Xamarin Forms?

I am making a poll application in Xamarin Forms and I want users to be able to vote just one time/day.我正在Xamarin Forms中进行投票申请,我希望用户每天只能投票一次。 On the UI page, I created an ImageButton and I want the user to be able to click it just one time/day.在 UI 页面上,我创建了一个 ImageButton,我希望用户能够每天点击一次。 I tried using a Timer, and tried to test it for 5 seconds intervals.我尝试使用计时器,并尝试以 5 秒的间隔对其进行测试。 The Application disabled the button when I first clicked it but after 5 seconds I could click it all over again and it doesn't disable the button.应用程序在我第一次单击它时禁用了该按钮,但 5 秒后我可以再次单击它并且它不会禁用该按钮。

private void ImageButton_Clicked(object sender, EventArgs e)
{
   this.IsEnabled = false;
   Timer aTimer = new Timer();
   aTimer.Interval = 5000; //ms
   aTimer.Enabled = true;
   aTimer.Elapsed += ATimer_Elapsed;
}

private void ATimer_Elapsed(object sender, ElapsedEventArgs e)
{
  this.IsEnabled = true;       
}

I saw that the application enters the ImageButton_Clicked function all the time but it does not execute this.IsEnabled=false ;我看到应用程序一直输入ImageButton_Clicked function 但它没有执行this.IsEnabled=false ;

Try this code.试试这个代码。 I hope it is working.我希望它正在工作。

    private void ImageButton_Clicked(object sender, EventArgs e)
    {
           var btn = sender as ImageButton;
           btn.IsEnabled = false;
           Device.StartTimer(TimeSpan.FromSeconds(5), () =>
           {

                    btn.IsEnabled = true;
                    return false;
           });
    }

Actually, the application is doing what you have told it.实际上,该应用程序正在执行您告诉它的操作。

this.IsEnabled is working, but this is referencing the page itself. this.IsEnabled正在工作,但这是引用页面本身。 If you want on click to disable the button that has fired event, then you need this:如果要单击以禁用已触发事件的按钮,则需要:

private void ImageButton_Clicked(object sender, EventArgs e)
{
    if (sender is Button button)
    {
        button.IsEnabled = false;
        // the rest of the logic
    }
}

Here, we are casting the sender as a Xamarin.Forms.在这里,我们将sender转换为 Xamarin.Forms。 Button .按钮 If the cast is successful, meaning if the sender is our button, then we can disable it.如果转换成功,这意味着如果发送者是我们的按钮,那么我们可以禁用它。

If you don't want to cast it or you want do use the button reference in another method (like you are enabling it again), the simply set the button with a Name property in the xml like so:如果您不想转换它或者您想在另一种方法中使用按钮引用(就像您再次启用它一样),只需在 xml 中使用Name属性设置按钮,如下所示:

<Button 
    x:Name="myButton"
    Clicked="ImageButton_Clicked" />

Then, you can use it in the code-behind in the ATimer_Elapsed method like this:然后,您可以在ATimer_Elapsed方法的代码隐藏中使用它,如下所示:

private void ATimer_Elapsed(object sender, ElapsedEventArgs e)
{
    Device.BeginInvokeOnMainThread(() => { myButton.IsEnabled = true; });
}

Edit: It is very important to invoke the IsEnabled = true here on the main/UI thread, since the timer logic is being done on a background thread.编辑:在主/UI线程上调用IsEnabled = true非常重要,因为计时器逻辑是在后台线程上完成的。

The answer for this question is a bit long, but simple.这个问题的答案有点长,但很简单。

  • Create a custom button component because XF doesn't disable button and change the color properly (at least for me):创建一个自定义按钮组件,因为 XF 不会禁用按钮并正确更改颜色(至少对我而言):

    • XAML: XAML:
<?xml version="1.0" encoding="utf-8"?>

<Button xmlns="http://xamarin.com/schemas/2014/forms"
        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
        x:Class="LindeGctMobileApplication.Modules.CustomComponents.CustomButton.CustomButtonView"
        FontAttributes="Bold"
        TextColor="{StaticResource LightTextPrimary}"
        FontSize="20"
        TextTransform="Uppercase"
        CornerRadius="20"
        WidthRequest="200"
        HorizontalOptions="Center" />
  • Code behind:后面的代码:
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class CustomButtonView
{
   #region constructors

   public CustomButtonView()
   {
      InitializeComponent();
      BackgroundColor = Color.Blue;

      Clicked += (_, args) =>
      {
         if (IsEnabled) Command?.Execute(args);
      };
   }

   #endregion

   #region Command

   public new static readonly BindableProperty CommandProperty = BindableProperty.Create(
            nameof(Command),
            typeof(ICommand),
            typeof(CustomButtonView));

   public new ICommand? Command
   {
      get => (ICommand)GetValue(CommandProperty);
      set => SetValue(CommandProperty, value);
   }


   #endregion
        
   #region IsEnabled

   public new static readonly BindableProperty IsEnabledProperty = BindableProperty.Create(
            nameof(IsEnabled),
            typeof(bool),
            typeof(CustomButtonView),
            true,
            propertyChanged: (bindable, _, newValue) =>
   {
      var component = (CustomButtonView)bindable;

      if ((bool)newValue)
      {
         component.BackgroundColor = Color.Blue;
      }
      else
      {
         component.BackgroundColor = Color.Gray;
      }
   });

   public new bool IsEnabled
   {
      get => (bool)GetValue(IsEnabledProperty);

      set => SetValue(IsEnabledProperty, value);
   }

   #endregion
}
  • Add the CustomButton inside your screen XAML:在屏幕 XAML 中添加 CustomButton:
<customButton:CustomButtonView Text="Your Custom Button"
                               Command="{Binding ClickCommand}"
                               IsEnabled="{Binding IsEnabled}"/>
  • Create the following static class to debounce your buttons clicks, the user can click multiple times and the method will compute the time after last click, it will be used later:创建以下 static class 来消除按钮点击,用户可以点击多次,该方法将计算最后一次点击后的时间,稍后使用:
public static class CustomTaskExtension
{
   #region fields

   private static int _last;

   #endregion

   public static void Debounce(CancellationTokenSource throttleCts, double debounceTimeMs, Action action)
   {
      var current = Interlocked.Increment(ref _last);
      Task.Delay(TimeSpan.FromMilliseconds(debounceTimeMs), throttleCts.Token).ContinueWith(task =>
         {
            if (current == _last) action();
               task.Dispose();
         });
    }
}
  • Add the following property in your ViewModel:在 ViewModel 中添加以下属性:
private bool _isEnabled;

public bool IsEnabled
{
   get => _isEnabled;
   set
   {
      OnPropertyChanged("IsEnabled");
      _isEnabled = value;
   }
}
  • Add the following command to your button:将以下命令添加到您的按钮:
public ICommand ClickCommand => new Command(() => Click());

private void Click()
{
   // disable the button
   IsEnabled = false;
   
   // the debounce is used to enable the button after 5s of the last call of this method
   CustomTaskExtension.Debounce(new CancellationTokenSource(), 5000, () =>
   {
      IsEnabled = true;
   });
}

That's all Folks!这就是所有的人!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM