The "My timer" event crashes because events are called on another thread
I get the error "Invalid cross-stream operation: control 'label1' is accessible from a thread other than the thread in which it was created." 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 the events are running on the same thread they were fired on.
You may be using the wrong timer. Try a WinForms timer, it runs on a GUI thread, so you don't have to do Invoke
We have 3 timer classes in NET (Timers.Timer, Threading.Timer and Windows.Forms.Timer), but only Windows.Forms has a Tick event.
In normal use (i.e. dragged onto a form at design time or generated in some form code) the event is triggered on the main thread and your problem shouldn't occur.
So most likely you are creating a Timer object on a different thread, you should probably change your question to show us how / where you create it and tell us if it is for a different Thread.
While the "Accepted" answer is technically correct (in doing so it will fix the problem), it doesn't answer the question.
ANSWER should 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
Do you remember using InvokeRequired ? This will allow you to update the UI element on the UI thread from the Timer thread.
I am assuming you are 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 call (or you pass an anonymous method) and then that delegate is called on the UI thread, not the calling thread.
Yes, events run on the same thread that called them. It just so happens to System.Timers.Timer
use the ThreadPool
default thread when creating an event Elapsed
. Use the property SynchronizingObject
to have the event handler Elapsed
run on the thread that hosted the target.
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 are doing this asynchronously (which sounds like you), make sure you catch the exceptions in your event handler or callback. If a background thread throws an exception, it will crash the application. This is the most common reason I've seen this behavior.
I am not a winform developer. But I heard something you read in the Timer class. I think you can set these properties and check.
T.Interval = 5000; //in Mili Seconds
T.Enabled = true;