C# System.Timers.Timer Class elapsed event and timer general precautions - c#

Two questions.
One: in a winforms application is it a good or bad idea to have a system.timers.timer be enabled and disabled inside of it's elapsed event so that the main UI thread can have access to variables and methods that were created on that main UI thread? So for example with code:
myElapsedTimerEvent(object sender, ElapsedEventArgs args)
{
timer.enabled = false;
/***Call some functions and manipulate some variables***/
timer.enabled = true;
}
Two: In anyone's experience, what are some precautions and dangers to be warned about the system.timers.timer in winform and c#? Are there any examples that you can provide about things that could happen with the hardware and/or software if a timer is not used properly?
Any suggestions for using system.timers.timer would be much appreciated.
Thanks for reading.

It is safe to set the Enabled property of a timer from inside the event handler, provided that the event handler is executed in the UI thread. Otherwise it is not safe, because the System.Timers.Timer class is not thread-safe. The make the handler execute in the UI thread you must set the SynchronizingObject property of the timer to the current Form. For example:
public Form1()
{
InitializeComponent();
timer = new Timers.Timer(5000);
timer.Elapsed += Timer_Elapsed;
timer.SynchronizingObject = this;
timer.AutoReset = true;
}
If I am not mistaken, this assignment happens automatically when you use the designer to add a Timer in a Form.
My suggestion though is to use the System.Windows.Forms.Timer, because it comes without thread-safety considerations. You are not restricted to only one timer. You can have as many of them as you want. Just keep in mind that their handlers are running in the UI thread, so you should avoid putting lengthy code in there, otherwise the responsiveness of the UI may suffer.

Related

What is the use of Dispatcher Priority, DispatcherTimer, DispatcherFrame

I have an Async DataGrid loading feature. Hence, i need to call WaitFor(). Here's that code:
WaitFor(TimeSpan.Zero, DispatcherPriority.SystemIdle);
And following are the 2 methods. Can someone explain what this methods are exactly doing?
public static void WaitFor(TimeSpan time, DispatcherPriority priority)
{
DispatcherTimer timer = new DispatcherTimer(priority);
timer.Tick += new EventHandler(OnDispatched);
timer.Interval = time;
DispatcherFrame dispatcherFrame = new DispatcherFrame(false);
timer.Tag = dispatcherFrame;
timer.Start();
Dispatcher.PushFrame(dispatcherFrame);
}
public static void OnDispatched(object sender, EventArgs args)
{
DispatcherTimer timer = (DispatcherTimer)sender;
timer.Tick -= new EventHandler(OnDispatched);
timer.Stop();
DispatcherFrame frame = (DispatcherFrame)timer.Tag;
frame.Continue = false;
}
You do not need any WaitFor(). Why waiting for something anyways? Just let the UI thread unfrozen and once data loaded the DataGrid will display them.
The methods you posted are doing the.... WaitFor mechanism. The method name explains it all :)
Here are few more details:
DispatcherTimer is a simple dumb Timer you might already know from basic C# just once tick method invoked it will be executed directly on UI thread, hence you do not need to care whether you are on UI thread or not. You always are :)
DispatcherTimer has a prority means if proprity set to high the tick invocation method will be called immediately after interval. If proprity is set to Background the tick method will be invoked when UI thread is not busy.
DispatcherFrame is the current scope you are in. Every displatcher operation has sort of scope. Each scope processes pending work items
Dispatcher.PushFrame is same as DoEvent() back when people used WinForms alot. To keep it simple with DoEvent you are forcing UI thread to do something.
To sum up you wait for things to get done in UI thread.
I hope this helps you any futher.

System.Windows.Forms.Timer not firing

I want to use a System.Windows.Forms.Timer to ensure that an event fires on the UI thread of an excel addin I'm creating. I construct the timer as follows:
private System.Windows.Forms.Timer _timer;
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
Debug.WriteLine("ThisAddIn_Startup:" + Thread.CurrentThread.ManagedThreadId);
_timer = new System.Windows.Forms.Timer();
_timer.Tick += new EventHandler(TimerEventHandler);
_timer.Interval = 500;
}
The timer is fired by a COM event from a library I am using:
private void OnEvent()
{
_timer.Start();
}
I then expect the _timer to call the following method when it ticks:
public void TimerEventHandler(object sender, EventArgs args)
{
_timer.Stop();
Debug.WriteLine("Tick: " + Thread.CurrentThread.ManagedThreadId);
}
As I understand, when I create the timer in the Addin thread, even though it is started from another thread (COM event in this case), it should fire on the thread that it was created on, i.e. the addin thread. However, this doesn't happen.
I have implemented this exact mechanism in an RTDServer I wrote in the past (as outlined by Kenny Kerr) and it works as expected but the _timer in this scenario never ticks.
I have also read other SO articles that point to the same behavior and can't figure out what is different about my addin setup?
EDIT:
The OnEvent() method is fired.
The winforms timer is a control and must be used by placing it on a form. You never add it to a control-collection, so I would not expect it to work properly. The documentation says the following
Implements a timer that raises an event at user-defined intervals. This timer is optimized for use in Windows Forms applications and must be used in a window.
Therefore, I would suggest that you use an instance of the System.Timers.Timer class. This class can be used anywhere.
Note that the Tick-event you use above, is called by another name in the System.Timer.Timer class, namely the Elapsed-event.
I initially meant to post this as comment, but it turned to be too long.
Firstly, your thread structure is a bit confusing to me, the way you described it. Put Debug.WriteLine("OnEvent:" + Thread.CurrentThread.ManagedThreadId) inside OnEvent and let us know all thread IDs you see from your debug output.
That said, the rules are:
You should create WinForms' Timer object on an STA thread, and the thread should be configured as STA before it starts.
This thread may or may not be the main UI thread (where your main form was created), but it still should execute a message loop (with Application.Run) for timer events to fire. There are other ways of pumping messages, but generally you do not control them from .NET code.
You should handle the events sourced by WinForms' Timer on the same thread it was created. You can then 'forward' these events to another thread context if you like (using SynchronizationContext Send or Post) but I can't think of any reasons for such complexity.
The answer by #Maarten actually suggests the right way of doing it, in my opinion.
I don't yet understand why the Forms.Timer doesn't operate as expected but the following excellent article explains in detail how to marshal work onto the UI thread: http://www.codeproject.com/Articles/31971/Understanding-SynchronizationContext-Part-I

How to trigger an event for the given interval of time repeatedly in c#?

How to schedule the event, for instance I need to call a method which should perform its action for every given seconds. I'm developing simple windows form app, I tried using like
while(true)
{
methodToBeScheduled();
Thread.Sleep(60000);
}
This particular piece of code makes my application "Not-responding" while its executing. I hope timer can do this or any other logic that you experts suggest, kindly please let me know.
Thanks!
You can use the WinForms timer:
Timer _timer;
// In constructor (or anywhere you want to start the timer, e.g. a button event):
_timer = new Timer();
_timer.Interval = 60000; // milliseconds
_timer.Tick += (sender, e) => methodToBeScheduled();
_timer.Start();
This will cause methodToBeScheduled to be called once every 60 seconds, roughly. It will be called on the main UI thread, so avoid doing any heavy processing in it.
The advantage of using this timer is that it's built-in, doesn't require thread synchronization, and is simple to use. The disadvantage is that the interval is not exact -- the actual interval will vary depending on what other messages need to be processed in the application, and is also at the mercy of the Windows system clock, which is only accurate to 10-20ms or so.
You can use a Timer(System.Threading.Timer).
using System;
using System.Threading;
Timer _timer = null;
_timer = new Timer(o =>
{
methodToBeScheduled();
});
_timer.Change(TimeSpan.Zero, TimeSpan.FromSeconds(60));
Var sequence = Observable.interval(1).publish
Sequence.subscribe ....
Will allow to subscribe to an observable that will fire an onnext every second. See reactive extension ..
Hate typing on iPads....
Yes, there are three different types of timers (all of which are named Timer but behave a little different) in .net. The windows.forms timer executes a function at a certain rate--it calls the function from the UI thread. The System.Threading Timer does the same but calls the function from another thread. There is another timer that I can't remember off the top of my head. You will have to pick one of them based on your circumstance.
Threading timer is my favorite. Here is an example if how to use it. Just keep in mind whatever you are calling is not done from the UI thread. May want to use the forms timer or synchronize things if that's an issue.

Creating a background timer to run asynchronously

I'm really struggling with this. I'm creating a winforms application in visual studio and need a background timer that ticks once every half hour - the purpose of this is to pull down updates from a server.
I have tried a couple of different approaches but they have failed, either due to poor tutorial/examples, or to my own shortcomings in C#. I think it would be a waste of time to show you what I have tried so far as it seems what I tried was pretty far off the mark.
Does anyone know of a clear and simple way of implementing an asynchronous background timer that is easily understandable by a C# newbie?
// Create a 30 min timer
timer = new System.Timers.Timer(1800000);
// Hook up the Elapsed event for the timer.
timer.Elapsed += OnTimedEvent;
timer.Enabled = true;
...
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
// do stuff
}
with the usual caveats of: timer won't be hugely accurate and might need to GC.KeepAlive(timer)
See also: Why does a System.Timers.Timer survive GC but not System.Threading.Timer?
Declare member variable in your form:
System.Timers.Timer theTimer;
On form load (or whatever other time you need to start update polling), do:
theTimer = new System.Timers.Timer(1800000);
theTimer.Elapsed += PollUpdates;
theTimer.Start();
Declare your PollUpdates member function like this:
private void PollUpdates(object sender, EventArgs e)
{
}
I think you need to know about all timer classes. See Jon's answer below.
What kind of timer are you using?
System.Windows.Forms.Timer will execute in the UI thread
System.Timers.Timer executes in a thread-pool thread unless you
specify a SynchronizingObject
System.Threading.Timer executes its callback in a thread-pool thread
In all cases, the timer itself will be asynchronous - it won't "take up" a thread until it fires.
Source: Do .NET Timers Run Asynchronously?

SynchronizingObject vs. Invoke

In my form's class, I've added a method to "fade" it out. This makes use of System.Timers.Timer and the Elapsed event uses a delegate to change the form's opacity. This was the code:
public void FadeOut()
{
// Timer for transition
Timer fade = new Timer();
// Transition code
fade.Elapsed += delegate
{
this.Opacity += 0.05;
if (this.Opacity >= .95)
{
this.Opacity = 1;
fade.Enabled = false;
fade.Dispose();
}
};
fade.Interval = 100;
fade.Enabled = true;
}
This caused a "Cross-thread operation not valid" error, which is a common hurdle I see. So I looked around for solutions and the first ones to come up involved using .BeginInvoke and blocks of code to keep the call to the same thread as the control. But I found this looked really bulky, so I kept looking and then discovered the SynchronizingObject property of System.Timers.Timer. This seems better because it only needed one extra line of code:
// Timer for transition
Timer fade = new Timer();
fade.SynchronizingObject = this;
The code runs fine now. But I'm really confused, how come a lot of solutions are suggesting the use of BeginInvoke/Invoke when all that's needed is to set SynchronizingObject to the form control?
Mostly because it is pointless to use the property. Yes, it ensures that the Elapsed event handler runs on the UI thread. But now it just does the same thing as a System.Windows.Forms.Timer.
Not quite though, it is worse. Because it doesn't guarantee that Elapsed won't be called after you disable it. Disabling it doesn't flush any pending invokes nor TP threads that aren't ready to run yet. There could be hundreds if the Interval is small compared to the amount of work done by the handler.
You absolutely want a System.Windows.Forms.Timer here. You are not doing any useful work on the threadpool thread.
I'm not sure, but I believe that the Timer will internally use Invoke or BeginInvoke as well on the SynchronizingObject property.
Let us say that this property just gives some abstraction to the developer; to make his life easier.
My guess was indeed correct, this is what Reflector tells us about the MyTimerCallback private member method of System.Timers.Timer:
ElapsedEventHandler onIntervalElapsed = this.onIntervalElapsed;
if (onIntervalElapsed != null)
{
if ((this.SynchronizingObject != null) && this.SynchronizingObject.InvokeRequired)
{
this.SynchronizingObject.BeginInvoke(onIntervalElapsed, new object[] { this, e });
}
else
{
onIntervalElapsed(this, e);
}
}
Why don't you use the WinForms timer? This is based on window messages and will always run in the UI thread; since you want to perform updates where the UI thread needs to pump messages anyways this may be a better solution (no synchronization/blocking required).
Timer solutions like this are really a bit of a hack.
You'd be better off writing a proper asynchronous thread and doing the callback either with
BeginInvoke or SynchronizationContext.
As you rightly observe, it's far from a one-liner, but multi-tasking, done properly, never is.
The point is the SCOPE of code. The whole event handler? or just the UI changing code.
timer.SynchronizingObject make the event handler to be called on the thread of given object. If you set this to 'this' in 'Form1' class, This means that all of your code for processing timer event is run by that same thread of 'Form1' instance even though you created a thread based timer. So this does NOTHING. SAME as windows form timer.
The reason you want to do this is because you want to access UI controls and make some changes in Form1, but the whole UI hangs if you use windows form timer. Because they all get executed on the same thread.
To avoid this, you use a threading based timer. Your event handler is called on another thread that comes from some system thread pool. This solves the problem of hanging UI. However, this brings up another problem. Cross-thread accessing UI controls exception. On some versions of Visual Studio, you can disable this checking on debug builds. But there is no way you can just bypass this checking on release builds. This thread checking is just by design to safeguard from crashes caused by multi-threading. THEN you need to use all those invoke and delegation stuff.
The important part here is that it is the only few lines of code that is redirected to be run on the Form1 thread. Not the whole event handler. Most of the event handling code is run on another thread. And that includes code like doing something on network or disk.
This makes the DIFFERENCE.
BUT, all these apply to windows form apps only. For WPF, just use dispatcher timer. (This is why you cannot find Windows.Threading in WinForm because you can't used dispatcher timer in WinForm, but available in WPF)

Categories

Resources