-1

I'm unsure of what's wrong with this code. The timer1 interval is set to 1000.

namespace timerbug
{
    public partial class Form1 : Form
    {
        int value;

        public Form1()
        {
            InitializeComponent();
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            do
            {
                value++;
                label1.Text = value.ToString();
            }
            while (value <= 5);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            value = 0;
            timer1.Start();
        }
    }
}

I thought the label would display 1 to 5, then stop. The counting doesn't even show up until 6, and continues to go up until I stop the program. Can someone explain why the numbers 1 to 5 are not showing up, and then why it doesn't stop at 5? Thank you.

DaveB
  • 51
  • 7
  • 3
    Because the UI doesn't update until the message pump runs. You can force it by adding `Application.DoEvents()` to the body of your loop, but that practice is highly discouraged. Take a look at [this quesiton](https://stackoverflow.com/questions/5181777/use-of-application-doevents) for more information. – itsme86 Jan 25 '19 at 20:45
  • 1
    it doesn't stop at 5 because you have a `do..while` loop, not a `while` loop – Daniel A. White Jan 25 '19 at 20:47
  • 1
    Possible duplicate of [Label text doesn't get updated until the whole loop is completed](https://stackoverflow.com/questions/14764513/label-text-doesnt-get-updated-until-the-whole-loop-is-completed) – mjwills Jan 25 '19 at 20:49
  • 2
    If I was you, I'd use the debugger and step through the code line by line. Put a breakpoint in `timer1_Tick`, right after the `while` statement. Observe `value` (it's 6 since that's the first value that is **not** <= 5. Put a breakpoint at the top of `timer1_Tick`. Continue running. After a second it will hit that breakpoint at the top. Observe `value` (it's still 6). Step through the code. Note that the body of the `do..while` loop is run (since it hasn't hit the `while` condition yet).... – Heretic Monkey Jan 25 '19 at 20:53
  • itsme86: Thank you. Reading that article, I should probably look into async/await to get the code to work the way I want, yes? I'm not yet familiar with those, so I'll have to check it out. – DaveB Jan 25 '19 at 20:54
  • Daniel A. White: Thank you, I'll change my loop accordingly and test it out. Heretic Monkey: Thanks, I'll uses the breakpoint and step through the code. – DaveB Jan 25 '19 at 20:55
  • mjwills - That article explained it very well, thank you for pointing me to the other thread. – DaveB Jan 25 '19 at 20:57
  • 1
    I think instead of updating the value in a loop inside the `Tick` event, you should just update it once. But first check if it's already `5`, and if it is, stop the timer. Something like: `if (value < 5) label1.Text = ++value.ToString(); else timer1.Stop();` – Rufus L Jan 25 '19 at 21:08

2 Answers2

1

As other people have correctly pointed out in comments, it stops at 6 instead of 5 because 6 is the first value for which value <= 5 evaluates as false (You are using a do-while loop, which means the condition is evaluated after the body is executed.). In order to stop at 5, you could either use regular while loop or change the condition to value < 5 or value <= 4.

Furthermore, 6 iterations of a loop in C# happen in a few microseconds. You could not really see the numbers being displayed in the label even if everything else was done correctly, simply because it would happen too fast. In order to see anything happen, you would need to introduce some kind of a delay (Thread.Sleep()) and at the end of each iteration, you would have to call Application.DoEvents() to let the Form re-paint.

Alternatively, you could use the Timer's ticks, which would be preferable in most cases. You could do it like this for instance.

namespace timerbug
{
    public partial class Form1 : Form
    {
        int value;

        public Form1()
        {
            InitializeComponent();
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            if (value < 5)
            {
                value++;
                label1.Text = value.ToString();
            }
            else
            {
                timer1.Stop();
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            value = 0;
            timer1.Start();
        }
    }
}
natiiix
  • 1,005
  • 1
  • 13
  • 21
  • Thank you. My solution below utilized this, and also updated using the Invalidate and Update statements. – DaveB Jan 25 '19 at 21:10
0

Changing the timer1_tick code to this worked fine, thanks for the assistance. I have a lot to learn.

        value++;

        if (value >= 5)
        {
            timer1.Stop();
        }

            label1.Text = value.ToString();
            label1.Invalidate();
            label1.Update();

        }
DaveB
  • 51
  • 7
  • There is no reason to invalidate or update the label. You just change it, and it updates all on its own. – Servy Jan 25 '19 at 21:07
  • Yes, I see that, you are correct. However, when drawing / painting (instead of just labels), I'll need the statements to update the screen as the ticks occur instead of after it all completes. This part was my little test. Thank you. – DaveB Jan 25 '19 at 21:23