延迟执行代码

时间:2016-04-04 06:28:40

标签: c# .net winforms linq events

我正在注册UserControl的事件,每次移动滚动条时都会抛出此事件(这意味着我们将收到很多事件)。不幸的是,当用户完成使用滚动条(== MouseUp)时,我们没有事件通知。

我们决定实施一种机制,只有在300毫秒后我们才从滚动条接收到任何新通知时才更新我们的模型。

我可以看到如何使用Timer执行此操作并在每次ScrollBar事件发生时重置计时器。

我想知道是否有办法用Linq和Delay做到这一点?

private Action _actionOnMoved;

private void OnScrollBarMoved(object sender, EventArgs args){

}

修改

我已经阅读了可能重复的答案,但节流与我所要求的不同。就我而言,即使我的活动时间少于指定时间,我也不想做任何事情(甚至不是第一次),因为应用此更改需要3-5秒才能完成检索。

所以有所不同:

  • 在给定的链接中,无论什么
  • ,都会执行第一个调用
  • 在我的情况下,如果在延迟时间内拨打电话,则应在延迟后执行电话

例如,如果每100毫秒触发一次此事件,并且延迟时间为300毫秒,我希望永远不会调用我的方法。

3 个答案:

答案 0 :(得分:1)

您可以将事件处理程序包装到以下

object _lock = new object();

SomeEvent += (s, e) =>
{
    lock(_lock)
    {
        Monitor.PulseAll(_lock); // pulse any (if any) awaiting events
        if(!Monitor.Wait(_lock, 5000)) // delay
        {
            ... // call event handler
                // we are here if timeout is expired
        }
    }
}

未经测试,但这是一个想法:当收到事件时,您开始等待脉冲或超时。如果脉冲来了(意味着接收到另一个事件),那么你只需退出。如果发生超时(表示没有其他事件发生),则调用事件处理程序。

注意:它不是异步的,事件调用者(调用或SomeEvent)将在延迟期间被阻止。您可能需要将lock打包到Task.Run

SomeEvent += (s, e) => Task.Run(() =>
{
    ... // the rest of code
}

但是这会在某个其他线程中引发事件处理程序,所以你可能需要调度(调用)到你需要的线程中。

答案 1 :(得分:0)

使用while循环和ThreadPool来监控事件。

class MyForm : Form {
    private volatile bool mouseWheelHandling = false;
    private UserControl userControl;

    public void Form_Load(){
        // userControl.Scroll 
        userControl.MouseWheel += (s, a) => {
            if(!mouseWheelHandling) { // capture MouseWheel and Scroll events, only handle 1 times.
                mouseWheelHandling = true;
                ThreadPool.QueueUserWorkItem(_=>{
                    var horizontalScroll = userControl.HorizontalScroll.Value;
                    while(true) {
                        Thread.Sleep(100);
                        if(horizontalScroll == userControl.HorizontalScroll.Value) {
                            // Control.Invoke to handle cross-thread action
                            // do action
                            mouseWheelHandling = false; // reset the flag
                            break;
                        }
                        horizontalScroll = userControl.HorizontalScroll.Value;
                    }
                });
            }
        }
    }
}

答案 2 :(得分:0)

我的确使用Sinatr的修改版本答案结束了:

public static EventHandler CreateDelayedEventHandler(EventHandler<EventArgs> handler, TimeSpan delay)
{
    object lockObject = new object();

    return (s, e) =>
    {
        Task.Run(() =>
        {
            lock (lockObject)
            {
                Monitor.PulseAll(lockObject);
                if (!Monitor.Wait(lockObject, delay))
                {
                    handler(s, e);
                }
            }
        });
    };
}

我现在唯一的疑问是创造了多少任务才可能无所作为。