Как обновить флажки в .NET checkListBox?

Я столкнулся с проблемой, когда я хочу отобразить список элементов в checkListBox и программно отмечать их один за другим по мере завершения каждого процесса, который я отслеживаю.

Я постараюсь свести свой код к самому необходимому, чтобы каждый мог легко понять, что происходит.

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

По сути, это то, что делает мой код. Индикатор выполнения обновляется во время выполнения цикла, но все флажки не устанавливаются до тех пор, пока цикл не завершится, и все они будут отмечены одновременно.

Это явно противоречит цели отображения флажков, и мне было любопытно, есть ли что-то, что я упустил, что позволяет вам обновить элемент управления checkListBox или что-то подобное.

Прошу прощения, если этот вопрос кажется расплывчатым, похоже, у меня здесь довольно часто возникает эта проблема.


person Kyle Van Koevering    schedule 23.06.2010    source источник


Ответы (2)


Это стандартное поведение для любого приложения с графическим интерфейсом Windows, обновления экрана не происходят до тех пор, пока поток пользовательского интерфейса не станет бездействующим, чтобы Windows могла доставить событие Paint. Одна из самых худших вещей, которые вы можете сделать, — это вызвать Application.DoEvents(). Да, это доставит событие Paint. Но это также позволяет вашему пользователю закрыть форму. Это производит Big Kaboom, когда элемент управления, который вы пытаетесь обновить, внезапно исчезает. Ваш цикл все еще работает, но формы больше нет.

Вы, должно быть, заметили, что индикатор выполнения действительно обновился, а CheckedListBox — нет. Это связано с тем, что ProgressBar часто используется для отображения прогресса, когда код находится в цикле, поэтому он гарантирует, что при изменении свойства Value он немедленно отрисовывается, не дожидаясь, пока Windows сообщит ему, что его нужно перерисовать. Грязный трюк, очень запутанный.

Но вы можете воспользоваться и этим трюком, это несложно. Измените свой код следующим образом:

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

Метод Update() означает «рисовать себя, когда это необходимо». То есть вы изменили состояние проверки элемента. Никогда на вас не действует Big Kaboom, пользователь не может внезапно заставить элемент управления исчезнуть.

Если SOME_FUNCTION() занимает много времени, например, более 10 x 0,3 секунды или около того, вам следует задуматься об использовании потоков.

person Hans Passant    schedule 23.06.2010
comment
Большое спасибо за этот информативный ответ. На самом деле я только вчера добавил Application.DoEvents() в свой код, потому что это сработало. Спасибо, что рассказали мне, почему это была плохая идея и лучшая альтернатива. - person Kyle Van Koevering; 24.06.2010

Вы можете вызвать Invalidate() для элемента управления, который нужно перекрасить.

Что-то вроде этого каждый раз, когда вы обновляете галочку в списке:

checkListBoxItems.Invalidate();

Наслаждаться!

person Doug    schedule 23.06.2010