-2

I have a Windows Forms application where I need to have a timer working for 90 seconds and every second should be shown after it elapses, kind of like a stopwatch 1..2..3 etc, after 90 seconds is up, it should throw an exception that something is wrong.

I have the following code, but the RunEvent never fires.

        private void ScanpXRF()
        {
            bool demo = false;

            System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();

            try
            {

                for (int timerCounter = 0; timerCounter < 90; timerCounter++)
                {
                    timer.Interval = 1000;
                    timer.Tick += new EventHandler(RunEvent);
                    timer.Start();

                    if(timerCounter == 89) {
                      throw new Exception(); 
                     }
                }

            }
            catch (Exception e)
            {
                timer.Dispose();
                MessageBox.Show("There is a problem!");                   
            }       
        }


          private void RunEvent(object sender, System.EventArgs e)
            {
                //boxStatus.AppendText("RunEvent() called at " + DateTime.Now.ToLongTimeString() + "\n");
                MessageBox.Show("timer fired!");
            }

Is there anything I am doing wrong here or are there other suggestions for other ways to achieve the same result?

sarsnake
  • 26,667
  • 58
  • 180
  • 286
  • 3
    You aren't calling `ScanpXRF()`. If you did, you would see the exception thrown immediately. – LarsTech Oct 17 '19 at 20:24
  • yes I am calling it. I have breakpoints, that's not the issue. – sarsnake Oct 17 '19 at 20:25
  • 2
    Whoa, wait a sec... I might be reading this wrong, but why are you looping 91 times and re-setting the Interval, subscribing to the Tick even (again), and calling Start again? I don't use Timers all that often, but that seems really odd to me. – Broots Waymb Oct 17 '19 at 20:26
  • 2
    But you should be hitting this: `throw new Exception()` pretty darn quick. Nothing in your code stops it from getting there. That loop you are using is messed up. – LarsTech Oct 17 '19 at 20:26
  • Larse, I updated the code. I am not experienced with timers either which is why I am asking here. – sarsnake Oct 17 '19 at 20:28
  • Timers need to be declared at the form level, otherwise it may not get disposed of properly. – LarsTech Oct 17 '19 at 20:29
  • Get rid of the loop. You should be counting in the RunEvent block since that's the block that will be called every second. – LarsTech Oct 17 '19 at 20:32
  • Larse, if you post the answer properly, that can work, I will mark it as an answer. Thank you! – sarsnake Oct 17 '19 at 20:33
  • TBH you don't need half of this, my comment was removed. Just declare it one time with the `Elapsed` event and handle it? It will tick every one second? – Trevor Oct 17 '19 at 20:36
  • Possible duplicate of [What is the best way to implement a "timer"?](https://stackoverflow.com/questions/12535722/what-is-the-best-way-to-implement-a-timer) Plentiful answers to your issue. – Trevor Oct 17 '19 at 20:38
  • 1
    _my comment was removed_ So was mine. Pointing out that MessageBox is not a good aid here is a useful hint imo. I wonder who and why did this? CoC ripples? Am I on a blacklist? – TaW Oct 17 '19 at 20:50
  • @TaW: comments are frequently removed here. If they are flagged by a reader as "no longer needed" a moderator almost certainly will remove them. The Meta community is fond of saying "comments are ephemeral" - if it is important it should be edited into a question post or an answer post. – halfer Mar 14 '20 at 21:19

2 Answers2

3

A timer needs to be declared at the form level, or else it may not be disposed of when the form closes:

System.Windows.Forms.Timer timer;
int counter = 0;

Your starting code should just start the timer:

private void ScanpXRF()
{
   counter = 0;
   timer = new System.Windows.Forms.Timer();
   timer.Interval = 1000;
   timer.Tick += RunEvent;
   timer.Start();
}

The RunEvent is your Tick event being called every second, so your logic needs to go in there:

private void RunEvent(object sender, EventArgs e)
{
  counter++;
  if (counter >= 90) {
    timer.Stop();
    // do something...
  }
}
LarsTech
  • 80,625
  • 14
  • 153
  • 225
  • _A timer needs to be declared at the form level_ - Can you back this up from the documentation? – TaW Oct 17 '19 at 20:55
  • my issue is that Tick event does not fire....I declared the timer in the designer form and set the properties there as well. – sarsnake Oct 17 '19 at 21:08
  • @sarsnake That is because it is being garbage collected. You need to keep a reference to the timer; Hence declare it at the form level. – Sorceri Oct 17 '19 at 21:11
  • @TaW WinForm Timers are components, not controls, so if a Timer component is declared at the method scope, the Form doesn't know to keep track of it. See [How should the clean-up of Timers declared inside the scope of a function be managed?](https://stackoverflow.com/a/24824649/719186). Even though that link is talking about System.Timers.Timer, the principle is the same. Besides, I once posted code with a local timer in the method, and Hans Passant told me that I had a "dangerous timer". Lesson learned. – LarsTech Oct 17 '19 at 21:24
  • 1
    OK, but one could still dispose of it oneself. And how does it explain OPs problem? The answer, of course, shows how to get the overall logic right but OP code should still hit `RunEvent`, right? – TaW Oct 17 '19 at 21:30
  • @TaW Yes, separate issues. If you don't dispose the timer and go to close the form, that timer might still be running. Why the OP is still having issues with the timer not firing? Don't see enough of their code. The hint that they have one in the designer and one declared might by the problem. – LarsTech Oct 17 '19 at 21:37
  • Hello, I tried declaring on the form level as well as in the designer. No go. Timer does not tick. I also switched to System.Timers and it also does not work. Is there anything else I can use instead of TImer? It seems like a simple issue but I have no idea why timer is not going off – sarsnake Oct 18 '19 at 17:32
  • @sarsnake Honestly, we would have to see more of your code to help you. Try creating a new project, drop a timer, set the properties, and see if that works. Avoid using Timers.Timer in a WinForm's application — just use a WinForm's timer. – LarsTech Oct 18 '19 at 17:34
  • Lars, I have a question about your code though - in your code wouldn't the timer stop after 1 second? I need it to run 90 times. According to your code, it will not fire again after 1 second. Does the timer stop after Tick function fires? – sarsnake Oct 18 '19 at 17:40
  • 1
    @sarsnake No, a timer is something that will raise that tick event based on your interval. Interval 1000 is going to call the Tick event every second. You mapped the Tick event to your RunEvent method, so RunEvent will run every second. That is why in my code when the counter is 90 or over, I call `Stop()`, which will then have the timer stop calling the RunEvent. – LarsTech Oct 18 '19 at 17:45
  • Thanks, I think I will forgo the timer as I tried everything and it just does not fire. Back to square one sadly but thank you for your help. Maybe Stopwatch is an alternative, not sure but Timer just doesn't work. If I stumble on something I will post it here – sarsnake Oct 18 '19 at 18:06
  • One thing I could think of after reading the documentation is that my app is not single threaded. I have a serial port that I am polling and a mutex as well. So maybe Timer is just not an option for me – sarsnake Oct 18 '19 at 18:08
  • @sarsnake A WinForms app pretty much needs the `[STAThread]` attribute on the `Main()` entry point. – LarsTech Oct 18 '19 at 18:16
0

made it work

   private void ScanpXRF()
        {
            _pXRFTimerCounter = 0;
            pXRFTimer.Enabled = true;
            pXRFTimer.Interval = 1000;
            pXRFTimer.Elapsed += new ElapsedEventHandler(pXRFTimer_Tick);
            pXRFTimer.Start();
        }

        private static void pXRFTimer_Tick(Object sender, EventArgs e)
        {
            _pXRFTimerCounter++;

            if (_pXRFTimerCounter >= 90)
            {
                pXRFTimer.Stop();
                // do something...               
            }
            else
            {
                MessageBox.Show(_pXRFTimerCounter.ToString() + " seconds passed");
            }
        }

I made the timer

System.Timers

sarsnake
  • 26,667
  • 58
  • 180
  • 286