In order to make our applications fluid and responsive, it is necessary to control the number of accesses to time-consuming operations (call to the database, to the file system, etc.), to perform them as often as possible.

However, in some cases it is not possible to predict in advance whether a method will be called once or several times in a short period of time.

For example, when subscribing to an event CollectionChanged of one ObservableCollection or when an action is to be taken during a change of text.

A possible solution

One strategy for solving this problem is to control these costly accesses and perform them as little as possible.

In this context, I have developed a small helper, which delays the execution of an action, if an action is initiated by then the previous action will never be executed.

The use is very simple:

_delayActionHelper.ExecuteActionAfterDelay(async () =>
{
    AMethodExecuteOnlyOneTime();
});

Original illustration unavailable: DelayHelper

Implementation:

/// <summary>
/// Helper which delay an action. 
/// If the same action is trigger wait to run it
/// </summary>
public class DelayActionHelper
{
    #region Fields
    DispatcherTimer _timer;
    Action _action;
    DateTime _dateToExecute;
    readonly int _delaySeconds;
    #endregion

    public DelayActionHelper(int delaySeconds = 3)
    {
        _delaySeconds = delaySeconds;
    }
    /// <summary>
    /// Enables the timer.
    /// </summary>
    void EnableTimer()
    {
        if (_timer == null)
        {
            _timer = new DispatcherTimer();
            _timer.Interval = TimeSpan.FromSeconds(_delaySeconds);
            _timer.Tick += _timer_Tick;
        }
        if (!_timer.IsEnabled)
            _timer.Start();
    }

    private void _timer_Tick(object sender, object e)
    {
        //Si on peut exécuté l’action alors on l’exécute…
        if (DateTime.Now > _dateToExecute)
        {
            var action = _action;
            //On a exécuté l’action on peut arrêter le timer
            _timer.Stop();
            if (action != null)
            {
                action();
                _action = null;
            }
        }
    }
    /// <summary>
    /// Execute action after a delay
    /// </summary>
    /// <param name="action">The action to execute.</param>
    public void ExecuteActionAfterDelay(Action action)
    {
        _action = action;
        _dateToExecute = DateTime.Now.AddSeconds(_delaySeconds);
        EnableTimer();
    }
}

Happy coding Original illustration unavailable: Laughing