2010-02-02 2 views
5

Я использую 5 BackgroundWorker объектов, работающих в то же время для определенной цели, и все они должны изменить одну и ту же метку. Как мне это сделать?BackgroundWorker многопоточный доступ к форме

Как мне изменить форму из более чем одного потока? И как это сделать, если я хочу изменить общедоступную строку?

ответ

17

Используйте Control.Invoke с делегатом.

В вашем фоне рабочего потока, вместо того чтобы сказать

label4.Text = "Hello"; 

говорят

label4.Invoke(new Action(() => 
{ 
    label4.Text = "Hello"; 
} 
)); 

Все внутри {} выполняется на резьбе элемента управления, поэтому во избежание исключения.

Это позволяет делать произвольные изменения в пользовательском интерфейсе от BackgroundWorker, а не просто сообщать о достигнутом прогрессе.

+0

ReportProgress также позволит вам вносить произвольные изменения в пользовательский интерфейс. –

+0

как мне его вызывать, если теперь это происходит с публичной строкой моей формы? – Marcelo

+0

@Henk: ReportProgress разрешает BackroundWorker отправлять единственный объект UserState, который затем должен интерпретироваться обработчиком события ProgressChanged для фактического обновления пользовательского интерфейса. То, что я пытался сказать, заключается в том, что с помощью метода Invoke() вы можете поместить код для обновления прямо внутри метода, в котором вы создаете BackgroundWorker, в первую очередь, что приведет к более эффективному и понятному коду. Это дизайнерское решение, конечно, со всеми нормальными компромиссами. – RobC

2

Вы можете использовать метод ReportProgress в своем BackgroundWorker, где вы хотите, чтобы метка изменилась и запишите фактический код в ProgressChanged обработчик события.

+0

проблема заключается в том, что это исключение, отображающее метку, поэтому не каждый раз, когда метод, выполняемый фоном, выполняет какое-либо взаимодействие с формой. – Marcelo

+0

. Вы можете использовать предложение RaYell для публикации информации в графическом интерфейсе, который затем может выполнить само обновление. –

0

Посмотрите на this answer. Неважно, если у вас есть один, пять или тысячи рабочих потоков (по смыслу понятия).

1

Вы должны быть очень осторожны при вызове синхронного Invoke, а не async BeginInvoke на gui. Скоро у вас будет невосприимчивый и неряшливый gui, который, похоже, изо всех сил пытается нарисовать себя, а также потенциал для тупиков.
Это зависит от того, как часто вы его обновляете - и действительно ли ваш фоновый поток должен ждать возвращения gui? Это похоже на проблему с вашей моделью.

1

Как и Control.BeginInvoke, вы можете взглянуть на SynchronizationContext.

Когда вы создаете BackgroundWorkers, предполагая, что вы создаете их из потока пользовательского интерфейса, вы проходите в SynchronizationContext.Current для рабочих. Когда BackgroundWorkers готовы вызывать что-то обратно в потоке пользовательского интерфейса, они вызывают метод Synchronization.Post экземпляра SynchronizationContext, который был передан, когда они были созданы.

Есть два хороших статьи по SynchronizationContext here и here.

Смежные вопросы