Principales respuestas
Background worker al abrir un formulario desde otro

Pregunta
-
Buenas tardes, estoy teniendo la siguiente complicación, tengo un formulario menú principal y otro formulario vehículo, estuve probando usar backgroundworker para las consultas que hago en cada form y me va bien, pero tengo problema al querer usarlo para abrir un formulario.
El formulario vehículo carga 4 combobox en el load cuando lo abro, pero quiero usar el backgroundworker para que no me tranque todo el programa mientras consulta.
En el formulario principal tengo una barra de tareas con un menu, y cuando pincho el menu de vehiculo me abre el form de vehiculo, pero al empezar a hacer las consultas mediante el backgroundworker me da el siguiente mensaje de error: Operación no valida atraves de subprocesos: se tuvo acceso al control "cbomarca" desde un subproceso distinto a aquel en el que se lo creó. Este error me lo muestra 4 veces, correspondiente a cada una de las query que hago a los 4 combobox.
Dejo el código que tengo:
NOTA: cbo son los combobox y CargaInicio es el backgroundworker
FORMULARIO VEHICULO:
Sub cargar()
Dim sql As String
Dim da As New Odbc.OdbcDataAdapter
Dim ds As New DataSet
Dim dt As New DataTable
Try
sql = "SELECT * FROM vehiculo_marca"
ConexionBD.conecta()
With comando
.Connection = Conectar
.CommandText = sql
.ExecuteNonQuery()
End With
da.SelectCommand = comando
dt = New DataTable
da.Fill(dt)
With cbomarca
.DataSource = dt
.DisplayMember = "marca"
.ValueMember = "id_vehimarc"
End With
Catch ex As Exception
MsgBox(ex.Message, MsgBoxStyle.Critical)
Finally
Conectar.Close()
End Try
Try
sql = "SELECT * FROM CATEGORIA"
ConexionBD.conecta()
With comando
.Connection = Conectar
.CommandText = sql
.ExecuteNonQuery()
End With
da.SelectCommand = comando
dt = New DataTable
da.Fill(dt)
With cboidcategoria
.DataSource = dt
.DisplayMember = "cat_nombre"
.ValueMember = "id_categoria"
End With
Catch ex As Exception
MsgBox(ex.Message, MsgBoxStyle.Critical)
Finally
Conectar.Close()
End Try
Try
sql = "SELECT * FROM SUCURSAL"
ConexionBD.conecta()
With comando
.Connection = Conectar
.CommandText = sql
.ExecuteNonQuery()
End With
da.SelectCommand = comando
dt = New DataTable
da.Fill(dt)
With cbosucursal
.DataSource = dt
.DisplayMember = "suc_nombre"
.ValueMember = "id_sucursal"
End With
Catch ex As Exception
MsgBox(ex.Message, MsgBoxStyle.Critical)
Finally
Conectar.Close()
End Try
Try
sql = "SELECT * FROM vehiculo_modelo"
ConexionBD.conecta()
With comando
.Connection = Conectar
.CommandText = sql
.ExecuteNonQuery()
End With
da.SelectCommand = comando
dt = New DataTable
da.Fill(dt)
With cbomodelo
.DataSource = dt
.DisplayMember = "modelo"
.ValueMember = "id_vehimod"
End With
Catch ex As Exception
MsgBox(ex.Message, MsgBoxStyle.Critical)
Finally
Conectar.Close()
End Try
End Sub
Private Sub CargaInicio_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles CargaInicio.DoWork
Call cargar()
piccargando.Visible = True
End Sub
Private Sub CargaInicio_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles CargaInicio.RunWorkerCompleted
piccargando.Visible = False
End Sub
FORMULARIO MENU PRINCIPAL:
Private Sub nuevovehiculo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tlsinuevovehiculo.Click
frmnuevovehiculo.MdiParent = Me
frmnuevovehiculo.Show()
frmnuevovehiculo.CargaInicio.RunWorkerAsync()
frmnuevovehiculo.BringToFront()
End Sub
- Cambiado Enrique M. Montejo miércoles, 27 de septiembre de 2017 8:52 Pregunta relacionada con controles de Windows Forms.
Respuestas
-
El problema es que el DoWork del backgroundworker se ejecuta en un hilo distinto, pero los formularios Windows son mono-hilo; su contenido solo se puede modificar desde el hilo que los creó. Esto implica que desde el DoWork de un BackGround worker no se puede pintar nada en pantalla, por ejemplo, no puedes meter items en los combos ni hacer visible un picturebox. Para resolver esto, el backgroundworker tiene el evento RunWorkerCompleted, que se dispara en el hilo principal y sí que puede modificar la pantalla. Entonces lo que hay que hacer es que en el DoWork se ejecutan las Select y se dejan los resultados en variables (tales como por ejemplo datasets), y esos datasets NO se conectan a los combos. Y luego, en el RinWorkerCompleted, se toman los datasets y se conectan a los combos (y se hacen cualesquiera otras operaciones como cambiar la visibilidad de un picturebox).
- Marcado como respuesta Enrique M. Montejo miércoles, 27 de septiembre de 2017 8:50
Todas las respuestas
-
El problema es que el DoWork del backgroundworker se ejecuta en un hilo distinto, pero los formularios Windows son mono-hilo; su contenido solo se puede modificar desde el hilo que los creó. Esto implica que desde el DoWork de un BackGround worker no se puede pintar nada en pantalla, por ejemplo, no puedes meter items en los combos ni hacer visible un picturebox. Para resolver esto, el backgroundworker tiene el evento RunWorkerCompleted, que se dispara en el hilo principal y sí que puede modificar la pantalla. Entonces lo que hay que hacer es que en el DoWork se ejecutan las Select y se dejan los resultados en variables (tales como por ejemplo datasets), y esos datasets NO se conectan a los combos. Y luego, en el RinWorkerCompleted, se toman los datasets y se conectan a los combos (y se hacen cualesquiera otras operaciones como cambiar la visibilidad de un picturebox).
- Marcado como respuesta Enrique M. Montejo miércoles, 27 de septiembre de 2017 8:50
-
-
El problema es que el DoWork del backgroundworker se ejecuta en un hilo distinto, pero los formularios Windows son mono-hilo; su contenido solo se puede modificar desde el hilo que los creó. Esto implica que desde el DoWork de un BackGround worker no se puede pintar nada en pantalla, por ejemplo, no puedes meter items en los combos ni hacer visible un picturebox. Para resolver esto, el backgroundworker tiene el evento RunWorkerCompleted, que se dispara en el hilo principal y sí que puede modificar la pantalla. Entonces lo que hay que hacer es que en el DoWork se ejecutan las Select y se dejan los resultados en variables (tales como por ejemplo datasets), y esos datasets NO se conectan a los combos. Y luego, en el RinWorkerCompleted, se toman los datasets y se conectan a los combos (y se hacen cualesquiera otras operaciones como cambiar la visibilidad de un picturebox).
Probé tu solución, pero no me estaría funcionando del todo bien me parece.
Logre hacerlo tal cual lo dijiste, pero en el backgroundcomplete cuando relleno los combos o lo que sea, se cuelga el hilo principal del programa, la consulta si me la hace en background, pero al llenar los combos u otro contenedor se cuelga unos segundos hasta rellenarlos
-
La idea es que normalmente lo que es lento es la ejecución de la consulta contra base de datos, mientras que la carga de esos datos en los combos solo debería durar unas milésimas de segundo. No tiene remedio el que el formulario se congele durante esas milésimas de segundo; esta carga necesariamente tiene que hacerse desde el hilo principal. Si en lugar de unas milésimas de segundo está tardando varios segundos, algo falla. O bien se está haciendo alguna operación superflua que no debería hacerse en ese momento, o bien se están cargando muchos miles de registros, en cuyo caso es un error utilizar un combo, que no está pensado para manejar grandes cantidades de datos.
- Propuesto como respuesta Juan Mondragón martes, 26 de septiembre de 2017 21:31