有没有办法在Windows窗体中延迟事件处理程序(比如1秒)

时间:2009-03-15 22:30:12

标签: c# .net winforms events

我需要能够延迟某些控件(如按钮)的事件处理程序,例如在实际事件发生1秒后(例如单击事件)..这可能是.net框架吗?

我使用计时器并从计时器的tick事件中调用我的代码,如下所示,但我不确定这是否是最好的方法!

void onButtonClick( ..)
{
   timer1.Enabled = true;
}

void onTimerTick( ..)
{
   timer.Enabled = false; 

   CallMyCodeNow();
}

8 个答案:

答案 0 :(得分:15)

也许你可以创建一个创建计时器的方法?

void onButtonClick(object sender, EventArgs e)
{
    Delay(1000, (o,a) => MessageBox.Show("Test"));
}

static void Delay(int ms, EventHandler action)
{
    var tmp = new Timer {Interval = ms};
    tmp.Tick += new EventHandler((o, e) => tmp.Enabled = false);
    tmp.Tick += action;
    tmp.Enabled = true;
}

答案 1 :(得分:5)

在回答你的问题之前,只要阅读了主要问题页面中的摘要位,计时器正是我要建议的。

这看起来很干净。这意味着,如果需要,您可以通过再次禁用计时器轻松“取消”延迟事件。它还可以在UI线程中完成所有操作(但不需要重入),这使得生活比其他替代方案更简单。

答案 2 :(得分:5)

如果您只为一个控件执行此操作,则计时器方法可以正常工作。支持多种控件和事件类型的更强大的方法如下所示:

class Event
{
   public DateTime StartTime { get; set; }
   public Action Method { get; set; }

   public Event(Action method)
   {
      Method = method;
      StartTime = DateTime.Now + TimeSpan.FromSeconds(1);
   }
}

在表单中维护Queue<Event>,并将需要延迟的UI事件添加到队列中,例如:

void onButtonClick( ..)
{
   EventQueue.Enqueue(new Event(MethodToCall));
}

让你的计时器每秒钟滴答10次左右,并使其Tick事件处理程序如下所示:

void onTimerTick()
{
   if (EventQueue.Any() && EventQueue.First().StartTime >= DateTime.Now)
   {
      Event e = EventQueue.Dequeue();
      e.Method;
   }
}

答案 3 :(得分:4)

我的解决方案使用System.Threading.Timer:

public static class ExecuteWithDelay
{
    class TimerState
    {
        public Timer Timer;
    }

    public static Timer Do(Action action, int dueTime)
    {
        var state = new TimerState();
        state.Timer = new Timer(o =>
        {
            action();
            lock (o) // The locking should prevent the timer callback from trying to free the timer prior to the Timer field having been set.
            {
                ((TimerState)o).Timer.Dispose();
            }
        }, state, dueTime, -1);
        return state.Timer;
    }
}

答案 4 :(得分:3)

对于那些仅限于.NET 2.0的人来说,这是对Bengt有用的解决方案的另一种看法:

/// <summary>
/// Executes the specified method in a delayed context by utilizing
/// a temporary timer.
/// </summary>
/// <param name="millisecondsToDelay">The milliseconds to delay.</param>
/// <param name="methodToExecute">The method to execute.</param>
public static void DelayedExecute(int millisecondsToDelay, MethodInvoker methodToExecute)
{
    Timer timer = new Timer();
    timer.Interval = millisecondsToDelay;
    timer.Tick += delegate
                      {
                          // This will be executed on a single (UI) thread, so lock is not necessary
                          // but multiple ticks may have been queued, so check for enabled.
                          if (timer.Enabled)
                          {
                              timer.Stop();

                              methodToExecute.Invoke();

                              timer.Dispose();
                          }
                      };

    timer.Start();
}

答案 5 :(得分:1)

使用Reactive Extensions:

首先,安装nuget包

PM> Install-Package Rx-Main

代码:

    private void CallMyCodeNow()
    {
        label1.Text = "reactivated!";
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        var o = Observable.FromEventPattern<EventHandler, EventArgs>(
            handler => button1.Click += handler
            , handler => button1.Click -= handler
            )
            .Delay(TimeSpan.FromSeconds(5))
            .ObserveOn(SynchronizationContext.Current)  // ensure event fires on UI thread
            .Subscribe(
                ev => CallMyCodeNow()
                , ex => MessageBox.Show(ex.Message)
            );
    }

答案 6 :(得分:0)

如果您正在寻找更实用的解决方案,您可能需要查看我的Reactive LINQ project。该链接没有显示如何解决您遇到的特定问题,但应该可以使用其中描述的技术(在整个4篇文章系列中)以相当优雅的方式解决。

答案 7 :(得分:-3)

您可以使用:

Thread.Sleep(1000);

这将暂停当前线程一秒钟。所以我会这样做......

最诚挚的问候!