From 95bba73d84a29e5762e6f7ff433eaba4e30112fb Mon Sep 17 00:00:00 2001 From: michael-hawker Date: Fri, 13 Sep 2019 14:09:38 -0700 Subject: [PATCH 1/2] Add a Debounce Extension to DispatcherTimer for rate-limiting UI events (like triggering on typing) For use in Graph Controls later --- .../Extensions/DispatcherTimerExtensions.cs | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 Microsoft.Toolkit.Uwp.UI/Extensions/DispatcherTimerExtensions.cs diff --git a/Microsoft.Toolkit.Uwp.UI/Extensions/DispatcherTimerExtensions.cs b/Microsoft.Toolkit.Uwp.UI/Extensions/DispatcherTimerExtensions.cs new file mode 100644 index 00000000000..5b4075095de --- /dev/null +++ b/Microsoft.Toolkit.Uwp.UI/Extensions/DispatcherTimerExtensions.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Concurrent; +using Windows.UI.Xaml; + +namespace Microsoft.Toolkit.Uwp.UI.Extensions +{ + /// + /// Set of extention methods for using . + /// + public static class DispatcherTimerExtensions + { + private static ConcurrentDictionary _debounceInstances = new ConcurrentDictionary(); + + /// + /// Used to debounce (rate-limit) an event. The action will be postponed and executed after the interval has elapsed. At the end of the interval, the function will be called with the arguments that were passed most recently to the debounced function. + /// Use this method to control the timer instead of calling Start/Interval/Stop manually. + /// A scheduled debounce can still be stopped by calling the stop method on the timer instance. + /// Each timer can only have one debounced function limited at a time. + /// + /// Timer instance, only one debounced function can be used per timer. + /// Action to execute at the end of the interval. + /// Interval to wait before executing the action. + /// Determines if the action execute on the leading edge instead of trailing edge. + /// + /// + /// private DispatcherTimer _typeTimer = new DispatcherTimer(); + /// + /// _typeTimer.Debounce(async () => + /// { + /// // Only executes this code after 0.3 seconds have elapsed since last trigger. + /// }, TimeSpan.FromSeconds(0.3)); + /// + /// + public static void Debounce(this DispatcherTimer timer, Action action, TimeSpan interval, bool immediate = false) + { + // Check and stop any existing timer + var timeout = timer.IsEnabled; + if (timeout) + { + timer.Stop(); + } + + // Reset timer parameters + timer.Tick -= Timer_Tick; + timer.Interval = interval; + + if (immediate) + { + // If we're in immediate mode then we only execute if the timer wasn't running beforehand + if (!timeout) + { + action.Invoke(); + } + } + else + { + // If we're not in immediate mode, then we'll execute when the current timer expires. + timer.Tick += Timer_Tick; + + // Store/Update function + _debounceInstances.AddOrUpdate(timer, action, (k, v) => v); + } + + // Start the timer to keep track of the last call here. + timer.Start(); + } + + private static void Timer_Tick(object sender, object e) + { + // This event is only registered/run if we weren't in immediate mode above + if (sender is DispatcherTimer timer) + { + timer.Tick -= Timer_Tick; + timer.Stop(); + + if (_debounceInstances.TryRemove(timer, out Action action)) + { + action?.Invoke(); + } + } + } + } +} From 4853d53684199bae3ccb87f4234b6916d8609af0 Mon Sep 17 00:00:00 2001 From: michael-hawker Date: Fri, 13 Sep 2019 14:11:41 -0700 Subject: [PATCH 2/2] Add License Header --- .../Extensions/DispatcherTimerExtensions.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Microsoft.Toolkit.Uwp.UI/Extensions/DispatcherTimerExtensions.cs b/Microsoft.Toolkit.Uwp.UI/Extensions/DispatcherTimerExtensions.cs index 5b4075095de..d1ecfed07ed 100644 --- a/Microsoft.Toolkit.Uwp.UI/Extensions/DispatcherTimerExtensions.cs +++ b/Microsoft.Toolkit.Uwp.UI/Extensions/DispatcherTimerExtensions.cs @@ -1,4 +1,8 @@ -using System; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; using System.Collections.Concurrent; using Windows.UI.Xaml;