4

I have this code:

for(int k = 0; k<11; k++)
{
    pBar.Maximum = 10;
    pBar.Value = k;
    if (pBar.Maximum == k)
        pBar.Value = 0;
}

However, the problem is, the progressbar gets reset when it is about 60% full. How can I ensure that the progressbar will fill all the way before being reset?

DaveRandom
  • 87,921
  • 11
  • 154
  • 174
CC Inc
  • 5,842
  • 3
  • 33
  • 64
  • 2
    With that code, I'd be surprised if it were even visible, as you don't appear to let the message pump run, and render any changes – Rowland Shaw Jul 15 '12 at 19:37
  • What exactly are you doing inside that loop? It doesn't actually look like this, I presume? – vgru Jul 15 '12 at 19:39
  • Unfortunately that happens all the time in a themed interface (Windows XP themed and above). If you switch to Classic mode, the progress bar will appear fully filled. I have no idea why it happens, but I suffer from it as well. – GSerg Jul 15 '12 at 19:40
  • @Groo, I am adding an sql row, based on a list. I used to have it in a foreach loop, but that did not have a current index value. – CC Inc Jul 15 '12 at 19:45
  • @GSerg, that does not happen to me. It does display 1 or higher. – CC Inc Jul 15 '12 at 19:49
  • @GSerg I generally don't condone using Thread.Sleep in a Winforms application.. Even with DoEvents, it can be problematic, and it's much simpler and more elegant (in my opinion) to implement it with a timer. – Daniel Jul 15 '12 at 19:51
  • @Daniel I solely added DoEvents and Sleep to let the visual effects actually appear in this trivial sample. The posted answers are all about the control not having time to redraw itself, but this is not actually the problem, which I tried to demonstrate. – GSerg Jul 15 '12 at 19:54
  • @GSerg My bad, I misunderstood and thought that that was the solution you were proposing. – Daniel Jul 15 '12 at 19:56
  • @GSerg: can you explain a bit better, what exactly happens "all the time"? Are you saying that setting both `Maximum` and `Value` to 10 will make `ProgressBar` show 60%? – vgru Jul 15 '12 at 20:00
  • @Groo, I believe that GSerg's problem is that at 1 and 2 the progress bar appears blank. – CC Inc Jul 15 '12 at 20:02
  • @Groo Yes, exactly. Also, when `Minimun = 0` and `Maximum = 10`, the progress bar appears completely empty when `Value = 0`, `1` or `2`. This does not happen if I switch my Windows 7 to the Classic mode or access it via remote desktop. I've suffered from this effect in my apps that involved backrogund workers associated with progress bars, but just accepted it as granted and moved on. – GSerg Jul 15 '12 at 20:03
  • @Groo But that only happens when you're using a loop, and a next value is set before the painting of the previous value is completed. If I just set `Value = Maximum` without a loop, it fully fills the bar, taking about 1.5 seconds for that. Which doesn't happen in Classics mode, where painting is synchronous. – GSerg Jul 15 '12 at 20:07
  • @Groo Indeed, the best way to understand something it to try to explain it to someone else :) I think I'll post an answer now. – GSerg Jul 15 '12 at 20:11
  • Why do people always try to point out how my questions somehow are duplicates? – CC Inc Jul 16 '12 at 01:32
  • @CCInc Don't take it personally. It is beneficial for the community to have links between questions that have exactly same underlying problem. If you seem to get that a lot, it *might* be an indication of you not using search properly, but in this particular case I just can't see how you could find that question with a search. – GSerg Jul 16 '12 at 09:38

4 Answers4

2
pBar.Maximum = 10;
int count = 0;

Timer timer = new Timer();
timer.Interval = 1000;
timer.Tick += (source, e) =>
{
    pBar.Value = count;
    if (pBar.Maximum == count)
    {
        pBar.Value = 0;
        timer.Stop();
    }
    count++;
}
timer.Start();

Your problem is that you're using a loop. You need to use a timer so that the program has time to both perform the checks/assignments and update the screen.

The code replaces the for loop with a timer that calls the body of the loop. Since a timer does not have an index variable, it is initialized outside of the timer (count) and updated with each tick.

Daniel
  • 2,944
  • 3
  • 22
  • 40
  • I doubt that OP really does absolutely nothing inside the loop. This will work, but I wouldn't say it's common to update a progress bar using a timer. – vgru Jul 15 '12 at 19:57
  • So, using this, how would I add the code from my original ForEach loop and after each interarion update the progressbar? – CC Inc Jul 15 '12 at 20:29
  • @CCInc Replace the code you have above with the code I provided. If you have anything that you would like to do in the loop, write it inside the Tick method, using count as the index variable. – Daniel Jul 15 '12 at 20:51
  • Ok, this works, however I am using a Sqlite database, and whenever I access the SqliteConnection inside of the Tick, the connection state is closed, while outside of the tick, it was open. Why is this? – CC Inc Jul 16 '12 at 01:51
  • @CCInc This is probably because the timer is called on a different thread than the connection, meaning that by the time the timer is called, the connection is already closed - is it possible for you to open the SqliteConnection inside of the timer? Also, where is the code that closes the connection? Maybe you can move it into the timer. – Daniel Jul 16 '12 at 02:08
  • @CCInc I edited my code to provide a timer.Stop() method, which should always be done - my bad for not including it originally. You could move the close connection code to the if clause. – Daniel Jul 16 '12 at 02:09
2

First: there is no any reason to assign pBar.Maximum on every interarion. Just do:

pBar.Maximum = 10;
for(int k = 0; k<11; k++)
{
   pBar.Value = k;
   if (pBar.Maximum == k)
      pBar.Value = 0;
}

Second: your code result in blocking iteration. There is no way it could ever behave correctly. Use multi-threading and change the progress value based on some event,tick whatever, not in loop, as it's done here.

Tigran
  • 61,654
  • 8
  • 86
  • 123
2

If you switch to Classic mode, this glitch will be gone. The progress bar will appear fully drawn before being reset.

This is because in Classic mode, the painting operation is synchronous and completes before the Value setter returns, but in the themed mode, there is some sort of animation played when you increase the value, and that takes some time to play.

On contrary, when you decrease the value, there is no animation; the progress bar is shrinked immediately.

This is why it appears only about 60% full: you decrease the value (which completes immediately) before the progress bar has time to draw the animation for the last several increments.

GSerg
  • 76,472
  • 17
  • 159
  • 346
1

I finally found a solution to this problem, and wrote about it here. The idea was from THIS SO question.

     progressBar1.Value = e.ProgressPercentage;
     if (e.ProgressPercentage != 0)
         progressBar1.Value = e.ProgressPercentage - 1;
     progressBar1.Value = e.ProgressPercentage;
     if (progressBar1.Maximum == e.ProgressPercentage)
         progressBar1.Value = 0;
Community
  • 1
  • 1
CC Inc
  • 5,842
  • 3
  • 33
  • 64