Firing method on interval with System.Threading.Timer in winForm C# - c#

What I want to do is to use the System.Threading.Timer to execute a method with a interval.
My example code looks like this atm.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
System.Threading.Timer t1 = new System.Threading.Timer(WriteSomething, null, TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(10));
}
private void button1_Click(object sender, EventArgs e)
{
textBox1.Clear();
}
public void WriteSomething(object o)
{
textBox1.Text = "Test";
}
}
}
Isn't this suppost to execute the WriteSomething method every 10'th second. What rly happens is that the WriteSomething is executed when I run my application and after 10 seconds the application closes. Think I have missunderstood how this works, can anyone tell me how to do this with the System.Threading.Timer.
thanks in advance, code examples are very welcome

The more likely scenario is that it crashes after 10 seconds. You cannot touch any controls in the callback, it runs on the wrong thread. You'd have to use Control.BeginInvoke(). Which makes it utterly pointless to use a System.Threading.Timer instead of a System.Windows.Forms.Timer.
Be practical. Make it 100 milliseconds so you don't grow a beard waiting for the crash. And don't use an asynchronous timer to update the UI, it is useless.

FYI, there is nothing about System.Windows.Forms timer that doesn't allow you to create in code (it's not just a "drag-and-drop" timer). Code:
Constructor code:
System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
timer.Tick += OnTimerTick;
timer.Interval = 10000;
timer.Start();
Event Handler:
private void OnTimerTick(object sender, EventArgs e)
{
// Modify GUI here.
}

Just to reiterate what Hans said, in a WinForms application all GUI elements are not inherently thread-safe. Almost all methods / properties on Control classes can only be called on the thread the GUI was created on. The System.Threading.Timer invokes its callback on a thread pool thread, not the the thread you created the timer on (see reference below from MSDN). As Hans said, you probably want a System.Windows.Forms.Timer instead, that will invoke your callback on the correct thread.
You can always verify whether you can call methods on a Control (assuring you're on the correct thread) by using the code:
System.Diagnostics.Debug.Assert(!InvokeRequired);
inside your event handler. If the assert trips, you're on a thread that cannot modify this Control.
Quote from MSDN help on System.Threading.Timer on the callback method you passed in the constructor:
The method does not execute on the
thread that created the timer; it
executes on a ThreadPool thread
supplied by the system.

Common error: need to keep timer variable as class member as garbage collector may kill it.

Related

Preventing A Thread From Ending

I understand that a Thread will terminate when all of the code it has been assigned is done, but how can I make it so that it stays around waiting for an event? Here is a simple look at my code so you can understand better what my problem is:
public static class TimeUpdater
{
static TimeUpdater()
{
//Initialize the Timer object
timer = new Timer();
timer.Interval = 1000;
timer.Tick += timer_Tick;
}
public static void StartTimer()
{
timer.Start();
}
private static void timer_Tick(object sender, EventArgs e)
{
//Do something
}
}
From the main Thread, here is how I am calling these methods:
Thread timeThread = new Thread(TimeUpdater.StartTimer);
timeThread.Name = "Time Updater";
timeThread.Start();
What this does is it goes inside the StartTimer() method, runs it, and then the thread terminates without ever entering the timer_Tick event handler. If I call StartTimer() from the main thread it works fine.
Anyone can spot the problem? Cheers.
You are starting the timer on a separate thread. Starting a timer is a very fast operation. That's why your thread completes immediately. Tick events are started on the thread-pool asynchronously when the time is due.
If you want a thread wait for something then you should insert code into the thread procedure to wait on something. At the moment you do not wait for anything.
If you want to run the timer procedure, just call it.
Apparently I didn't need to use a Timer object. Here is how I made it work:
public static void StartTimer()
{
while (true)
{
UpdateTime();
Thread.Sleep(1000);
}
}
Thanks for the help guys!
In your StartTimer method you can spin around an infinite loop and call Thread.Sleep to delay execution when needed. I see you have already figured that out though. An alternate idea is to use a timer, but instead of starting it from a worker thread start it from the main thread. You really do not need to be manually creating threads at all here.

Timer being interrupted

I have a problem with the Timer in a Windows Forms app. The archiver that needs the Timer to note the time of archiving. However something is interrupting the timer?
I suspect it is the streams. Any advice on what could cause the timer to be interrupted?
public partial class Form1 : Form
{
int timerCounter = 0;
System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
public Form1()
{
InitializeComponent();
timer.Interval = 1000;
timer.Enabled = true;
}
public void button2_Click(object sender, EventArgs e)
{
timer.Start();
timer.Tick += new EventHandler(timer1_Tick);
// code for archiving, streams
timer.Stop();
MessageBox.Show("Archive was created! :)");
}
public void timer1_Tick(object sender, EventArgs e)
{
this.label7.Text = (++timerCounter).ToString();
}
}
The Windows Forms timer is not multi-threaded. That means, the tick event only fires when the program is idle (receives messages through its message queue). In your program this doesn't seem to be the case. You can easily check this: If your UI is responsive during the archiving process, then the Forms.Timer runs also and the problem is somewhere else. If it is not responsive, then the form (and the timer as a consequence) is blocked (no messages in the application's message queue are processed).
There are two ways out of this:
To do what you want to achieve, you can use System.Timers.Timer or System.Threading.Timer, as they run asynchronously in the background. The UI still won't update (the timer method would stop), however, as the UI is still blocked (see above).
The other way is to use a background worker for the archiving process (this then runs in another thread). The UI and the timer keep responsive.
First of all you should to know that long running operation should be performent in another than UI thread. So, you create a proccessing thread which do archiving itself and also it notifies UI by using Control.Invoke method. msdn description of Control.Invoke
Initially i thought that you are performing your archiving in the background thread. If it is not so - you should consider using BackgroundWorker for executing the operation in the background (here's some examples).
Here is the simpler solution, though:
Try to add Application.DoEvents() in your button2_Click handler (I guess you are waiting for 'streams' to finish the archiving). For timer to fire and for label7 to redraw its new text value the redraw event should be processed.
The use of timer here is unnecessary why don t you just use TimeSpan
public void button2_Click(object sender, EventArgs e)
{
DateTime startTime = DateTime.Now;
// code for archiving, streams
TimeSpan diff = DateTime.Now - startTime;
MessageBox.Show("Archive was created! in " + diff.TotalSeconds + " seconds.");
}

System.Timers.Timer delay hangs application

I have an issue with the System.Timers.Timer object. I use the timer object to perform a task at regular intervals. In the timer constructor I call the method doing the work ( DoTimeCheck() ), to ensure that the task is run once at startup also. The work (at regular intervals) is done in a BackgroundWorker.
I call the timer with this:
UpdaterTimer ut = UpdaterTimer.UpdaterTimerInstance;
My problem is that I need to delay the first run of the task with 3 minutes(the one that runs at application startup). Subsequent runs (Elapsed event) should run without delay. I thought of doing this by calling
System.Threading.Thread.Sleep(TimeToDelayFirstRunInMiliseconds);
but this fails, because it also hangs the UI of the app (main thread) making it unusable. How can I delay the first run of DoTimeCheck() without hanging the UI?
The code of the timer is below. If the issue is not presented in a clear manner please let me know and I will edit. Thank you in advance.
public sealed class UpdaterTimer : Timer
{
private static readonly UpdaterTimer _timer = new UpdaterTimer();
public static UpdaterTimer UpdaterTimerInstance
{
get { return _timer; }
}
static UpdaterTimer()
{
_timer.AutoReset = true;
_timer.Interval = Utils.TimeBetweenChecksInMiliseconds;
_timer.Elapsed += new ElapsedEventHandler(_timer_Elapsed);
_timer.Start();
DoTimeCheck();
}
static void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
DoTimeCheck();
}
private static void DoTimeCheck()
{
//... work here
}
}
One way of doing this would be to give the Timer Interval an initial value (e.g. 3 minutes). Then, in your Elapsed event handler, you could change the interval to your regular value which will be used from then on.
_timer.Interval = Utils.InitialCheckInterval;
static void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
if (_timer.Interval == Utils.InitialCheckInterval)
{
_timer.Interval = Utils.RegularCheckInterval;
}
DoTimeCheck();
}
It appears (although you've not shown that code) that you're calling Sleep(TimeToDelayFirstRunInMiliseconds); on the main/GUI thread, so that's what's causing your UI thread to hang. Instead, you should set your timer to be delayed by 3 minutes on the first run, then once it runs you change the timer again to run at the frequency you desire for all the subsequent runs.
Your UI resides on the same thread, so when you put the thread to sleep, it will cause your UI to hang as well. You need to run the timer on a different thread.
You're already using timers fine it seems. Just use another one to do a three minute delay before you start up your other timer.
timer = new Timer();
timer.AutoReset = false;
timer.Interval = 3*60*1000;
timer.Elapsed += startOtherTimerMethod;
timer.Start();
Edit: I should note that this is much the same as Peter Kelly's answer except that his solution is more elegant since it uses just one timer, no extra methods and takes advantage of the fact that the timer is changeable between runs. If you liked this answer, you'll love his. ;-)
Your UI needs a seperate thread, currently you are also sleeping the UI. Check this post.
You should not use thread.sleep in this situation you should use the winforms control
BackgroundWorker which never locks the main UI. You can write your logic there.
example here:
http://www.knowdotnet.com/articles/backgroundworker.html
Use a System.Threading.Timer - the constructor takes a parameter for the delay of the first run and an interval for the subsequent runs.

How do I let main thread suspend and wait for the System.Timer.Timer running

Hi I am using System.Timer.Timer
I always get NULL after running my programme and it only works if I add this.sleep(6000). Suppose the reason is the main thread ends but the timer hasn't finished ...
Here is the class and I call the class from my main form.
Class class1
{
string finalResult = "";
public string getNumber()
{
RunTimer();
return finalResult;
}
pubic void RunTimer ()
{
timer = new System.Timers.Timer(30000);
timer.Interval = 1000;
timer.Elapsed += new System.Timers.ElapsedEventHandler(cal);
timer.Start();
}
private void cal(object sender,System.Timers.ElapsedEventArgs e)
{
finalResult += READFROMCOMPORT;
}
}
A good rule of thumb is to never use Thread.Sleep in production code. Its presence usually indicates poor threading design.
Instead, listen to the COM Port's DataReceived event.
Why would you want to use a timer in this instance?
If you want this to be a synchronous operation and wait for finalresult to get populated, you could just wait 6 seconds before returning READFROMCOMPORT.
EDIT: If you need the program to continue running, you could create a callback event that you bind to after you instantiate the class. Once the timer expires, you can raise the callback event and pass your new value
EDIT 2: an easy way to implement this sort of asynchronous'ness is to use a BackgroundWorker component. the backgroundworker has a DoWork() method which contains your asynchrnous code, as well as a "RunWorkerCompleted" callback event which you can subscribe to to get your asynchronous result. See here for more: http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
If you're already calling GetNumber() from a separate thread from the GUI, ditch the timer, do the work in GetNumber(), and the thread will stop returning early. In any case, don't use Thread.Sleep because there's no way to unblock it if you need to, or if the app quits. Use Monitor.Wait instead, which can be unblocked with Monitor.Pulse.
Use TimerCallback
http://www.gnu.org/software/dotgnu/pnetlib-doc/System/Threading/Timer.html

My Timer event crashes because the events are called on a different thread

I get the error "Cross-thread operation not valid: Control 'label1' accessed from a thread other than the thread it was created on." when I run this code:
using System;
using System.ComponentModel;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Timers;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
System.Timers.Timer T = new System.Timers.Timer();
public Form1()
{
InitializeComponent();
T.Elapsed += new ElapsedEventHandler(T_Elapsed);
T.Start();
}
void T_Elapsed(object sender, ElapsedEventArgs e)
{
label1.Text = "This will not work";
}
}
}
I thought events ran in the same thread as they were triggered in.
We have 3 Timer classes in NET (Timers.Timer, Threading.Timer and Windows.Forms.Timer) but only the Windows.Forms one has a Tick event.
When used normally (ie dragged to the Form in Design-Time or created in some Form Code) the event is running on the Main thread and your problem should not occur.
It is therefore most likely that you create the Timer object in another thread, you should probably Edit your question to show us how/where you create it and tell us if it is on another Thread on purpose.
While the "Accepted" answer is technically correct (in that this will fix the problem) this doesn't answer the question.
The ANSWER is to use
void T_Elapsed(object sender, ElapsedEventArgs e)
{
this.BeginInvoke(new MethodInvoker(delegate(){
label1.Text = "This will work";
}));
}
http://jaysonknight.com/blog/archive/2007/02/14/using-anonymous-methods-for-control-invoke-control-begininvoke.aspx
You might be using the wrong kind of timer. Try the WinForms timer, its runs on the GUI thread so you don't have to do Invoke
Are you remembering to use InvokeRequired? It will allow you to update a UI element on the UI thread from the Timer thread.
I'm assuming you're talking about a WinForms application.
When trying to update a Form element (which lives on the UI thread) from another thread, you need to use Control.Invoke or Control.BeginInvoke. You pass a delegate to the method you want to invoke (or pass an anonymous method in) and then that delegate gets called on the UI thread rather than the calling thread.
Yes, events are executed in the same thread which triggered them. It just so happens that System.Timers.Timer uses a ThreadPool thread by default when raising the Elapsed event. Use the SynchronizingObject property to cause the Elapsed event handler to execute on the thread hosting the target object instead.
public partial class Form1 : Form
{
System.Timers.Timer T = new System.Timers.Timer();
public Form1()
{
InitializeComponent();
T.Elapsed += new ElapsedEventHandler(T_Elapsed);
T.SynchronizingObject = this;
T.Start();
}
void T_Elapsed(object sender, ElapsedEventArgs e)
{
label1.Text = "This will not work";
}
}
If you're doing this asynchronously (it sounds like you are), be sure that you catch exceptions in the event handler or callback. If a background thread throws an exception, it will crash the app. This is the most common cause that I've seen of this behavior.
I am not a winform developer. But i heard something regararding Timer class which you are using. I think you might want to set these properties and check.
T.Interval = 5000; //in Mili Seconds
T.Enabled = true;

Categories