如何在不使用Rx Framework的情况下限制事件的速度

use*_*847 9 c# system.reactive c#-5.0 windows-8 windows-runtime

我想限制事件的速度,如何在不使用Microsoft Rx框架的情况下实现这一目标.我在Rx的帮助下做到了这一点.但我正在尝试的是,我需要根据时间段限制Map的View更改事件.是否可以在不使用Rx的情况下实现相同的功能.

我不允许使用Rx,我必须保持二进制大小尽可能小.

Jam*_*rld 16

如果您的事件是类型的,那么这是有效的EventHandler<EventArgs>.它为受限制的事件处理程序创建一个包装器:

private EventHandler<EventArgs> CreateThrottledEventHandler(
    EventHandler<EventArgs> handler, 
    TimeSpan throttle)
{   
    bool throttling = false;
    return (s,e) =>
    {
        if(throttling) return;              
        handler(s,e);
        throttling = true;
        Task.Delay(throttle).ContinueWith(_ => throttling = false);
    };
}
Run Code Online (Sandbox Code Playgroud)

像这样附上:

this.SomeEvent += CreateThrottledEventHandler(
    (s,e) => Console.WriteLine("I am throttled!"),
    TimeSpan.FromSeconds(5));
Run Code Online (Sandbox Code Playgroud)

虽然,CreateThrottledEventHandler如果您需要-=稍后将其解除,则应该存储从中返回的处理程序.


BTo*_*TKD 15

我相信在'throttled'事件处理程序中,以下要求是必不可少的:

  • 一个事件立即引发.
  • 后续事件 - 在限制期内发生 - 将被忽略.
  • 一旦限制期结束,保证在限制期间发生的最后一个事件将被提升.

考虑到这些要求,以前接受的答案并不令人满意; 它正确地满足了前两个要求,但并不能保证最终会引发最后一个事件.我认为这一点特别重要,因为以高频率提出的事件通常代表"状态变化"和/或"用户请求"; 我们总是希望收到有关状态或用户交互更改的最新更新.

为了满足所有这些要求,我创建了自己的通用"ThrottledEventHandler"类.

public class ThrottledEventHandler<TArgs>
    where TArgs : EventArgs
{
    private readonly EventHandler<TArgs> _innerHandler;
    private readonly EventHandler<TArgs> _outerHandler;
    private readonly Timer _throttleTimer;

    private readonly object _throttleLock = new object();
    private Action _delayedHandler = null;

    public ThrottledEventHandler(EventHandler<TArgs> handler, TimeSpan delay)
    {
        _innerHandler = handler;
        _outerHandler = HandleIncomingEvent;
        _throttleTimer = new Timer(delay.TotalMilliseconds);
        _throttleTimer.Elapsed += Timer_Tick;
    }

    private void HandleIncomingEvent(object sender, TArgs args)
    {
        lock (_throttleLock)
        {
            if (_throttleTimer.Enabled)
            {
                _delayedHandler = () => SendEventToHandler(sender, args);
            }
            else
            {
                SendEventToHandler(sender, args);
            }
        }
    }

    private void SendEventToHandler(object sender, TArgs args)
    {
        if (_innerHandler != null)
        {
            _innerHandler(sender, args);
            _throttleTimer.Start();
        }
    }

    private void Timer_Tick(object sender, EventArgs args)
    {
        lock (_throttleLock)
        {
            _throttleTimer.Stop();
            if (_delayedHandler != null)
            {
                _delayedHandler();
                _delayedHandler = null;
            }
        }
    }

    public static implicit operator EventHandler<TArgs>(ThrottledEventHandler<TArgs> throttledHandler)
    {
        return throttledHandler._outerHandler;
    }
}
Run Code Online (Sandbox Code Playgroud)

用法看起来像这样:

myObject.MyFrequentlyRaisedEvent += new ThrottledEventHandler(MyActualEventHandler, TimeSpan.FromMilliseconds(50));
Run Code Online (Sandbox Code Playgroud)