Fairly new to C# and timers, although I've managed to do some really fun stuff in C#, however I'm not getting the hang of Timers.
Form1.cs:
private int counter;
static System.Windows.Forms.Timer timer1 = new System.Windows.Forms.Timer();
public void goTimer()
{
// Set Counter
counter = 60;
// If timer is already enabled, stop it.
if (timer1.Enabled)
{
timer1.Dispose();
//timer1.Stop() <- also tried
}
timer1.Tick += new EventHandler(timer1_Tick);
timer1.Interval = 1000; // 1 second
timer1.Start(); // Timer exists
txtCountdown.Text = counter.ToString();
}
private void timer1_Tick(object sender, EventArgs e)
{
counter--;
if(counter == 0)
{
timer1.Stop();
}
txtCountdown.Text = counter.ToString();
}
So, what happens is that it seems to work as intended, until you start calling goTimer(); from e.g. a button press, then it will speed up the (int) counter as many times as you pressed it... And after a while the memory will be eaten up.
In this case the users will be able to do call the timer function, as it will remove some objects, clear some data and refresh the session, but also when the timer reaches 0.
Using Winforms, I did not add a timer in visual studio (it's only referenced here in Form1.cs).
How do I terminate all timers, and then restart at (int) counter?
Using start and stop of the timer would be the proper aproach, but generally also the dispose variant will work.
Your memory hole results from the multiplied event handler assignments, you need to move this method to your constructor or some other initialization method:
timer1.Tick += new EventHandler(timer1_Tick);
If you really want to create a new timer every time, you need to release the event handler before:
timer1.Tick -= timer1_Tick;
First of all, as MichaelSander already mentioned, you should put these lines in your Form1.cs constructor:
timer1.Tick += new EventHandler(timer1_Tick);
timer1.Interval = 1000; // 1 second
Secondly, there is no point in disposing your timer if it's meant to be used more than once. Instead of timer1.Dispose() you should use timer1.Stop() just like you do in your timer1_Tick handler. Also there is no point in checking whether the timer is enabled or disabled as both timer1.Start() and timer1.Stop() will either turn it on/off respectively or do nothing at all. That means that in your case you can remove this block completely:
if (timer1.Enabled)
{
timer1.Dispose();
}
Related
I am teaching myself C# and, as part of this, am trying to develop an iOS countdown timer app that is to play a .wav sound file X seconds after a timer initiating button has been clicked as the timer value has gone from X to 0.
In an attempt to do this I have tried using the System.Timers namespace but have been unable to figure out how to program the countdown timer described above. Below is my incomplete code (code that obviously does not fulfill the above described function but might be a part of the full code that would fulfill that function):
partial void UIButton1416_TouchUpInside(UIButton sender)
{
url = NSUrl.FromFilename("Sounds/bell.wav");
bell = new SystemSound(url);
int RoundedTimerValue = Convert.ToInt32(Math.Round(TimerSlider.Value, 0));
System.Timers.Timer timer = new System.Timers.Timer();
timer.Interval = 60000;
timer.Enabled = true;
}
Does anyone know how to create the described countdown timer / Trigger an event X seconds after a button has been clicked?
Example Code.
Timer timer = new Timer();
timer.Interval = 60000;
timer.Elapsed += new ElapsedEventHandler((x,y) => {
//Do whatever you want
timer.Stop();
});
Put the below code in the Button Click Handler and make the timer variable global.
timer.Start();
Or you can leave everything in the Button's click handler, not a big deal.
Explanation:
The timer class has an event called Elapsed which is called when the specified number of milliseconds in the timer's Interval gets over. with the line
timer.Elapsed += new ElapsedEventHandler((x,y) => {...
we are assigning a Delegate(Virtual function) to be called when the timer is up. therefore any code within the braces{} will be called at every Timer.Interval milliseconds. we stop the timer at that time as we don't want it to keep running and generate a lot of events.
Update 2:
Normally , EventHandlers are Defined using
return_type functionName(object sender, EventArgs e);
But since the delegate is virtual, so is the parameter. x corresponds to sender and y corresponds to e.
that event handler code can also be written as below
void someFunction(object sender, ElapsedEventArgs e)
{
timer.Stop();
}
and then,
timer.Elapsed += new ElapsedEventHandler(someFunction);
As for the '=>' you can read about Lambda Expressions Here
In my application I'm using two Timer, each Timer use a BackgroundWorker. Here the declaration:
DispatcherTimer timer1 = new DispatcherTimer();
DispatcherTimer timer2 = new DispatcherTimer();
BackgroundWorker worker1 = new BackgroundWorker();
BackgroundWorker worker2= new BackgroundWorker();
I using timer1 for perform an heavy method with a BackgroundWorker and timer2 for execute another BackgroundWorker that check the content of a file.
In this way I assign the event to BackgroundWorkers:
worker1.DoWork += worker_DoWork;
worker1.RunWorkerCompleted += worker_RunWorkerCompleted;
worker1.WorkerSupportsCancellation = true;
worker2.DoWork += worker_DoWork2;
worker2.RunWorkerCompleted += worker_RunWorkerCompleted2;
worker2.WorkerSupportsCancellation = true;
Now timer1 have a range of 15 minutes so the BackgroundWorker execute the heavy method each 15 minutes. And timer2 have a range of 1 second. With the timer1 all working good, but the problems are coming when I've added the timer2.
As I said before this timer allow me to start a method that read a file through the worker2, this file have a property, if this property change I need to perform some special activity. Until here no problem.
What I did is the following:
//This method is called by MainWindow
public ReadFile()
{
//before this I already assigned to timer1 the tick event and start
timer2.Tick -= new EventHandler(Event_Tick);
timer2.Tick += new EventHandler(Event_Tick);
timer2.Interval = new TimeSpan(0, 0, 1);
timer2.Start();
}
This is the Tick event associated to timer2
private void Event_Tick(object sender, EventArgs e)
{
if (!worker1.IsBusy) //I skip the reading, worker1 is busy
{
timer1.Stop(); //stop the first timer
worker2.RunWorkerAsync();
}
else
{
Console.WriteLine("worker1 is busy!");
}
}
I don't need to add here the DoWork, is just a parsing of a file, very useless for the question. When worker2 complete the task I did this:
private void worker_RunWorkerCompleted2(object sender, RunWorkerCompletedEventArgs e)
{
timer1.Start();
ReadFile();
}
How you can see I start the timer1 again, and execute again the ReadFile method. Now if timer1 has reached the interval, so 15 minutes has passed, should execute the timer1.Tick += new EventHandler(Heavy_Tick); that execute the DoWork to worker1. But the timer1 never start.
I can't figure out to this, what am I doing wrong?
Now I get it!
You want to execute worker1 every 15 minutes and worker2 every second but only when worker1 is not busy. Your problem is this here:
if (!worker1.IsBusy) //I skip the reading, worker1 is busy
{
timer1.Stop(); //stop the first timer
worker2.RunWorkerAsync();
}
and this:
public ReadFile()
{
//before this I already assigned to timer1 the tick event and start
timer2.Tick -= new EventHandler(Event_Tick);
timer2.Tick += new EventHandler(Event_Tick);
timer2.Interval = new TimeSpan(0, 0, 1);
timer2.Start();
}
Set both timer intervals and tick event handlers during startup, e.g. Form_Load()or at the beginning of Main(). Start them there too. You should not have to stop any timer at all!
By setting the interval, all you have to do is handle the Tick() event. Remove your .Start() and Stop() calls from your WorkerCompletedand Tick methods and you should do fine.
So a lot could be going on here but you should make sure that:
You timer isn't storing it's old progress and you are checking for a certain length of time before stopping. This will automatically cause the timer to stop when restarting.
The timer.stop() function is not disposing your object to an un-restart-able state.
You aren't accessing the timer variable through some pointer that is maintain a stopped value. (Unlikely but annoying when it happens)
I'd personally consider just pausing the timer and resetting the progress, instead of fully stopping it since this is causing issues.
I am trying to repeat a code execution after predefined time passes and i don't want to mess up things by using threads. Is the below code a good practice?
Stopwatch sw = new Stopwatch(); // sw constructor
EXIT:
// Here I have my code
sw.Start();
while (sw.ElapsedMilliseconds < 100000)
{
// do nothing, just wait
}
System.Media.SystemSounds.Beep.Play(); // for test
sw.Stop();
goto EXIT;
Use a timer instead of labels and StopWatch. You are doing busy waiting, tying up the CPU in that tight loop.
You start a timer, giving it an interval to fire on (100000 milliseconds), then run your code in the event handler for the Tick event.
See Comparing the Timer Classes in the .NET Framework Class Library in MSDN magazine.
You could use a timer what Oded suggested:
public partial class TestTimerClass : Form
{
Timer timer1 = new Timer(); // Make the timer available for this class.
public TestTimerClass()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
timer1.Tick += timer1_Tick; // Assign the tick event
timer1.Interval = 1000; // Set the interval of the timer in ms (1000 ms = 1 sec)
timer1.Start(); // Start the timer
}
void timer1_Tick(object sender, EventArgs e)
{
System.Media.SystemSounds.Beep.Play();
timer1.Stop(); // Stop the timer (remove this if you want to loop the timer)
}
}
EDIT: Just want to show you how to make an easy timer if you don't know how to :)
Lets say I have a button that gets clicked and it does this:
public void ButtonClick(object sender, EventArgs e)
{
System.Timers.Timer NewTimer = new System.Timers.Timer();
NewTimer.AutoReset = false;
NewTimer.Elapsed += new ElapsedEventHandler(TimerElapsed);
NewTimer.Interval = 1000;
NewTimer.Start();
}
public void TimerElapsed(object sender, ElapsedEventArgs e)
{
}
If this button gets clicked 100 times what happens to those instances that have been created? Will garbage collection kick in or does the System.Timers.Timer.Close method need calling and if it does where do you call it from?
No this will not cause a memory leak. In fact the way your code is written it's not guaranteed to execute properly. Timers.Timer is really just a wrapper over Threading.Timer and it's explicitly listed as being collectable even if it's currently running.
http://msdn.microsoft.com/en-us/library/system.threading.timer.aspx
Here you keep no reference to it and hence the very next GC could collect it while your form is still running and before the event ever fires
EDIT
The documentation for Timers.Timer appears to be incorrect. The Timer instance will not be collected if it's unreferenced. It will indeed live on
var timer = new System.Timers.Timer
{
Interval = 400,
AutoReset = true
};
timer.Elapsed += (_, __) => Console.WriteLine("Stayin alive (2)...");
timer.Enabled = true;
WeakReference weakTimer = new WeakReference(timer);
timer = null;
for (int i = 0; i < 100; i++)
{
GC.Collect();
GC.WaitForPendingFinalizers();
}
Console.WriteLine("Weak Reference: {0}", weakTimer.Target);
Console.ReadKey();
They will be collected once method is left. TimerElapsed will be either called or not depending on when Timer gets finalized. Most likely it will be dead long before 1 second passed.
When you call Timer.Close() you thus call Timer.Dispose() that de-registers timer from timer queue and in that case TimerElapsed won't be called (of course if it was not called before).
If you leave timer not closed, GC will eventaully call Finalize() that in turn will call Dispose(). But there is not exact knowledge when it will happen :)
See below example, Console.Out.WriteLine("called!!!") will never execute:
using (System.Timers.Timer NewTimer = new System.Timers.Timer())
{
NewTimer.AutoReset = false;
ElapsedEventHandler TimerElapsed = (sender, args) => { Console.Out.WriteLine("called!!!"); };
NewTimer.Elapsed += new ElapsedEventHandler(TimerElapsed);
NewTimer.Interval = 1000;
NewTimer.Start();
}
Thread.Sleep(3000);
After answers by the_joric and JaredPar and running profiler tests which showed timers sticking around after garbage collection kicked in the reason they stuck around was because there is a reference to the event handler sticking around. For a more detailed explanation see this answer.
The real answer is that it is a memory leak unless the timer is closed in the elapsed event handler.
Just goes to show that although I trust the answers on SO (maybe too much) from the great contributors they may be slightly off.
Can i create successfully a timer clock on a thread? i'm creating one but it doesn't seem to work that well. My app is a multi-thread app that has to start a timer on a thread when ever a certain event happens. The timer is placed in every client connection. The clock doesn't work until i close my winform(i don't know why) . Is there anything in particular that i should know about timers in threads ?
Here is my timer code :
timer1.Interval = 1000;
timer1.Tick += new EventHandler(timer_Tick);
timer1.Enabled = true;
timer1.Start();
You might try to use System.Threading.Timer, which is basically a timer that's in a separate thread. You might also consider using a WaitHandle that's never fired and then using WaitOne(1000, false) to wait for a second.
Try this:
public void EnableTimer()
{
if (this.InvokeRequired)
this.Invoke(new Action(EnableTimer));
else
this.timer1.Enabled = true;
}