Estoy modificando un formulario de Windows para permitir que los datos se carguen en segundo plano mientras la UI sigue siendo receptiva. Los datos toman un tiempo notable tanto para recuperar como para enlazar. Idealmente, haría ambas cosas en segundo plano, pero hay cierta ambigüedad sobre qué tipo de actualizaciones de UI debería estar haciendo en segundo plano (como fuera del hilo principal). Un ejemplo sólido que muestre la recuperación de datos y el enlace de datos en el fondo sería muy útil.WinForms UI capacidad de respuesta cuando se trata de datos "pesados"
Respuesta
La recuperación puede, y debe, ser empujado hacia fuera a un subproceso de fondo - pero hay algunas pautas para poner todo en su lugar.
Básicamente, comenzará un hilo de fondo para recuperar los datos, una vez hecho, deberá fusionarse de nuevo en el hilo de la interfaz de usuario para realizar las actualizaciones de UI (las actualizaciones de UI en los hilos son malas).
Hay tres formas básicas de fondo roscado para explorar
- el más fácil/más limitada (y peculiar OMI) es el componente BackgroundWorker
- utilizando los delegados y sus BeginInvoke()/EndInvoke() métodos proporcionar un buen equilibrio de facilidad y flexibilidad (y utilizar ThreadPool Hilos)
- usando proporciona el máximo control de rosca objetos primas, pero son más lentos de instalar que ThreadPool Hilos
Personalmente me inclino hacia la opción Delegados; son bastante fáciles de trabajar una vez que obtienes el patrón. El BackgroundWorker parece agradable desde el principio, pero tiene algunas trampas y falta de plomería que hacen que trabajar sea más complicado de lo que cabría esperar. Permítanme preparar una pequeña muestra del enfoque Delegado; Voy a actualizar en breve ...
edición
Aquí hay un código, que es en VB, pero debe ser lo suficientemente fácil para transcribir si eres un chico de C#. Tienes un par de opciones más sobre cómo quieres que se comporte el hilo de fondo, así que aquí hay dos ejemplos. Mi preferido es el no bloqueo, pero si lo estás adaptando al código existente, entonces el bloqueo podría ser más fácil para ti.
sin bloqueo, el método de devolución de llamada (GetData_Complete) será llamada en el subproceso de interfaz de usuario una vez que el hilo de fondo es 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
bloqueo 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
No actualice la interfaz de usuario desde ninguna cadena de fondo, una vez que haya recuperado los datos de la invocación de su servidor al hilo de la interfaz de usuario para actualizar los controles de la UI o el conjunto de datos al que está sujeta su interfaz de usuario.
El uso de BackgroundWorker le ayudará en este caso a conectar los eventos.
HTH
Phil'
La carga (como en "recuperación desde el origen de datos") puede ser trivial, ya sea que use delegados, trabajadores en segundo plano o cualquier otro protocolo.Pero el enlace parece complicado, porque no hay mucho control que uno pueda ejercer sobre él, al menos en la mayoría de los controles vinculados a datos: puede recuperar datos de forma asincrónica, pero una vez que lo tiene listo ¿cómo alimentarlo a una grilla grande en el fondo? ¿Esa es tu pregunta? Si es así, creo que puede:
- crear (o subclase) su control de vista, que proporciona interfaces para la carga asíncrona;
- implementa una vista paginada, que muestra solo N registros a la vez, para que la IU no se bloquee mientras se recuperan/formatean registros.
- 1. Capacidad de respuesta de CLLocationManager
- 2. de error, datos de cadena o binarios se trunca cuando se trata de insertar
- 3. JQuery ajax congela ui cuando la respuesta es muy grande
- 4. repetitivo cuando se trata de muchos tipos no relacionados
- 5. Actividad de muerte cuando se trata de primer plano
- 6. Excepción SQLite hay tal columna cuando se trata de seleccionar
- 7. ¿Prefiere nombres detallados cuando se trata de columnas de bases de datos?
- 8. ¿Qué no se debe probar cuando se trata de pruebas unitarias?
- 9. problema cuando se trata de definir un operador en Prolog
- 10. error extraño cuando se trata de asignar parseInt en Clojure
- 11. APP setParameter cuando se trata de "NO EN (: param)"
- 12. ILMerge excepción cuando se trata de fusionar archivo PDB
- 13. ¿De qué se trata _GLIBCXX_USE_NANOSLEEP?
- 14. Respuesta personalizada de JQuery UI DatePicker
- 15. Winforms listbox no se actualiza cuando los cambios de datos vinculados
- 16. MATLAB: se trata de java.lang.String
- 17. MethodHandle: ¿de qué se trata?
- 18. IE8 trata la respuesta json como archivo e intenta descargarlo
- 19. Estilo de Winforms/UI Sugerencias de Look and Feel
- 20. ¿Obtienes todo el cuerpo de respuesta cuando la respuesta se fragmenta?
- 21. Respetando los temas de XP al diseñar WinForms UI
- 22. Animaciones suaves para diseños pesados
- 23. WPF MediaElement se detiene cuando se trata de reproducir archivos de Windows Media Center grabación
- 24. ¿Dónde se crean ejemplos de UI de programas geniales de forma gratuita con Winforms?
- 25. ¿Cómo puedo anular la presentación de NSError cuando se trata de enlaces?
- 26. Semántica de movimiento: ¿de qué se trata?
- 27. ¿Nunca se debe usar immediate = "true" cuando se trata de un componente AJAXified JSF 2.0?
- 28. error de archivo de clase no válida cuando se trata de paquete de la aplicación Blackberry
- 29. capacidad de "bit de datos" frente al tamaño de "bits de tara"?
- 30. Java LinkedBlockingQueue con la capacidad de señalizar cuando haya terminado?
Esta fue mi principal preocupación. Estaba bastante seguro de que no debería estar haciendo cosas como control.Datasource = myData; en segundo plano, pero lleva tiempo completarlo. Así que tenía curiosidad sobre el alcance del trabajo que podía justificar poner en segundo plano. – ramnik