Backgoundworker e cross thread

giovedì 31 luglio 2008 - 14.22

gabriel81 Profilo | Junior Member

Essesimo problema...
Il mio form è lento nel caricamento perchè carico gli item delle 6 combobox da database. Quindi per performante che sia, un po' ci va....
Infatti se commento il codice che carica le combo, il form si carica velocissimamente (però ovviamente le combo sono vuote!).

Ora ho pensato che sarebbe bello far gestire il caricamento delle combo a un backgroundworker.
Questa soluzione, permetterebbe all'applicazione di far visualizzare il form subito come se non dovesse riempire le combo, mentre il backgroundworker si occupa di riempire le combo?
Faccio questa domanda perchè ieri sera ci ho provato, però i risultati non si sono visti.
Praticamente su form.load faccio

Me.bg.RunWorkerAsync()


la routine Dowork è questa:

Private Sub bg_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bg.DoWork
If (Not (Me.DescCL1A.InvokeRequired)) Then
Me.DescCL1A.PopolaValori("SELECT * FROM VCCCL1AA", "DescCL1A", "CL1A")
Me.DescCL1A.Text = ""
Me.DescCL1B.Text = ""
Me.DescCL1B.DisplayMember = "DescCL1B"
Me.DescCL1B.ValueMember = "CL1B"
Me.DescCL2.PopolaValori("SELECT * FROM VCCCL2A", "DescCL2", "CL2")
Me.DescCL2.Text = ""
Me.DescCL3.PopolaValori("SELECT * FROM VCCCL3A", "DescCL3", "CL3")
Me.DescCL3.Text = ""
Me.DescCL4.PopolaValori("SELECT * FROM VCCCL4A", "DescCL4", "CL4")
Me.DescCL4.Text = ""
Me.DescCL5.PopolaValori("SELECT * FROM VCCCL5A", "DescCL5", "CL5")
Me.DescCL5.Text = ""
Else
Dim d As New ScriviSuListViewDelegate(AddressOf scrivisullistiview)
Me.DescCL1A.Invoke(d)
End If
Ens Sub

Il delegato è questo:
Private Delegate Sub ScriviSuListViewDelegate()

mentre il codice che esegue il delegato è:
Private Sub scrivisullistiview()
Me.DescCL1A.PopolaValori("SELECT * FROM VCCCL1AA", "DescCL1A", "CL1A")
Me.DescCL1A.Text = ""
Me.DescCL1B.Text = ""
Me.DescCL1B.DisplayMember = "DescCL1B"
Me.DescCL1B.ValueMember = "CL1B"
Me.DescCL2.PopolaValori("SELECT * FROM VCCCL2A", "DescCL2", "CL2")
Me.DescCL2.Text = ""
Me.DescCL3.PopolaValori("SELECT * FROM VCCCL3A", "DescCL3", "CL3")
Me.DescCL3.Text = ""
Me.DescCL4.PopolaValori("SELECT * FROM VCCCL4A", "DescCL4", "CL4")
Me.DescCL4.Text = ""
Me.DescCL5.PopolaValori("SELECT * FROM VCCCL5A", "DescCL5", "CL5")
Me.DescCL5.Text = ""
End Sub


So per certo che esegue il codice di scrivisullistiview() e non quello di "If (Not (Me.DescCL1A.InvokeRequired)) Then"

Il risultato è che ora è più lento di prima a partire.... sob
Qualcuno sa aiutarmi?

0v3rCl0ck Profilo | Guru

Ciao,

Con il background worker non hai bisogno di utilizzare il delegate con il check sull'InvokeRequired, perchè è stato studiato apposta per evitare quell'operazione e semplificare la vita al programmatore.

http://msdn.microsoft.com/en-us/library/hybbz6ke.aspx

Tutte le operazioni fatte sui controlli della form devono essere eseguite nell'evento RunWorkerCompleted che è associato ad un delegato creato sul thread principale.


Enojy It
- Michael -
http://blogs.dotnethell.it/Regulator/

gabriel81 Profilo | Junior Member

L'ho già letto quell articolo, insieme ad altre decine di articoli...
Prima di scivere la versione che ho postato, avevo messo il codice per popolare le combo dentro il DOwork.
Mi dava errore di cross-threading...

0v3rCl0ck Profilo | Guru

>L'ho già letto quell articolo, insieme ad altre decine di articoli...
>Prima di scivere la versione che ho postato, avevo messo il codice
>per popolare le combo dentro il DOwork.
>Mi dava errore di cross-threading...

E non puoi utilizzare l'evento RunWorkerCompleted?


- Michael -
http://blogs.dotnethell.it/Regulator/

gabriel81 Profilo | Junior Member

What?
Veramente avevo capito dal sito di msdn che RunWorkerCompleted serve a notificare la fine del lavoro in background...
Ho provato a mettere il codice sull evento RunWorkerCompleted però rallenta ugualmente il caricamento del form...........................

0v3rCl0ck Profilo | Guru

Ti ho allegato un esempio. Da quel che ho capito tu però hai una chiamata a db che restituirà dei valori, devi riuscire a salvarti questi valori in una classe, o una collezione (generic o hashtable), e utilizzare al proprietà e.Result che puoi scrivere all'interno dell'evento DoWork e leggere all'interno di RunWorkerCompleted. In questo modo avrai tutto quello che ti serve all'interno di RunWorkerCompleted per potere scrivere sui controlli senza avere nessun problema di cross thread.


- Michael -
http://blogs.dotnethell.it/Regulator/

0v3rCl0ck Profilo | Guru

>What?
>Veramente avevo capito dal sito di msdn che RunWorkerCompleted
>serve a notificare la fine del lavoro in background...
>Posso utilizzarlo ai miei scopi?

Si è la fine del lavoro, ma non solo, ha lo scopo fondamentale di potere agire sui controlli della form. Altrimenti come hai fatto tu potevi tranquillamente utilizzare un normale Thread.


- Michael -
http://blogs.dotnethell.it/Regulator/

gabriel81 Profilo | Junior Member

Io uso delle combobox automatizzate che hanno il metodo PopolaValori(ByVal Query As String, ByVal ColonnaVisualizzata As String, ByVal ColonnaChiave As String)
Questo metodo istanzia al suo interno una mia classe IterfacciaDati che repereisce i dati e li ficca nella combo.
Il codice è questo:

Public Sub PopolaValori(ByVal Query As String, ByVal ColonnaVisualizzata As String, ByVal ColonnaChiave As String)
Dim Dati As New GestioneDati.InterfacciaDb
Dati.FillDt(Query)
Me.DataSource = Dati.Dt
Me.DisplayMember = ColonnaVisualizzata
Me.ValueMember = ColonnaChiave
End Sub

Devo cambiare approccio?

0v3rCl0ck Profilo | Guru

>Io uso delle combobox automatizzate che hanno il metodo PopolaValori(ByVal
>Query As String, ByVal ColonnaVisualizzata As String, ByVal ColonnaChiave
>As String)
>Questo metodo istanzia al suo interno una mia classe IterfacciaDati
>che repereisce i dati e li ficca nella combo.
>Il codice è questo:
>
>Public Sub PopolaValori(ByVal Query As String, ByVal ColonnaVisualizzata
>As String, ByVal ColonnaChiave As String)
> Dim Dati As New GestioneDati.InterfacciaDb
> Dati.FillDt(Query)
> Me.DataSource = Dati.Dt
> Me.DisplayMember = ColonnaVisualizzata
> Me.ValueMember = ColonnaChiave
>End Sub
>
>Devo cambiare approccio?

Si, mi dispiace darti questa brutta notizia, ma a vederla così, dovresti proprio cambiare approccio. Se hai intenzione di continuare ad utilizzare una combo automatizzata, devi mettere la logica a thread all'interno del controllo stesso, per il semplice motivo che la parte dove associ al datasource il datatable dovrebbe essere fatto nel RunWorkerCompleted.

Nella tua combo potresti definire un BackgroundWorker, creare le funzioni DoWork e RunWorkerCompleted, attaccare gli eventi con l'AddHandler, insomma farei una cosa di questo tipo:

Il codice sorgente non è stato renderizzato qui
perchè non c'è sufficiente spazio.
Clicca qui per visualizzarlo in una nuova finestra

Le proprietà DisplayMember e ValueMember direi che si possono valorizzare anche prima, altrimenti puoi passare anche quelli, basta passare al RunWorkerAsync un HashTable contenente le tre variabili necessarie.


- Michael -
http://blogs.dotnethell.it/Regulator/

gabriel81 Profilo | Junior Member

Funziona!!! Sei un grande.........
Ora mi studio bene il codice che mi hai postato, perchè è comunque giusto conoscere bene cosa succede nell'applicazione!!

Grazie 1000

0v3rCl0ck Profilo | Guru

>Funziona!!! Sei un grande.........

GRAZIE

Ti ho allegato un altro esempio, lo stesso progetto di prima, dove però ho aggiunto un controllo specializzato, appunto come nel tuo caso una ComboBox. Prendilo solo come punto di partenza, perchè ovviamente ci sono mille soluzioni valide, ma la strada che ti ho messo potrebbe essere interessante.

>Ora mi studio bene il codice che mi hai postato, perchè è comunque
>giusto conoscere bene cosa succede nell'applicazione!!

Bravissimo è lo spirito giusto!

>
>Grazie 1000

Alla prox...

- Michael -
http://blogs.dotnethell.it/Regulator/
Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?

Dopo esserti registrato potrai chiedere
aiuto sul nostro Forum oppure aiutare gli altri

Consulta le Stanze disponibili.

Registrati ora !
Copyright © dotNetHell.it 2002-2024
Running on Windows Server 2008 R2 Standard, SQL Server 2012 & ASP.NET 3.5