Tutorial :Is there a way to delay an event handler (say for 1 sec) in Windows Forms



Question:

I need to be able to delay the event handlers for some controls (like a button) to be fired for example after 1 sec of the actual event (click event for example) .. is this possible by the .net framework ?

I use a timer and call my code from the timer's tick event as below but I am not sure if this is the best approach !

void onButtonClick( ..)  {     timer1.Enabled = true;  }    void onTimerTick( ..)  {     timer.Enabled = false;        CallMyCodeNow();  }  


Solution:1

Perhaps you could make a method that creates the timer?

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;  }  


Solution:2

Before coming to your question, just having read the summary bit from the main questions page, a timer was exactly what I was going to suggest.

This looks pretty clean to me. It means you can easily "cancel" the delayed event if you need to, by disabling the timer again, for example. It also does everything within the UI thread (but without reentrancy), which makes life a bit simpler than other alternatives might be.


Solution:3

If you're only doing this for one control, the timer approach will work fine. A more robust approach supporting multiple controls and types of events looks something like this:

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

Maintain a Queue<Event> in your form and have UI events that need to be delayed add them to the queue, e.g.:

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

Make your timer tick 10 times a second or so, and have its Tick event handler look like this:

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


Solution:4

My solution uses 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;      }  }  


Solution:5

For those limited to .NET 2.0, here is another take on Bengt's helpful solution:

/// <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();  }  


Solution:6

Using Reactive Extensions:

First, install the nuget package

PM> Install-Package Rx-Main  

Code:

    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)              );      }  


Solution:7

If you're looking for a more fancy solution, you may want to take a look at my Reactive LINQ project. The link doesn't show how to solve the particular problem you're having, but it should be possible to solve in quite an elegant style using the technique described there (in the whole 4-article series).


Solution:8

You can use:

Thread.Sleep(1000);  

That will pause the current Thread for one second. So I would do that...

Best Regards!


Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »