using System;
using System.Threading;
using System.Threading.Tasks;
namespace Wino.Mail.ViewModels.Helpers;
///
/// A throttled event handler that delays execution of a callback until a specified time has passed
/// without the event being triggered again. This is useful for scenarios where events fire rapidly
/// but you only want to handle the "final" event after a quiet period.
///
public class ThrottledEventHandler : IDisposable
{
private readonly int _delayMilliseconds;
private readonly Func _asyncCallback;
private readonly Action _syncCallback;
private Timer _timer;
private volatile bool _disposed;
///
/// Creates a new throttled event handler with a synchronous callback.
///
/// The delay in milliseconds to wait before executing the callback
/// The action to execute after the delay period
public ThrottledEventHandler(int delayMilliseconds, Action callback)
{
_delayMilliseconds = delayMilliseconds;
_syncCallback = callback ?? throw new ArgumentNullException(nameof(callback));
}
///
/// Creates a new throttled event handler with an asynchronous callback.
///
/// The delay in milliseconds to wait before executing the callback
/// The async function to execute after the delay period
public ThrottledEventHandler(int delayMilliseconds, Func callback)
{
_delayMilliseconds = delayMilliseconds;
_asyncCallback = callback ?? throw new ArgumentNullException(nameof(callback));
}
///
/// Triggers the throttled execution. If called again before the delay period expires,
/// the timer is reset and the callback execution is delayed further.
///
public void Trigger()
{
if (_disposed) return;
// Dispose existing timer if it exists
_timer?.Dispose();
// Create new timer that will execute the callback after the delay
_timer = new Timer(ExecuteCallback, null, _delayMilliseconds, Timeout.Infinite);
}
private async void ExecuteCallback(object state)
{
if (_disposed) return;
try
{
if (_asyncCallback != null)
{
await _asyncCallback();
}
else
{
_syncCallback?.Invoke();
}
}
catch (Exception ex)
{
// Log error if logging is available, but don't crash
System.Diagnostics.Debug.WriteLine($"ThrottledEventHandler callback error: {ex}");
}
finally
{
// Dispose the timer since it's one-shot
_timer?.Dispose();
_timer = null;
}
}
public void Dispose()
{
if (_disposed) return;
_disposed = true;
_timer?.Dispose();
_timer = null;
}
}