如何在WPF中跟踪按钮上的垃圾邮件点击次数

时间:2016-07-20 12:12:10

标签: wpf button

我有一个按钮,可以按x秒跳过视频。如果用户垃圾邮件点击该按钮,我的视频反复更新,这是一项昂贵的操作。阻止用户发送垃圾按钮的最佳方法是什么?我正在使用路由的ui命令,并希望将秒加起来并执行1次操作。这是延迟计时器的最佳实践吗?延迟操作10ms并重置每次点击的延迟?或者是否有内置到wpf中的内容可以提供帮助?

更新: 我想跟踪用户在垃圾邮件点击按钮时点击的次数

4 个答案:

答案 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添加了一个示例项目,并将为此问题添加更好的命令

https://github.com/sgreaves1/DelayedCommands

答案 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;
    }