2010-02-02 22 views
5

Sto utilizzando 5 oggetti BackgroundWorker in esecuzione contemporaneamente per un determinato scopo e tutti devono modificare la stessa etichetta. Come lo faccio?BackgroundWorker accesso multithread al modulo

Come si modifica il modulo da più di un thread, quindi? E come lo faccio nel caso in cui voglio cambiare una stringa pubblica?

risposta

17

Utilizzare Control.Invoke con un delegato.

Nel tuo thread in background dei lavoratori, invece di dire

label4.Text = "Hello"; 

dicono

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

Tutto all'interno della {} esegue sul filo del controllo, in modo da evitare l'eccezione.

Ciò consente di apportare modifiche arbitrarie all'interfaccia utente da un numero BackgroundWorker anziché segnalare semplicemente i progressi.

+0

ReportProgress consente inoltre di apportare modifiche arbitrarie all'interfaccia utente. –

+0

come faccio a invocarlo se sta accadendo ora a una stringa pubblica del mio modulo? – Marcelo

+0

@Henk: ReportProgress consentirà solo a BackroundWorker di inviare un singolo oggetto "UserState", che deve quindi essere interpretato dal gestore di eventi ProgressChanged per aggiornare effettivamente l'interfaccia utente. Quello che stavo cercando di dire è che con l'approccio Invoke() puoi inserire il codice per l'aggiornamento proprio all'interno del metodo in cui crei in primo luogo il BackgroundWorker, portando a un codice più efficiente e più leggibile. Questa è una decisione progettuale, ovviamente, con tutti i normali compromessi. – RobC

2

È possibile utilizzare il metodo ReportProgress nel proprio BackgroundWorker in cui si desidera modificare l'etichetta e scrivere il codice effettivo nel gestore di eventi ProgressChanged.

+0

il problema è che questa è un'eccezione che mostra un'etichetta, quindi non è sempre il caso in cui il metodo eseguito da Backgroundworker compie qualsiasi interazione con il modulo – Marcelo

+0

È possibile utilizzare il suggerimento di RaYell per inviare informazioni alla GUI che può quindi eseguire l'aggiornamento stesso. –

0

Dai un'occhiata a this answer. Non importa se hai uno, cinque o mille thread di lavoro (in termini di concetto).

1

Si dovrebbe essere molto cauti nel chiamare l'Invoke sincrono piuttosto che il BeginInvoke asincrono su una GUI. Presto avrai un gui non reattivo e sciatto che sembra stia lottando per dipingere se stesso, oltre al potenziale di deadlock.
Dipende dalla frequenza con cui lo si aggiorna e il thread in background deve davvero attendere che la GUi sia restituita? Sembra un problema con il tuo modello.

1

Così come Control.BeginInvoke, è possibile dare un'occhiata a SynchronizationContext.

Quando si creano i BackgroundWorkers, supponendo che si stiano creando dal thread dell'interfaccia utente, si passa in SynchronizationContext.Current ai worker. Quando i BackgroundWorkers sono pronti a richiamare qualcosa sul thread dell'interfaccia utente, chiamano il metodo Synchronization.Post sull'istanza SynchronizationContext passata al momento della creazione.

Ci sono due buoni articoli su SynchronizationContext here e here.