C# event debounce

后端 未结 14 1122
南旧
南旧 2020-11-28 06:22

I\'m listening to a hardware event message, but I need to debounce it to avoid too many queries.

This is an hardware event that sends the machine status and I have t

14条回答
  •  天命终不由人
    2020-11-28 06:37

    I ran into issues with this. I tried each of the answers here, and since I'm in a Xamarin universal app, I seem to be missing certain things that are required in each of these answers, and I didn't want to add any more packages or libraries. My solution works exactly how I'd expect it to, and I haven't run into any issues with it. Hope it helps somebody.

    using System;
    using System.Collections.Generic;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace OrderScanner.Models
    {
        class Debouncer
        {
            private List StepperCancelTokens = new List();
            private int MillisecondsToWait;
            private readonly object _lockThis = new object(); // Use a locking object to prevent the debouncer to trigger again while the func is still running
    
            public Debouncer(int millisecondsToWait = 300)
            {
                this.MillisecondsToWait = millisecondsToWait;
            }
    
            public void Debouce(Action func)
            {
                CancelAllStepperTokens(); // Cancel all api requests;
                var newTokenSrc = new CancellationTokenSource();
                lock (_lockThis)
                {
                    StepperCancelTokens.Add(newTokenSrc);
                }
                Task.Delay(MillisecondsToWait, newTokenSrc.Token).ContinueWith(task => // Create new request
                {
                    if (!newTokenSrc.IsCancellationRequested) // if it hasn't been cancelled
                    {
                        CancelAllStepperTokens(); // Cancel any that remain (there shouldn't be any)
                        StepperCancelTokens = new List(); // set to new list
                        lock (_lockThis)
                        {
                            func(); // run
                        }
                    }
                }, TaskScheduler.FromCurrentSynchronizationContext());
            }
    
            private void CancelAllStepperTokens()
            {
                foreach (var token in StepperCancelTokens)
                {
                    if (!token.IsCancellationRequested)
                    {
                        token.Cancel();
                    }
                }
            }
        }
    }
    

    It's called like so...

    private Debouncer StepperDeboucer = new Debouncer(1000); // one second
    
    StepperDeboucer.Debouce(() => { WhateverMethod(args) });
    

    I wouldn't recommend this for anything where the machine could be sending in hundreds of requests a second, but for user input, it works excellently. I'm using it on a stepper in an android/IOS app that calls to an api on step.

提交回复
热议问题