2016-03-27 26 views
5

Sto creando un'applicazione Windows Form che crea dinamicamente controlli basati su dati estratti da un database.VB/C# .net Aggiunge dinamicamente elementi di controllo con Background Worker

Ho il codice ottimo in background che carica i dati dal database e lo applica alle variabili, il problema che sto riscontrando è quando provo a creare i controlli usando questi dati, ottengo un errore multi-threading (Ulteriori informazioni: operazione cross-thread non valida:. controllo 'flowpanelMenuRules' si accede da un thread diverso dal thread è stato creato su)

sto usando l'evento BackgroundWorker_DoWork e il codice che non riesce è la seguente:

Me.flowpanelMenuRules.Controls.Add(PanelRule(i)) 

Il codice precedente è un semplice ciclo che passa attraverso la variabile (che è pulle d dal database) e la raccolta delle informazioni.

Qualcuno ha avuto esperienza nell'invocare in modo sicuro la suddetta linea? Io proprio non riesco a farlo funzionare a tutti :(

Grazie per l'aiuto, posso postare più di codice, se necessario.

+0

Vedere https://stackoverflow.com/questions/142003/cross-thread-operation-not-valid-control-accessed-from-a-thread-other-than-the?rq=1 per chiarimenti su cosa è andato storto. –

+0

I controlli non devono essere creati su un thread in background. Vengono assegnati al thread in cui sono creati e dovrebbero essere utilizzati solo lì. Dovresti invocare la creazione e l'aggiornamento specifici dei controlli, il resto può essere fatto nella BGW. –

risposta

6

La mia raccomandazione è di avere il BackgroundWorker semplicemente creare i controlli, ma non li aggiungere al modulo. Invece, restituire i comandi preparati al thread di chiamata/dell'interfaccia utente tramite l'evento RunWorkerCompleted. Quindi aggiungi i controlli al modulo a questo punto, eventualmente in combinazione con i metodi SuspendLayout()/ResumeLayout().

+1

Joel - Ho usato questa idea e funziona perfettamente. Il worker in background ora esegue il mio codice SQL per estrarre le informazioni dal database nelle variabili e quindi utilizzare l'evento Background Worker Completed per compilare i risultati in FlowLayoutPanel. Grazie! Ho già utilizzato i Background Workers ma per qualche motivo l'evento Completed mi è sfuggito di mente –

1

Il modo nativo per applicazioni WinForms è quello di utilizzare metodi come System.Winfows.Forms.ControlInvoke() e InvokeRequired proprietà per l'accesso ai thread dell'interfaccia utente:

if(this.flowpanelMenuRules.InvokeRequired) 
{ 
    this.flowpanelMenuRules.Invoke(() => AddPanelRule()); 
} 
else 
{ 
    AddPanelRule(); 
} 

È inoltre possibile utilizzare Dispatcher classe

Se si è sicuri di essere su un thread dell'interfaccia utente (ad esempio in un gestore di button.Click),.fornisce il dispatcher del thread dell'interfaccia utente che è possibile utilizzare in seguito per inviare dai thread in background al thread dell'interfaccia utente come al solito.

Dispatcher.CurrentDispatcher.Invoke(() => this.flowpanelMenuRules.Controls.Add(PanelRule(i))); 
+0

Stai forse mixando VB e C#? – Camo

+0

@Rinecamo la domanda è stata posta con il tag C# e tutti i miei esempi contengono solo codice C#. –

+0

'Me' è il VB equivalente a' this';) – Camo