Использование ProgressBar в качестве панели ожидания — как избежать зависаний?

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

Я использую ProgressBar (System.Windows.Forms.ProgressBar в режиме выделения) как часть этого элемента управления. Мне не нужно обновлять состояние индикатора выполнения, я просто хочу, чтобы он перемещался снова и снова, пока диаграмма не будет создана.

Сейчас я использую его по следующей схеме:
- Запустить полосу ожидания (появится ProgressBar и начнет работать)
- Вызвать методы построения графика
- Когда график будет готов, полоса ожидания будет скрыта.

Проблема в том, что некоторые методы построения диаграмм действительно требовательны к вычислительным ресурсам, и полоса ожидания в такие моменты зависает. Как избежать этих зависаний? Должен ли я использовать какой-то потоковый/фоновый рабочий? И если да, то как проще всего это сделать?

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

ИЗМЕНИТЬ

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

Но как дождаться завершения потока и не заморозить GUI?

Я попробовал, как было предложено здесь, что-то как это:

Thread t = new Thread( () => { DoSomeLongAndDemandingTask(withParameters); });
t.Start();
t.Join()

// do something that needs to be done after thread finishes
InvokeMeAfterThreadFinished();

Но это замораживает графический интерфейс. Есть ли другой способ избежать этих зависаний?


person Gacek    schedule 19.07.2010    source источник


Ответы (2)


Вы сами ответили на свой вопрос - обычно ответ заключается в переносе вычислений в фоновый поток. Существует компонент WinForms, называемый BackgroundWorker, который делает за вас большую работу:

http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx http://dotnetperls.com/backgroundworker

Обратите внимание, что вы не сможете получить доступ к компонентам пользовательского интерфейса из фонового потока, вам необходимо Control.Invoke перейти в поток пользовательского интерфейса, чтобы получить доступ к элементам управления пользовательского интерфейса. Об этом много говорят (и предлагают решения) в сети, поэтому для этого будет легко найти Google.

В качестве альтернативы, иногда фоновый поток не работает (не знаю почему), поэтому вы можете использовать Application.DoEvents() - если память не изменяет, это обрабатывает ожидающие сообщения в очереди сообщений (включая отрисовку элементов управления, обновление пользовательского интерфейса). Если вы выполняете только небольшую работу, которая вызывает дрожание, это может быть более быстрый и простой вариант, хотя и не рекомендуется слишком часто.

person Adam Houldsworth    schedule 19.07.2010
comment
Есть ли способ запустить ProgressBar в BacgroungWOrker вместо методов построения диаграмм? - person Gacek; 19.07.2010
comment
Я не думаю, что в той же форме, но ничто не мешает вам показать форму в другом потоке, используя другой Application.Run(new ProgressForm()) - хотя обычно это делается наоборот. - person Adam Houldsworth; 19.07.2010

Использование класса BackgroundWorker — самый простой способ выполнить фоновый расчет.

Однако будьте осторожны, чтобы методы построения диаграмм, которые вы используете в фоновом режиме, не обновляли пользовательский интерфейс. Все обновления самого пользовательского интерфейса должны выполняться потоком пользовательского интерфейса. Таким образом, фоновый поток должен будет «сортировать» такие вызовы пользовательского интерфейса — см. Control .Invoke для отправной точки.

person Justin Ethier    schedule 19.07.2010