Sto modificando un modulo di Windows per consentire il caricamento dei dati in background mentre l'interfaccia utente rimane reattiva. I dati richiedono tempi notevoli per il recupero e il binding. Idealmente, farei entrambe le cose in background, ma c'è qualche ambiguità su quale tipo di aggiornamenti UI dovrei fare in background (come al di fuori del thread principale). Un solido esempio che mostra il recupero dei dati e l'associazione dei dati in background sarebbe molto utile.WinForms reattività dell'interfaccia utente quando si tratta di dati "pesanti"
risposta
Il recupero può, e deve, essere spinto fuori ad un thread in background - ma c'è alcuni modelli a mettere tutto a posto.
Fondamentalmente si avvia un thread in background per recuperare i dati, una volta terminato, sarà necessario unire nuovamente il thread dell'interfaccia utente per eseguire gli aggiornamenti dell'interfaccia utente effettivi (gli aggiornamenti dell'interfaccia tra thread sono negativi).
Ci sono tre modi di base di sfondo filettatura per esplorare
- il più facile/più limitata (e stravagante IMO) è la componente BackgroundWorker
- utilizzando i delegati e) Metodi di loro BeginInvoke()/EndInvoke (fornire un buon equilibrio di facilità e flessibilità (e utilizzare ThreadPool discussioni)
- utilizzando oggetti della discussione prime offre il massimo controllo, ma sono più lenti per l'installazione di ThreadPool discussioni
Personalmente mi chino verso l'opzione Delegati; sono abbastanza facili da lavorare quando si ottiene il modello. The BackgroundWorker sembra bello in primo piano, ma ha alcuni trucchi e tubature mancanti che rendono più complicato lavorare con quanto ci si aspetterebbe. Lasciatemi fare un breve esempio dell'approccio Delegato; Io aggiornerò prossimamente ...
modificare
Ecco un po 'di codice, è in VB, ma dovrebbe essere abbastanza facile da trascrivere, se sei un C# ragazzo. Hai un paio di altre opzioni su come vuoi che si comporti il thread in background, quindi qui ci sono due esempi. Il non blocco è il mio preferito, ma se lo stai inserendo nel codice esistente, il blocco potrebbe essere più facile per te.
non bloccante, il metodo di callback (GetData_Complete) sarà chiamato sul thread UI una volta che il thread in background è completa
Sub Main()
Console.WriteLine("On the main thread")
Dim dataDelegate As New GetDataCaller(AddressOf GetData)
Dim iar As IAsyncResult
' Non-blocking approach using a callback method
iar = dataDelegate.BeginInvoke(AddressOf GetData_Complete, Nothing)
End Sub
Private Delegate Sub GetData_CompleteCaller(ByVal iar As IAsyncResult)
Private Sub GetData_Complete(ByVal iar As IAsyncResult)
If InvokeRequired Then
Dim invokeDelegate As New GetData_CompleteCaller(AddressOf GetData_Complete)
Invoke(invokeDelegate, New Object() {iar})
Exit Sub
End If
' Downcast the IAsyncResult to an AsyncResult -- it's safe and provides extra methods
Dim ar As System.Runtime.Remoting.Messaging.AsyncResult = DirectCast(iar, System.Runtime.Remoting.Messaging.AsyncResult)
Dim dataDelegate As GetDataCaller = DirectCast(ar.AsyncDelegate, GetDataCaller)
Dim result As String = dataDelegate.EndInvoke(iar)
Console.WriteLine("On the main thread again, background result is: " + result)
End Sub
Private Delegate Function GetDataCaller() As String
Private Function GetData() As String
Console.WriteLine("On the background thread!")
For index As Integer = 0 To 2
Console.WriteLine("Background thread is working")
Next
Return "Yay, background thread got the data!"
End Function
Blocco Sub Main()
Console.WriteLine("On the main thread")
Dim dataDelegate As New GetDataCaller(AddressOf GetData)
Dim iar As IAsyncResult
' blocking approach; WaitOne() will block this thread from proceeding until the background thread is finished
iar = dataDelegate.BeginInvoke(Nothing, Nothing)
iar.AsyncWaitHandle.WaitOne()
Dim result As String = dataDelegate.EndInvoke(iar)
Console.WriteLine("On the main thread again, background result is: " + result)
End Sub
Private Sub GetData_Complete(ByVal iar As IAsyncResult)
' Downcast the IAsyncResult to an AsyncResult -- it's safe and provides extra methods
Dim ar As System.Runtime.Remoting.Messaging.AsyncResult = DirectCast(iar, System.Runtime.Remoting.Messaging.AsyncResult)
Dim dataDelegate As GetDataCaller = DirectCast(ar.AsyncDelegate, GetDataCaller)
Dim result As String = dataDelegate.EndInvoke(iar)
Console.WriteLine("On the main thread again, background result is: " + result)
End Sub
Private Delegate Function GetDataCaller() As String
Private Function GetData() As String
Console.WriteLine("On the background thread!")
For index As Integer = 0 To 2
Console.WriteLine("Background thread is working")
Next
Return "Yay, background thread got the data!"
End Function
Non aggiornare mai l'interfaccia utente da alcun thread in background, una volta recuperati i dati dal server richiamare il thread dell'interfaccia utente per aggiornare i controlli dell'interfaccia utente o il set di dati a cui è collegata l'interfaccia utente.
Utilizzando BackgroundWorker sarà utile in questo caso collegare solo gli eventi.
HTH
Phil'
di carico (come in "recupero dall'origine dati") potrebbe essere banale, se si utilizzano i delegati, i lavoratori di sfondo o qualsiasi altro protocollo.Ma il binding sembra complicato, perché non c'è molto controllo su cui può esercitarsi, almeno nella maggior parte dei controlli con associazione a dati: è possibile recuperare i dati in modo asincrono, ma una volta pronto come alimentarlo a una grande griglia in background? È questa la tua domanda? In tal caso, è possibile che:
- creare (o sottoclasse) il controllo della vista, fornendo interfacce per il carico asincrono;
- implementa una visualizzazione a pagine, mostrando solo N record alla volta, in modo che l'interfaccia utente non sia bloccata durante il recupero/la formattazione dei record.
Questa era la mia preoccupazione principale. Ero abbastanza sicuro che non dovevo fare cose come control.Datasource = myData; sullo sfondo, ma ci vuole del tempo per completare. Quindi ero per lo più curioso dell'estensione del lavoro che potrei giustificare mettendo in secondo piano. – ramnik