我有一个按钮,可以按x秒跳过视频。如果用户垃圾邮件点击该按钮,我的视频反复更新,这是一项昂贵的操作。阻止用户发送垃圾按钮的最佳方法是什么?我正在使用路由的ui命令,并希望将秒加起来并执行1次操作。这是延迟计时器的最佳实践吗?延迟操作10ms并重置每次点击的延迟?或者是否有内置到wpf中的内容可以提供帮助?
更新: 我想跟踪用户在垃圾邮件点击按钮时点击的次数
答案 0 :(得分:0)
不确定内置 Command 执行此操作的能力,但您可以使用延迟(根据评论更新):
private int spamCount = 0;
private int delayValue = 0;
private object isHoldedLock = new object();
private bool isHolded = false;
public bool CanProceed(int delay, Action updateVideo)
{
lock (this.isHoldedLock)
{
if (this.isHolded)
{
this.spamCount++;
this.delayValue = delay;
return false;
}
this.isHolded = true;
this.delayValue = delay;
Task.Run(async () =>
{
while (this.delayValue > 0)
{
await Task.Delay(100);
this.delayValue -= 100;
}
updateVideo();
lock (this.isHoldedLock)
{
this.isHolded = false;
}
});
return true;
}
}
以任何您需要的方式在spamCount
内处理/重置SkipVideo
值。
在命令处理程序中使用:
private void InvokedFromCommand()
{
if (CanProceed(1000, SkipVideo()))
{
// SkipVideo();
}
}
答案 1 :(得分:0)
我真的希望异步方式有效,而我们正在尝试创建一个解决方案,随时告诉我所有错误和任何不良做法。
我决定使用调度程序计时器,即使我并不是真的想要。无法在网上找到更好的做法。
private TimeSpan overallSkipSpeed = TimeSpan.Zero;
private readonly TimeSpan Interval = TimeSpan.FromMilliseconds(400);
private DispatcherTimer _dispatcherTimer;
private TimeSpan _time;
// Execute command function
public void ExecuteClickCommand()
{
// If the timer isn't going create and start it
if (_dispatcherTimer == null)
{
overallSkipSpeed = TimeSpanToModifyBy(skipSpeed, skipForward);
_time = Interval;
_dispatcherTimer = new DispatcherTimer(Interval, DispatcherPriority.Normal, Tick, Application.Current.Dispatcher);
_dispatcherTimer.Start();
}
else // If the timer is going reset to interval
{
// THIS IS WHERE I ADDED MY SKIP VALUES TOGETHER
// So value from last click + value from this click
_dispatcherTimer.Stop();
_time = Interval;
_dispatcherTimer.Start();
}
}
// Method to run when timer ticks over
private void Tick(object sender, EventArgs eventArgs)
{
// if the timer has reached below zero
if (_time <= TimeSpan.Zero)
{
_dispatcherTimer.Stop();
_dispatcherTimer = null;
_time = TimeSpan.FromSeconds(0);
// HERE IS WHERE WE CAN NOW SKIP VIDEO BY
// THE SKIP SPEED WE HAVE ACCUMULATED
}
else
{
_time = _time.Add(-Interval);
}
}
答案 2 :(得分:0)
我已经更进了一步并创建了我自己的命令。
此命令的作用类似于中继命令,但如果在初始化时设置延迟时间跨度,则会延迟。您可以检索在执行方法中单击它的次数。
初始化命令:
ICommand DelayedClickCommand = new DelayedCommand(ExecuteDelayedClickCommand, TimeSpan.FromMilliseconds(200));
创建一个执行方法并检索点击的次数:
private void ExecuteClickCommand()
{
TimesClicked = ((DelayedCommand)ClickCommand).TimesClicked;
}
这是命令类:
public class DelayedCommand : ICommand
{
private readonly Action _methodToExecute;
private readonly Func<bool> _canExecuteEvaluator;
private readonly DispatcherTimer _dispatcherTimer;
public int TimesClicked;
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
/// <summary>
/// A command to stop the spamming of the <see cref="Execute"/> method
/// </summary>
/// <param name="methodToExecute">Method to run when command executes</param>
/// <param name="canExecuteEvaluator">Method used to determine if the command can execute</param>
/// <param name="delayTime">The cool down period required between click execution</param>
public DelayedCommand(Action methodToExecute, Func<bool> canExecuteEvaluator, TimeSpan delayTime)
{
_methodToExecute = methodToExecute;
_canExecuteEvaluator = canExecuteEvaluator;
_dispatcherTimer = new DispatcherTimer(delayTime, DispatcherPriority.Normal, Callback, Application.Current.Dispatcher);
}
/// <summary>
/// A command to stop the spamming of the <see cref="Execute"/> method
/// when no <see cref="CanExecute"/> method is required
/// </summary>
/// <param name="methodToExecute">Method to run when command executes</param>
/// <param name="delayTime">The cool down period required between click execution</param>
public DelayedCommand(Action methodToExecute, TimeSpan delayTime)
: this(methodToExecute, null, delayTime)
{
}
/// <summary>
/// A command when only a <see cref="Execute"/> method is needed
/// </summary>
/// <param name="methodToExecute">Method to run when command executes</param>
public DelayedCommand(Action methodToExecute)
: this(methodToExecute, null, TimeSpan.Zero)
{
}
/// <summary>
/// A command taking a <see cref="Execute"/> Method and a <see cref="CanExecute"/> method
/// </summary>
/// <param name="methodToExecute">Method to run when command executes</param>
/// <param name="canExecuteEvaluator">Method used to determine if the command can execute</param>
public DelayedCommand(Action methodToExecute, Func<bool> canExecuteEvaluator)
: this(methodToExecute, canExecuteEvaluator, TimeSpan.Zero)
{
}
public bool CanExecute(object parameter)
{
if (_canExecuteEvaluator == null)
{
return true;
}
return _canExecuteEvaluator.Invoke();
}
public void Execute(object parameter)
{
if (!_dispatcherTimer.IsEnabled)
TimesClicked = 0;
TimesClicked++;
_dispatcherTimer?.Stop();
_dispatcherTimer?.Start();
}
private void Callback(object sender, EventArgs eventArgs)
{
_dispatcherTimer.Stop();
_methodToExecute.Invoke();
}
}
注意:当你垃圾邮件时点击此命令,执行最后一次点击后直到200毫秒才会运行,从而产生滞后效果。我已经向git hub添加了一个示例项目,并将为此问题添加更好的命令
答案 3 :(得分:0)
猜猜我是这里最懒的人......
public class PostponeCommand : ICommand
{
private TimeSpan _delay;
private Action<object> _command;
private CancellationTokenSource _cancellation;
public PostponeCommand(Action<object> command, int delayMs)
{
this._command = command;
this._delay = TimeSpan.FromMilliseconds(delayMs);
}
public bool CanExecute(object parameter)
{
return true;
}
public async void Execute(object parameter)
{
_cancellation?.Cancel();
_cancellation = new CancellationTokenSource();
try
{
await Task.Delay(_delay, _cancellation.Token);
_command?.Invoke(parameter);
}
catch (TaskCanceledException ex)
{
// canceled
}
}
public event EventHandler CanExecuteChanged;
}