IVSoftware.Portable.WatchdogTimer
1.3.0-prerelease
Prefix Reserved
dotnet add package IVSoftware.Portable.WatchdogTimer --version 1.3.0-prerelease
NuGet\Install-Package IVSoftware.Portable.WatchdogTimer -Version 1.3.0-prerelease
<PackageReference Include="IVSoftware.Portable.WatchdogTimer" Version="1.3.0-prerelease" />
paket add IVSoftware.Portable.WatchdogTimer --version 1.3.0-prerelease
#r "nuget: IVSoftware.Portable.WatchdogTimer, 1.3.0-prerelease"
// Install IVSoftware.Portable.WatchdogTimer as a Cake Addin #addin nuget:?package=IVSoftware.Portable.WatchdogTimer&version=1.3.0-prerelease&prerelease // Install IVSoftware.Portable.WatchdogTimer as a Cake Tool #tool nuget:?package=IVSoftware.Portable.WatchdogTimer&version=1.3.0-prerelease&prerelease
Watchdog timer
What It Is
A timer that triggers once after the TimeSpan
set in the Interval
property has elapsed since the most recent call to the StartOrRestart
method, regardless of how many restarts occur. Invoking the Cancel
method prevents any pending actions or events.
Examples
Display an alert after user moves the mouse
Suppose we want to handle mouse move events but only trigger a single consolidated response when the mouse has stopped moving for a short period. Using a WatchdogTimer, we can ensure that an alert is displayed only after the user has stopped moving the mouse for a defined interval.
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);
}
}
Explanation:
The OnMouseMove method resets the timer each time the mouse moves, and starts the timer on the first move. If the mouse stops moving for 0.5 seconds (as defined by Interval), the StartOrRestart method executes, displaying a message with the timestamps of the event.
Debouncing
For impatient users who tap multiple times, a WatchdogTimer can ensure the action occurs only once, requiring a cooldown period before allowing the same action again.
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();
}
}
Constructor
/// <summary>
/// Initializes a new instance of the <see cref="WatchdogTimer"/> class with optional default actions for the initial and completion phases.
/// </summary>
/// <param name="defaultInitialAction">An optional default action to be executed when the timer starts, if no other initial action is provided in the call to the `StartOrRestart` method.</param>
/// <param name="defaultCompleteAction">An optional default action to be executed upon successful completion of the timer, if no other completion action is provided in the call to the `StartOrRestart` method.</param>
/// <remarks>
/// The preferred usage is to choose one of the following approaches:
/// - Always use default actions, or
/// - Always use actions passed in as arguments to the method.
/// However, in situations where both defaults and method arguments are provided, an orderly scheme is in place for resolving conflicts: actions passed as arguments to the method will always take precedence over default actions, even if defaults are set.
/// This ensures the timer behaves predictably and consistently in scenarios where both default and explicit actions are provided.
/// </remarks>
public WatchdogTimer(Action defaultInitialAction = null, Action defaultCompleteAction = null);
Methods
/// <summary>
/// Restarts the watchdog timer using default completion actions.
/// </summary>
/// <remarks>
/// Clients may subscribe to the <see cref="RanToCompletion"/> event to receive notifications upon completion.
/// On completion, an event is fired with an empty <see cref="EventArgs"/> object.
/// This overload does not specify an initial action, but if <see cref="DefaultInitialAction"/> is set, it will be executed.
/// This overload does not specify a completion action, but if <see cref="DefaultCompleteAction"/> is set, it will be executed.
/// </remarks>
public void StartOrRestart();
/// <summary>
/// Restarts the watchdog timer using default completion actions and specified event arguments.
/// </summary>
/// <remarks>
/// Clients may subscribe to the <see cref="RanToCompletion"/> event to receive notifications upon completion.
/// On completion, an event is fired with the provided <see cref="EventArgs"/> object.
/// This overload does not specify an initial action, but if <see cref="DefaultInitialAction"/> is set, it will be executed.
/// This overload does not specify a completion action, but if <see cref="DefaultCompleteAction"/> is set, it will be executed.
/// </remarks>
/// <param name="e">An optional <see cref="EventArgs"/> object to pass to the completion event.
/// If null, an empty <see cref="EventArgs"/> will be used.</param>
public void StartOrRestart(EventArgs e);
/// <summary>
/// Restarts the watchdog timer using a specified completion action.
/// </summary>
/// <remarks>
/// Clients may subscribe to the <see cref="RanToCompletion"/> event to receive notifications upon completion.
/// On completion, an event is fired with an empty <see cref="EventArgs"/> object.
/// This overload does not specify an initial action, but if <see cref="DefaultInitialAction"/> is set, it will be executed.
/// The provided completion action will be executed upon successful completion of the timer, overriding the <see cref="DefaultCompleteAction"/>.
/// </remarks>
/// <param name="action">The action to execute upon successful completion of the timer.
/// This parameter cannot be null and will override the <see cref="DefaultCompleteAction"/> if it is set.</param>
/// <exception cref="ArgumentNullException">Thrown when the <paramref name="action"/> parameter is null.</exception>
public void StartOrRestart(Action action);
/// <summary>
/// Restarts the watchdog timer using a specified completion action and event arguments.
/// </summary>
/// <remarks>
/// Clients may subscribe to the <see cref="RanToCompletion"/> event to receive notifications upon completion.
/// On completion, an event is fired with the provided <see cref="EventArgs"/> object.
/// This overload does not specify an initial action, but if <see cref="DefaultInitialAction"/> is set, it will be executed.
/// The provided completion action will be executed upon successful completion of the timer, overriding the <see cref="DefaultCompleteAction"/>.
/// </remarks>
/// <param name="action">The action to execute upon successful completion of the timer.
/// This parameter cannot be null and will override the <see cref="DefaultCompleteAction"/> if it is set.</param>
/// <param name="e">An optional <see cref="EventArgs"/> object to pass to the completion event.
/// If null, an empty <see cref="EventArgs"/> will be used.</param>
/// <exception cref="ArgumentNullException">Thrown when the <paramref name="action"/> parameter is null.</exception>
public void StartOrRestart(Action action, EventArgs e);
/// <summary>
/// Restarts the watchdog timer using specified initial and completion actions.
/// </summary>
/// <remarks>
/// Clients may subscribe to the <see cref="RanToCompletion"/> event to receive notifications upon completion.
/// On completion, an event is fired with an empty <see cref="EventArgs"/> object.
/// This overload allows clients to specify both an initial action and a completion action,
/// and both actions will override <see cref="DefaultInitialAction"/> and <see cref="DefaultCompleteAction"/> if they are set.
/// </remarks>
/// <param name="initialAction">The action to execute when starting the timer.
/// This parameter cannot be null and will override the <see cref="DefaultInitialAction"/> if it is set.</param>
/// <param name="completeAction">The action to execute upon successful completion of the timer.
/// This parameter cannot be null and will override the <see cref="DefaultCompleteAction"/> if it is set.</param>
/// <exception cref="ArgumentNullException">Thrown when either <paramref name="initialAction"/> or <paramref name="completeAction"/> is null.</exception>
public void StartOrRestart(Action initialAction, Action completeAction);
/// <summary>
/// Cancels the current timer, preventing any pending completion actions and events.
/// </summary>
/// <remarks>
/// Calling this method stops the timer and prevents any pending completion actions from running.
/// You can subscribe to the <see cref="Cancelled"/> event to be notified when the timer is cancelled.
/// </remarks>
public void Cancel();
Properties
/// <summary>
/// Gets or sets the time interval for the watchdog timer. This interval defines the delay period before the completion action is triggered.
/// </summary>
/// <value>The interval duration for the timer. Defaults to 1 second if not explicitly set.</value>
public TimeSpan Interval { get; set; }
/// <summary>
/// Gets a value indicating whether the timer is currently running. This property is bindable.
/// </summary>
/// <value><c>true</c> if the timer is running; otherwise, <c>false</c>.</value>
/// <remarks>
/// The running state is managed internally by the <see cref="WatchdogTimer"/> class and cannot be set externally.
/// This property supports data binding and triggers the <see cref="PropertyChanged"/> event when the running state changes.
/// </remarks>
public bool Running { get; }
/// <summary>
/// Gets the default action to be executed when the timer starts, if no other initial action is provided.
/// This property is read-only and can only be set through the constructor.
/// </summary>
/// <value>The default initial action.</value>
public Action DefaultInitialAction { get; }
/// <summary>
/// Gets the default action to be executed upon successful completion of the timer, if no other completion action is provided.
/// This property is read-only and can only be set through the constructor.
/// </summary>
/// <value>The default completion action.</value>
public Action DefaultCompleteAction { get; }
Events
/// <summary>
/// Raised when the timer successfully completes its countdown and the completion action is invoked.
/// </summary>
public event EventHandler RanToCompletion;
/// <summary>
/// Raised when the timer is cancelled before completing its countdown.
/// </summary>
public event EventHandler Cancelled;
/// <summary>
/// Raised when a property value changes, supporting data binding for the <see cref="Running"/> property.
/// </summary>
/// <remarks>
/// This event is triggered whenever the <see cref="Running"/> property changes.
/// It is part of the <see cref="INotifyPropertyChanged"/> interface to support data binding in UI frameworks.
/// </remarks>
public event PropertyChangedEventHandler PropertyChanged;
Main Features and Enhancements:
- Support for Default Actions at Instantiation:
- You can now set default actions for
InitialAction
andCompletedAction
at the time of instantiation. These defaults will be automatically used in theStartOrRestart
method when no specific actions are provided. - This enhances the flexibility of the timer, allowing reusable behavior without requiring actions to be passed in every time.
- Consider using a singleton pattern to initialize using non-static properties of the instance.
- You can now set default actions for
/// <summary>
/// Instantiate using singleton pattern.
/// </summary>
public WatchdogTimer WatchdogTimer
{
get
{
if (_watchdogTimer is null)
{
_watchdogTimer = new WatchdogTimer(
defaultInitialAction: () =>
{
Console.WriteLine("Timer Started");
},
defaultCompleteAction: () =>
{
Console.WriteLine("Timer Completed");
}
);
}
return _watchdogTimer;
}
}
WatchdogTimer _watchdogTimer = default;
StackOverflow
Product | Versions 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. |
-
.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.3.0-prerelease | 93 | 10/20/2024 |
1.2.1 | 292 | 11/7/2023 |
Main Features and Enhancements:
- Support for Default Actions at Instantiation: You can now set default actions for InitialAction and CompletedAction at the time of instantiation. These defaults will be automatically used in the StartOrRestart method when no specific actions are provided.
- Minor Fixes: Improved Property Change Notification.