[ACCEPTED]-Is there a way to delay an event handler (say for 1 sec) in Windows Forms-events
Perhaps you could make a method that creates 1 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;
}
Before coming to your question, just having 9 read the summary bit from the main questions 8 page, a timer was exactly what I was going 7 to suggest.
This looks pretty clean to me. It 6 means you can easily "cancel" the delayed 5 event if you need to, by disabling the timer 4 again, for example. It also does everything 3 within the UI thread (but without reentrancy), which 2 makes life a bit simpler than other alternatives 1 might be.
If you're only doing this for one control, the 7 timer approach will work fine. A more robust 6 approach supporting multiple controls and 5 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 4 a Queue<Event>
in your form and have UI events that 3 need to be delayed add them to the queue, e.g.:
void onButtonClick( ..)
{
EventQueue.Enqueue(new Event(MethodToCall));
}
Make 2 your timer tick 10 times a second or so, and 1 have its Tick event handler look like this:
void onTimerTick()
{
if (EventQueue.Any() && EventQueue.First().StartTime >= DateTime.Now)
{
Event e = EventQueue.Dequeue();
e.Method;
}
}
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;
}
}
0
For those limited to .NET 2.0, here is another 1 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();
}
Using Reactive Extensions:
First, install 1 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)
);
}
If you're looking for a more fancy solution, you 6 may want to take a look at my Reactive LINQ project. The 5 link doesn't show how to solve the particular 4 problem you're having, but it should be 3 possible to solve in quite an elegant style 2 using the technique described there (in 1 the whole 4-article series).
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.