views:

414

answers:

2

In a VSTO add-in I'm developing, I need to execute a method with a specific delay. The tricky part is that the method may take anywhere from 0.1 sec to 1 sec to execute. I'm currently using a System.Timers.Timer like this:

    private Timer tmrRecalc = new Timer();

    // tmrRecalc.Interval = 500 milliseconds

    private void tmrRecalc_Elapsed(object sender, System.Timers.ElapsedEventArgs e){

        // stop the timer, do the task
        tmrRecalc.Stop();           
        Calc.recalcAll();
        
        // restart the timer to repeat after 500 ms
        tmrRecalc.Start();
    }

Which basically starts, raises 1 elapse event after which it is stopped for the arbitrary length task is executed. But the UI thread seems to hang up for 3-5 seconds between each task.

Do Timers have a 'warm-up' time to start? Is that why it takes so long for its first (and last) elapse?

Which type of timer do I use instead?

+2  A: 

Maybe your calculations are taking longer than you thought. Timers don't have any kind of warm-up.

Is there any reason you can't use a background thread, maybe a BackgroundWorker object to run the calculations without needing a timer?

Tesserex
If I call the `Calc.recalcAll` method manually using a Button on the Ribbon UI, it takes exactly as I said before, 0.1 sec to 1 sec per call to execute fully. Can a BackgroundWorker work with the UI thread?
Jenko
To be honest, I haven't used BackgroundWorkers myself. But you can very easily create new Thread objects, set a ThreadStart delegate, and then start them. When your calculations update, you can have them fire off your UI functions, but yes you need to marshal them. It's easy - either have the background function call Invoke on any controls on your UI, or have your controls protected with an InvokeRequired block. You can look up the latter pattern on Google or here on SO.
Tesserex
To be clear, it technically doesn't matter what control you call Invoke on. Anything on your UI will do. All that matters is that the object was created on a thread that has a message loop running (which was created by Application.Run).
Tesserex
+2  A: 

Instead of using a timer I recommend doing the calculations in a different thread (spawn a thread), and using Thread.Sleep(milliseconds) to sleep between intervals. This has worked quite wonderfully for me.

Cyril Gupta
Never did any multithreading before. How do I spawn a thread and can it work with the UI thread easily? (Don't ask me to write marshals for every method I want to call)
Jenko
Yes, it will work with UI threads well, you just need to call BeginInvoke on the main thread if you are going to update the main thread's UI. It's just 2 lines. .Net has very good support for threading, basically you only need to supply the method's name to a new Thread Object (System.Threading.Thread). In these days of multi-proc computing, you can't do without threading.I have in fact already started learning the Parallel Task Library in the new .Net 4 so that I can make the best use of multiple processors in my future software.
Cyril Gupta