views:

21

answers:

3

I've run into a problem where I want to display a list of items in a checkListBox and programmatically check them off one by one as each process I am monitoring gets completed.

I will try to water my code down to the bare essentials so everyone can easily grasp what is happening.

for (int i = 0; i < 10; i++)
{
    SOME_FUNCTION();
    progressBar.Value++;
    checkListBoxItems.SetItemCheckState(i, CheckState.Checked);
}

This is essentially what my code is doing. The progress bar gets updated while the loop is running, but all of the check boxes do not get checked until the loop is finished and they are all checked at the same time.

This obviously defeats the purpose of displaying the check boxes and I was curious if there was something I was missing that allows you to refresh the checkListBox control, or something similar.

I apologize if this question seems vague, I seem to have that problem quite often here.

Thank you all for your time and help,

Kyle

A: 

Hi,

You can call Invalidate() on the control you need to have repainted.

So something like this every time you update a check mark in the list:

checkListBoxItems.Invalidate();

Enjoy!

Doug
A: 
for (int i = 0; i < 10; i++)
{
    SOME_FUNCTION();
    progressBar.Value++;
    checkListBoxItems.SetItemCheckState(i, CheckState.Checked);
    Application.DoEvents();
}
STO
Worked like a charm....thanks!
Kyle Van Koevering
+2  A: 

This is standard behavior for any Windows GUI application, screen updates don't happen until the UI thread goes idle so that Windows can deliver the Paint event. One of the absolute worst things you could do is calling Application.DoEvents(). Yes, that will deliver the Paint event. But it also allows your user to close the form. That produces a Big Kaboom when the control you are trying to update is suddenly not there anymore. Your loop is still running, but the form isn't there anymore.

What you must have noticed is that the progress bar actually updated but the CheckedListBox did not. That's because ProgressBar often is used to show progress when the code is in a loop, so it makes sure that when you change the Value property, it immediately paints itself without waiting for Windows to tell it that it needs to be repainted. Dirty trick, very confusing.

But you can take advantage of that trick as well, it is easy. Modify your code like this:

for (int i = 0; i < 10; i++)
{
    SOME_FUNCTION();
    progressBar.Value++;
    checkListBoxItems.SetItemCheckState(i, CheckState.Checked);
    checkListBoxItems.Update();
}

The Update() method means "paint yourself when necessary". It is, you changed the check state of an item. Never does the Big Kaboom thingy on you, the user can't suddenly make the control disappear.

If SOME_FUNCTION() takes a long time, like more than 10 x 0.3 seconds or so, then you should start thinking about using threads.

Hans Passant
Thank you very much for this informative response.I actually just put Application.DoEvents() into my code yesterday because it worked. Thank you for telling me why it was a bad idea and a better alternative.
Kyle Van Koevering