I am in C# .NET 3.5
What happens when timer elapses and event handler is performed ?
Does the timer cease to exist ?
Can I register several events in different time on one timer, expecting them all to fire one after another ?
You can set a timer to fire off the event only once or continue to do it (Timer.AutoReset property). Yes, you can register several different event handlers on a single timer, but I don't know that there is any way of knowing what order they will fire. If that matters to you, set a single handler, and have that handler call the others. If what you are trying to do is to call a different handler, each time the timer goes off, I would suggest setting a single handler that keeps an enum indicating which function to call and incrementing it each time it gets called by the timer.
To call the same handler to "iterate" through a list of parameters, once on each interval elapsed, I would have an array or list of the parameters and the handler would just increase a counter or consume the list.
using System.Timers;
public class MyTimedDelete {
private static List<int> ListOfIds=null;
private static System.Timers.Timer myTimer=null;
public static void AddIdToQueue(int id)
{
if (ListOfIds == null)
{
ListOfIds = new List<int>();
myTimer = new System.Timers.Timer(2000);
myTimer.Elapsed += OnTimedEvent;
}
ListOfIds.Add(id);
if (ListOfIds.Count==1)
{
myTimer.Start();
}
}
private static void OnTimedEvent(Object source, ElapsedEventArgs e)
{
deleteItem(ListOfIds[0]);
ListOfIds.RemoveAt(0);
if (ListOfIds.Count == 0) {
myTimer.Stop();
}
}
}
Related
Let's say I have this code
public static Timer timer;
static void Main ()
{
timer = new Timer ( 60 * 1000 ); // It ticks every minute
timer.Elpased += One;
timer.Elapsed += Two;
}
private static void One ( sender o, EventArgs e )
{
timer.Stop ();
}
private static void Two ( sender o, EventArgs e )
{
DoSomething ();
}
Since I'm assuming that 'One' and 'Two' will execute in subscribe order, stopping the Timer in 'One' will prevent 'Two' from happening?
If not, how can I do it?
System.Threading.Timer does not have an Elapsed event. It requires a single TimerCallback delegate passed to the constructor, which it executes on a ThreadPool thread.
https://msdn.microsoft.com/en-us/library/system.threading.timer(v=vs.110).aspx
I believe you are looking at System.Timers.Timer, which does have an Elapsed event.
https://msdn.microsoft.com/en-us/library/system.timers.timer(v=vs.110).aspx
I do not believe there is a way to guarantee a way to prevent Two from firing the way you describe. You must assume that One and Two execute at the exact same time on 2 different threads. Even calling Stop() isn't guaranteed to prevent the timer from firing an additional time: https://msdn.microsoft.com/en-us/library/system.timers.timer.stop(v=vs.110).aspx.
My suggestion would be to have a single callback that handles the branching logic on if it should perform the actions in Two after the logic in One executes.
So I am making a Robbery system the timer works perfectly on the first start the sequence by the timer goes down is 10,9,8,7...... But on the 2nd try the sequence is 10,8,6,4...... on the 3rd try its 10,7,4,1..... Etc meaning on each start the timer sequence increase the decrease time? How is it possible? Can you make an edit on the code for me?
public int time;
Timer cd = new Timer(2000);
public void robberyCountdown(User player)
{
time = 10;
cd.Elapsed += (source, e) => OnTimer(player);
cd.Start();
}
public void OnTimer(User player)
{
cd.Stop();
cd.Elapsed -= (source, e) => OnTimer(player);
}
but when i use (cd1.Elapsed += (Object source, ElapsedEventArgs e, User player) on OnTimer it gives me an error on the cd.Elapsed -= (source, e) => OnTimer(source, e, player); Line stating local variable is source cannot be used here as it is defined in this scope
I suspect this is because your elapsed event handler isn't actually being removed, so it is firing multiple times at each tick.
The following question/answer discusses how to remove a delegate, and how Delegate.Equals determines which delegate gets removed (if any): C# removing an event handler
However, you are not removing the same handler, you are creating two separate lambda functions that perform exactly the same task within different contexts. .NET isn't very good at collapsing duplicate code - it cannot resolve that your second lambda is the same as your first because they are each created in a different scope, and therefore each has a different closure (the saved image of all visible variables within the scope where it is created).
If you create an actual non-lambda method, and then use delegates rather than lambdas, this problem should go away. Or, you may be able to assign the lambda to a variable that is accessible to both functions (without modifying it in between).
This is a example implementation of Matt Jordan's solution "assign the lambda to a variable that is accessible to both functions"
public int time;
Timer cd = new Timer(2000);
public void robberyCountdown(User player)
{
time = 10;
ElapsedEventHandler handler = null;
handler = (source, e) => OnTimer(player, handler);
cd.Elapsed += handler;
cd.Start();
}
public void OnTimer(User player, ElapsedEventHandler handler)
{
cd.Stop();
cd.Elapsed -= handler;
}
Because lambadas capture variables, not values, handler can reference itself so long as it is already been initialized to a value (null in this example) before you try to use it.
I was wondering if there is a way to determine which timer just elapsed based on 'duration' or something else, because I create lots of individual timers all with different intervals or durations, by using 'sender' or 'e' without having to create multiple timers or elapsed event handlers.
Code:
public void timePowerup(float duration)
{
Timer timedDelay = new Timer();
timedDelay.Interval = duration;
timedDelay.AutoReset = false;
timedDelay.Elapsed += new ElapsedEventHandler(timedDelayElapsed);
timedDelay.Enabled = true;
}
public void timedDelayElapsed(object sender, ElapsedEventArgs e)
{
}
You can just use sender. It is the timer which triggered the current event. Try
public void timedDelayElapsed(object sender, ElapsedEventArgs e)
{
Timer timer = (Timer)sender;
}
From Events, Delegates, and CLR Event System Conventions:
By convention, event delegates in the .NET Framework have two parameters, the source that raised the event, represented by the sender parameter, and the data for the event, represented by the e parameter.
I have a project here and it has set by default that the actions occur by MouseEnter event. I mean, opening a Window, closing, returning, whatever, happens only by the MouseEnter event.
I was requested to make the event fire only after 3 seconds. That means that the user will place the mouse on the control and only after 3 seconds the event must happen for all the controls in the window.
So, I thought about a global timer or something alike, that will return false untill the timer reaches 3... I think that's the way...
Geez, does anybody knows how can I make such thing?
Thanks!!
You can define a class that will expose a DelayedExecute method that receives an action to execute and creates timers as needed for the delayed execution. It would look something like this:
public static class DelayedExecutionService
{
// We keep a static list of timers because if we only declare the timers
// in the scope of the method, they might be garbage collected prematurely.
private static IList<DispatcherTimer> timers = new List<DispatcherTimer>();
public static void DelayedExecute(Action action, int delay = 3)
{
var dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
// Add the timer to the list to avoid it being garbage collected
// after we exit the scope of the method.
timers.Add(dispatcherTimer);
EventHandler handler = null;
handler = (sender, e) =>
{
// Stop the timer so it won't keep executing every X seconds
// and also avoid keeping the handler in memory.
dispatcherTimer.Tick -= handler;
dispatcherTimer.Stop();
// The timer is no longer used and shouldn't be kept in memory.
timers.Remove(dispatcherTimer);
// Perform the action.
action();
};
dispatcherTimer.Tick += handler;
dispatcherTimer.Interval = TimeSpan.FromSeconds(delay);
dispatcherTimer.Start();
}
}
Then you can call it like this:
DelayedExecutionService.DelayedExecute(() => MessageBox.Show("Hello!"));
or
DelayedExecutionService.DelayedExecute(() =>
{
DoSomething();
DoSomethingElse();
});
I just wanted to add a simpler solution:
public static void DelayedExecute(Action action, int delay = 3000)
{
Task.Factory.StartNew(() =>
{
Thread.Sleep(delay);
action();
}
}
Then use it just like in this other answer
How do I get a timer event to fire one at a time.
For example I have a timer that raises an event every 10 minutes.
The event that is raised takes 10 or more minutes to finish executing.
I would like the timer to reset AFTER the event has finished.
In other words I do not want to raise more than 1 instance of the event at any one time.
Use System.Timers.Timer not the Threading one
Set AutoReset to false.
Then Start it again when you're done.
Usually what I do is have my event stop the timer when it's raised and then restart the timer when the event process completes:
private void timerHandler(object sender, TimerElapsedEventArgs e)
{
Timer timer = (Timer)sender;
timer.Stop();
RunProcess();
timer.Start();
}
public void RunProcess()
{
/* Do stuff that takes longer than my timer interval */
}
Now my timer will start again on completion of the process
It may be difficult to stop timers for efficiency or logic. The following code synchronizes skipping the events.
static readonly object key = new object();
void TimerHandler(object sender, TimerElapsedEventArgs e)
{
if(Monitor.TryEnter(key))
{
try
{
//do your stuff
}
finally
{
Montitor.Exit(key);
}
}
}