IVSoftware.Portable.WatchdogTimer 1.2.1

The ID prefix of this package has been reserved for one of the owners of this package by NuGet.org. Prefix Reserved
dotnet add package IVSoftware.Portable.WatchdogTimer --version 1.2.1
NuGet\Install-Package IVSoftware.Portable.WatchdogTimer -Version 1.2.1
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="IVSoftware.Portable.WatchdogTimer" Version="1.2.1" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add IVSoftware.Portable.WatchdogTimer --version 1.2.1
#r "nuget: IVSoftware.Portable.WatchdogTimer, 1.2.1"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install IVSoftware.Portable.WatchdogTimer as a Cake Addin
#addin nuget:?package=IVSoftware.Portable.WatchdogTimer&version=1.2.1

// Install IVSoftware.Portable.WatchdogTimer as a Cake Tool
#tool nuget:?package=IVSoftware.Portable.WatchdogTimer&version=1.2.1

Watchdog timer

What is it?

A timer that completes one time, after the TimeSpan in the Interval property has elapsed since the most recent call to the StartOrRestart method, regardless of the number of restarts. Invoking the Cancel method negates any enqueued action or event in the queue.

Examples

Display an alert after user moves the mouse

Suppose we're interested in mouse move events, but obviously don't want to make a message each time one occurs.

Winforms App Image

public partial class MainForm : Form
{
    public MainForm() => InitializeComponent();

    WatchdogTimer _wdtMouseMove = new WatchdogTimer
    {
        Interval = TimeSpan.FromSeconds(0.5)
    };

    DateTime _mouseStartTimeStamp = DateTime.MinValue;
    protected override void OnMouseMove(MouseEventArgs e)
    {
        if(!_wdtMouseMove.Running)
        {
            _mouseStartTimeStamp = DateTime.Now;
        }
        _wdtMouseMove.StartOrRestart(() =>
        {
            BeginInvoke(() =>
                MessageBox.Show(
                    $"Mouse down @ {
                        _mouseStartTimeStamp.ToString(@"hh\:mm\:ss tt")
                    }\nTime now is {
                        DateTime.Now.ToString(@"hh\:mm\:ss tt")
                    }."));
        });
        base.OnMouseMove(e);
    }
}

Debouncing

An impatient user might tap multiple times. A watchdog timer can ensure that an action takes place the first time, and requires a cooling off interval before the same action can happen again.

Maui .Net Default App Image with Modifications

public partial class MainPage : ContentPage
{
    int count = 0;

    public MainPage()
    {
        BindingContext = this;
        InitializeComponent();
    }
    private void OnCounterClicked(object sender, EventArgs e)
    {
        if (checkboxIsLockOutMechanismEnabled.IsChecked)
        {
            ExtendLockout();
        }
        count++;
        if (count == 1)
            CounterBtn.Text = $"Clicked {count} time";
        else
            CounterBtn.Text = $"Clicked {count} times";

        SemanticScreenReader.Announce(CounterBtn.Text);
    }
    WatchdogTimer _wdtOverlay = new WatchdogTimer { Interval = TimeSpan.FromSeconds(2) };

    private void ExtendLockout()
    {
        _wdtOverlay.StartOrRestart(
            initialAction: () => IsLockedOut = true,
            completeAction: () => IsLockedOut = false);
    }

    public bool IsLockedOut
    {
        get => _isLockedOut;
        set
        {
            if (!Equals(_isLockedOut, value))
            {
                _isLockedOut = value;
                OnPropertyChanged();
            }
        }
    }
    bool _isLockedOut = false;

    private void OnOverlayTapped(object sender, TappedEventArgs e)
    {
        ExtendLockout();
    }
}

Methods

/// <summary>
/// Restart the watchdog timer.
/// </summary>
/// <remarks>
/// Core method that can take a parameterized action as well as a custom EventArgs object.
/// </remarks>
public void StartOrRestart(Action action, EventArgs e)
{
    Running = true;
    _wdtCount++;
    var capturedCount = _wdtCount;
    _isCancelled= false;
    Task
        .Delay(Interval)
        .GetAwaiter()
        .OnCompleted(() =>
        {
            // If the 'captured' localCount has not changed after awaiting the Interval, 
            // it indicates that no new 'bones' have been thrown during that interval.        
            if (capturedCount.Equals(_wdtCount) && !_isCancelled)
            {
                action?.Invoke();
                Running = false;
                RanToCompletion?.Invoke(this, e ?? EventArgs.Empty);
            }
        });
}

/// <summary>
/// Restart the watchdog timer.
/// </summary>
/// <remarks>
/// Subscribe to the RanToCompletion event to receive notification of completion.  
/// On completion, fire an event with an empty EventArgs object.
/// </remarks>
public void StartOrRestart() => StartOrRestart(null, EventArgs.Empty);

/// <summary>
/// Restart the watchdog timer injecting a custom event to be fired on completion.
/// </summary>
/// <remarks>
/// Subscribe to the RanToCompletion event to receive notification of completion.  
/// On completion, fire an event using a custom parameterized EventArgs object.
/// </remarks>
public void StartOrRestart(EventArgs e) => StartOrRestart(null, e);

/// <summary>
/// Restart the watchdog timer with action to invoke on completion.
/// </summary>
/// <remarks>
/// Subscribe to the RanToCompletion event to receive notification of completion.  
/// On completion, invoke a parameterized action.
/// </remarks>
public void StartOrRestart(Action action) => StartOrRestart(action, EventArgs.Empty);

/// <summary>
/// Restart the watchdog timer with actions to invoke on initialization and completion.
/// </summary>
/// <remarks>
/// Invoke an initial parameterized action if not already running.
/// Subscribe to the RanToCompletion event to receive notification of completion.  
/// On completion, invoke a parameterized action.
/// </remarks>
public void StartOrRestart(Action initialAction, Action completeAction);        

public void Cancel() => _isCancelled = true;    

Properties

public TimeSpan Interval { get; set; } = TimeSpan.FromSeconds(1);

public bool Running { get; private set; }

Event

public event EventHandler RanToCompletion;

StackOverflow

Call a method after some delay when an event is raised, but any subsequent events should "restart" this delay.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETStandard 2.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.2.1 211 11/7/2023