如何在WPF中按住按钮一段时间来触发绑定命令

问题描述 投票:0回答:1

在WPF中,按钮命令触发正常是立即触发;但有时我们需要防止无意按下而误触发;那么如何按住按钮一段时间,比如1s,或者500ms,然后触发绑定命令。

我希望它能像行为一样工作,只需在 Xaml 中配置按钮的持续时间。

wpf button time
1个回答
0
投票

您可以使用

Task.Delay
和任务取消来延迟按钮操作。

要真正消除按钮的抖动(将一段时间内的多次点击解释为单次点击),您必须使用基于计时器的实现。但从你的问题来看,你似乎只是想要一个简单的延迟。

从用户体验的角度来看,延迟按钮点击会显着降低用户体验。这不是用户期望的按钮行为。而且,您必须按住按钮未知的时间才能调用该操作,这并不直观。我认为这是一种 UI 设计味道。

如果该按钮将调用关键操作,您应该考虑显示一个确认对话框(“您确定吗?”-“确定”或“取消”)。然后取消此对话框可以恢复原始值(或简单地吞下按钮操作)。
我认为这比使用延迟按钮要好得多(就用户体验而言)。
按钮是“点击即忘”的。有一些众所周知的例外情况,其中按住按钮(例如

RepeatButton
)会连续增加例如日期值。在所有其他场景中,按钮必须在单击时执行,其中按下状态的持续时间应该无关紧要。

以下示例创建一个自定义

DelayButton
,它支持所有单击模式(按下、释放、悬停)并延迟
Button.Click
事件和
Button.Command
调用:

<!-- Use DelayInMilliseconds="0" to use it as a normal button -->
<DelayButton DelayInMilliseconds="1000" />
public class DelayButton : Button
{
  public int DelayInMilliseconds
  {
    get => (int)GetValue(DelayInMillisecondsProperty);
    set => SetValue(DelayInMillisecondsProperty, value);
  }

  public static readonly DependencyProperty DelayInMillisecondsProperty = DependencyProperty.Register(
    nameof(DelayInMilliseconds),
    typeof(int),
    typeof(DelayButton),
    new PropertyMetadata(0));

  private CancellationTokenSource? delayCancellationTokenSource;
  private bool isClickValid;

  protected override async void OnMouseLeftButtonDown(MouseButtonEventArgs e)
  {
    try
    {
      this.delayCancellationTokenSource = new CancellationTokenSource();

      await Task.Delay(TimeSpan.FromMilliseconds(this.DelayInMilliseconds), this.delayCancellationTokenSource.Token);

      if (e.LeftButton is MouseButtonState.Pressed)
      {
        this.isClickValid = true;
        base.OnMouseLeftButtonDown(e);
      }
    }
    catch (OperationCanceledException)
    {
      return;
    }
    finally
    {
      this.delayCancellationTokenSource?.Dispose();
      this.delayCancellationTokenSource = null;
    }
  }

  protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
  {
    this.delayCancellationTokenSource?.Cancel();
    if (this.ClickMode is ClickMode.Release)
    {
      if (this.isClickValid)
      {
        base.OnMouseLeftButtonUp(e);
      }
    }
    else
    {
      base.OnMouseLeftButtonUp(e);
    }

    this.isClickValid = false;
  }

  protected override async void OnMouseEnter(MouseEventArgs e)
  {
    try
    {
      if (this.ClickMode is ClickMode.Hover)
      {
        this.delayCancellationTokenSource = new CancellationTokenSource();
        await Task.Delay(TimeSpan.FromMilliseconds(this.DelayInMilliseconds), this.delayCancellationTokenSource.Token);
      }

      base.OnMouseEnter(e);
    }
    catch (OperationCanceledException)
    {
      return;
    }
    finally
    {
      this.delayCancellationTokenSource?.Dispose();
      this.delayCancellationTokenSource = null;
    }
  }

  protected override void OnMouseLeave(MouseEventArgs e)
  {
    this.delayCancellationTokenSource?.Cancel();
    base.OnMouseLeave(e);
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.