Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 仅当上次触发后经过一段时间时,处理事件的最简单方法是什么?_C#_.net_C# 4.0 - Fatal编程技术网

C# 仅当上次触发后经过一段时间时,处理事件的最简单方法是什么?

C# 仅当上次触发后经过一段时间时,处理事件的最简单方法是什么?,c#,.net,c#-4.0,C#,.net,C# 4.0,我有一个事件处理程序: private void Control_Scroll(object sender, ScrollEventArgs e) { UpdateAnnotations(); } 现在,我只希望在用户停止滚动时更新注释,就像上次滚动事件超过100毫秒后,执行操作,否则放弃它,因为这无关紧要 最简单/可重用的方法是什么,最好是一些静态方法,如publicstaticvoiddelayedaction(Action-Action,TimeSpan-del

我有一个事件处理程序:

 private void Control_Scroll(object sender, ScrollEventArgs e)
 {
     UpdateAnnotations();
 }     
现在,我只希望在用户停止滚动时更新注释,就像上次滚动事件超过100毫秒后,执行操作,否则放弃它,因为这无关紧要

最简单/可重用的方法是什么,最好是一些静态方法,如
publicstaticvoiddelayedaction(Action-Action,TimeSpan-delay)


使用.NET 4.0。

是否可以不存储触发事件的时间(DateTime.Now)以及何时调用该事件,请检查自上次事件(例如DateTime.Now-lastExecutionTime>minTime)以来的时间

**更新**

或者基于您的静态助手想法的更通用的方法:

public static void DelayedAction(Action action, TimeSpan delay)
{
    var delayedActionTimer = new Timer(x => action(), null, delay, TimeSpan.FromMilliseconds(-1));
}

显然需要工作。。。例如,您可以将计时器存储在字段中,并在用户每次滚动时重置(更改)延迟,参见Rx(反应性扩展)问题。(您可以使用创建事件的可观察对象。)

我会使用类似的方法

class MyClass
{
   private System.Timers.Timer _ScrollTimer;
   public MyClass()
   {
       _ScrollTimer= new System.Timers.Timer(100);
       _ScrollTimer.Elapsed += new ElapsedEventHandler(ScrollTimerElapsed);
   }

   private void ResetTimer()
   {
        _ScrollTimer.Stop();
        _ScrollTimer.Start();
   }

   private void Control_Scroll(object sender, ScrollEventArgs e, TimeSpan delay)
    {
        ResetTimer();
    }    

    private void ScrollTimerElapsed(object sender, ElapsedEventArgs e)
    {
        _ScrollTimer.Stop();
        UpdateAnnotations();           
    }
}

每次用户滚动时,计时器都会被重置,只有当滚动停止100毫秒时,才会触发TimeRecursed,您可以更新批注。

我在表单上同时尝试了几个控件,外部可以重用它

private void vScrollBar1_Scroll(object sender, ScrollEventArgs e)
{
    if (DelayedAction(100, sender))
        UpdateAnnotations();
}

Dictionary<object, Timer> timers = new Dictionary<object, Timer>();
bool DelayedAction(int delay, object o)
{
    if (timers.ContainsKey(o))
        return false;

    var timer = new Timer();
    timer.Interval = delay;
    timer.Tick += (s, e) =>
        {
            timer.Stop();
            timer.Dispose();
            lock(timers)
                timers.Remove(o);
        };

    lock(timers)
        timers.Add(o, timer);

    timer.Start();
    return true;
}
private void vScrollBar1\u滚动(对象发送方,ScrollEventArgs e)
{
if(延迟动作(100,发送方))
UpdateAnnotations();
}
字典计时器=新字典();
布尔延迟动作(整数延迟,对象o)
{
if(计时器容器(o))
返回false;
var timer=new timer();
时间间隔=延迟;
计时器.勾号+=(s,e)=>
{
timer.Stop();
timer.Dispose();
锁(计时器)
定时器。移除(o);
};
锁(计时器)
定时器。添加(o,定时器);
timer.Start();
返回true;
}
词典被锁定,因为如果用户不能同时点击两个控件,则可能会在删除另一个控件的同时插入计时器。

尝试以下类:

public class ActionHelper
{
    private static Dictionary<Delegate, System.Threading.Timer> timers =
        new Dictionary<Delegate, System.Threading.Timer>();

    private static object lockObject = new object();

    public static void DelayAction(Action action, TimeSpan delay)
    {
        lock (lockObject)
        {
            System.Threading.Timer timer;
            if (!timers.TryGetValue(action, out timer))
            {
                timer = new System.Threading.Timer(EventTimerCallback, action,
                    System.Threading.Timeout.Infinite,
                    System.Threading.Timeout.Infinite);
                timers.Add(action, timer);
            }
            timer.Change(delay, TimeSpan.FromMilliseconds(-1));
        }
    }

    public static void EventTimerCallback(object state)
    {
        var action = (Action)state;
        lock (lockObject)
        {
            var timer = timers[action];
            timers.Remove(action);
            timer.Dispose();
        }
        action();
    }
}
请注意,该方法是在单独的线程中调用的。如果需要进行UI工作,则需要使用(WinForms)或(WPF):


Rx是处理这种情况的最优雅的方法。虽然我选择了Rx方法,但您的方法非常好,并标记为答案,因为对于某些人来说Rx可能是不可接受的解决方案。
private void Control_Scroll(object sender, ScrollEventArgs e)
{
    ActionHelper.DelayAction(UpdateAnnotations, TimeSpan.FromSeconds(1));
}
// The method is contained in a Form (winforms)
private void UpdateAnnotations()
{
    if (this.InvokeRequired)
        this.Invoke(new Action(UpdateAnnotations));
    else
    {
        MessageBox.Show("Method is called");
    }
}