-2

I'm trying to use System.Timers.Timer on a UI control.

The error: System.Timers.Timer "Cross-thread operation not valid: Control 'txtOutput' accessed from a thread other than the thread it was created on."

My code is the following:

System.Timers.Timer timeRandomEvent = new System.Timers.Timer(10 * 1000); 

// timer for random events  
timeRandomEvent.Elapsed += new ElapsedEventHandler(timeRandomEvent_Elapsed);
timeRandomEvent.Start();

void timeRandomEvent_Elapsed(object sender, ElapsedEventArgs e) 
{
    wl("Adding some text to a text box.");   // Exception occurs here
}

Is there a way to allow it, or another alternative that's hopefully easy?

Phil
  • 607
  • 1
  • 8
  • 22
  • 1
    Could you just use `System.Windows.Forms.Timer` instead? – hatchet - done with SOverflow Jun 06 '14 at 16:04
  • @hatchet Although that seems to be the natural choice for WinForms, `System.Windows.Forms.Timer` is actually less accurate than `System.Timers.Timer` ([limited to accuracy of 55 milliseconds](http://msdn.microsoft.com/en-us/library/system.windows.forms.timer%28v=vs.90%29.aspx)). So *if* the OP wanted a WinForms application with a more accurate timer, a `System.Timers.Timer` is the way to go. – JW Lim Jun 06 '14 at 16:08
  • @JWLim - I thought about that, but with the timer in his/her code set to fire every 10 seconds, I thought the 55 millisecond resolution issue might be irrelevant. – hatchet - done with SOverflow Jun 06 '14 at 16:11
  • @hatchet I agree, but it is still worth mentioning as we're not sure if that's the actual code the OP is going to use :) Besides, I think it's always a good thing to understand your options, lest you try to use them for things they were not designed for. – JW Lim Jun 06 '14 at 16:13

1 Answers1

4

You need to set the SynchronizingObject property of your timer to your form object.

timer.SynchronizingObject = this; // Synchronize the timer with this form UI

Relevant excerpt from the official documentation:

When the Elapsed event is handled by a visual Windows Forms component, such as a button, accessing the component through the system-thread pool might result in an exception or just might not work. Avoid this effect by setting SynchronizingObject to a Windows Forms component, which causes the method that handles the Elapsed event to be called on the same thread that the component was created on.

JW Lim
  • 1,794
  • 3
  • 21
  • 41
  • @Phil you're welcome, I'm glad it helped. I think you should tag your question with `[winforms]` btw (and perhaps `[timer]`), instead of `[multithreading]`. – JW Lim Jun 06 '14 at 16:01