Ejecución de clase como nuevo hilo
-
03-07-2019 - |
Pregunta
Quiero comenzar un trabajo en un nuevo hilo o usar backgroundworker para hacerlo, pero no lo he hecho antes y te pregunto de qué manera debo hacerlo.
Mi programa tiene una vista de cuadrícula de datos con una lista de archivos, un archivo por fila. Quiero que el usuario pueda seleccionar una fila y luego presione " Iniciar descarga " para iniciar un trabajo en segundo plano de la descarga. Quiero recuperar los eventos del progreso de la descarga.
Tengo una clase clsDownload que maneja todo y vuelve a generar eventos, pero ¿cómo implemento el trabajo en segundo plano?
¿Debo usar System.ComponentModel.BackgroundWorker dentro de la clase o crear algún contenedor que maneje esto o usar algún otro material de subprocesamiento?
Gracias.
Editar: No entiendo cómo implementar mi descarga en el backgroundworker, cualquier pequeño ejemplo sería muy bueno. El ejemplo en msdn no me llevó lejos.
Tengo una clase de descarga que tiene una función StartDownload. ¿Debo usar el trabajador de fondo EN la clase o en la persona que llama? " sentirse estúpido "
Solución
He creado varias clases diferentes que incorporan BackgroundWorker. Lo que generalmente hago es tener un componente BackgroundWorker en el formulario que se abrirá cuando se realice el trabajo, luego paso esa instancia al constructor de mi clase de trabajo.
Así es como se vería su clase de trabajo:
Private m_bwMain As BackgroundWorker
Public Sub New(ByVal bwMain As BackgroundWorker)
m_bwMain = bwMain
'additional setup code here
End Sub
Para iniciar un trabajo, haría algo como esto en el controlador de eventos de clic de su botón Iniciar descarga:
lblStatus.Text = "Initializing ..."
bgwMain.RunWorkerAsync(someFileName)
Declaro mi clase de trabajo como miembro privado del formulario actual, y luego lo instancia en el evento BackgroundWorker.DoWork. Desde allí puede llamar a su método para descargar un archivo:
Private Sub bgwMain_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bgwMain.DoWork
m_oJobEngine = New JobEngine(CType(sender, BackgroundWorker))
m_oJobEngine.DownloadFile(CStr(e.Argument))
End Sub
Para informar el progreso al usuario, puede manejar los eventos generados por su clase en su formulario principal. Solo necesita asegurarse de que la declaración del objeto de clase de trabajo tenga la palabra clave WithEvents. Desde esos controladores puede llamar al método ReportProgress de BackgroundWorker. Desde ReportProgress puede realizar los cambios que necesite en la interfaz de usuario para indicar el progreso. Aquí hay un ejemplo:
Private Sub m_oJobEngine.DownloadProgress(ByVal bgw as Backgroundworker, ByVal bytesTransferred as Long) Handles m_oJobEngine.DownloadProgress
bgw.ReportProgress(0, bytesTransferred)
End Sub
Private Sub bgwMain_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles bgwMain.ProgressChanged
lblStatus.Text = CLng(e.UserState).ToString & " bytes transferred."
End Sub
Espero que esto ayude.
Otros consejos
Si solo va a realizar la descarga y no necesita otro procesamiento asíncrono, puede usar los métodos asíncronos de WebClient
. Aunque como ya tienes tu propia clase, probablemente no sea una solución para ti.
De lo contrario, puede usar BackgroundWorker
como usted mencionó. La página de MSDN tiene un ejemplo de cómo hacerlo.
EDITAR: El cuento es:
- Crea el
BackgroundWorker
a partir de la persona que llama; - Cuando desee iniciar el trabajo en segundo plano, llame a
BackgroundWorker.RunWorkerAsync
; - en el controlador de eventos
DoWork
usted hace el trabajo de fondo, en su caso, inicie su clase de descarga; - mientras realiza el trabajo en segundo plano, debe verificar de vez en cuando el
CancelationPending
; - cuando desee informar de algún progreso, debe calcularlo en porcentaje y llamar a
ReportProgress
.
Y si necesita algo realmente personalizado, siempre puede crear su propio Tema
.
Personalmente me quedaría con BackgroundWorker
. Tiene un buen conjunto de notificaciones para varias etapas del trabajo. Si utiliza Thread
, tendrá que implementarlos usted mismo.
También me aseguraría de que el código no cree demasiadas instancias. Desea limitar el número de descargas precisas y poner en cola cualquier cosa que supere ese número.
Recomiendo encarecidamente a BackgroundWorker
si necesita proporcionar comentarios al usuario sobre la interfaz de usuario. Los eventos ProgressChanged
y RunWorkerCompleted
se ejecutan en el subproceso de la interfaz de usuario, por lo que no es necesario realizar una clasificación, lo que puede hacer que su código sea más complejo.
El trabajador de fondo parece que debería funcionar ... Hay un ejemplo en MSDN.
http://msdn.microsoft.com/en -us / library / system.componentmodel.backgroundworker.aspx
O podrías hacer algo como:
WaitCallBack workCallBack= new WaitCallBack(DownloadMethod);
if(!ThreadPool.QueueUserWorkItem(workCallBack, "ThreadPooled")
{
// Unable to Pool
}
// Work has been added to pool and will execute when possible
Depende de los parámetros que necesite para el subproceso.
La clase que usa clsDownload (probablemente su clase Form) debería usar BackgroundWorker para ejecutar el método de descarga.