Introducción
El objetivo del articulo es demostrar algunos problemas que pueden surgir cuando se necesita que el ComboBox ubicado en las celdas del DataGridView, varíe su contenido de acuerdo al registro que se visualiza.
Para demostrar el problema, se ha definido un dominio del ejemplo intentara cargar una grilla de sucursales, de los cuales mostraran el listado de los teléfonos disponibles.
Por supuesto para cada sucursal los teléfonos disponibles varían, por lo tanto definir el contenido del combo como una única lista no es posible.
Carga del contenido variable en ComboBox
En el evento Load del formulario se procede a la carga de las sucursales, e inmediatamente después de esta operación se invoca a un método creado con el fin de la carga de los combos de cada registro de a grilla.
Este método recorre en un ciclo cada registro, toma el id de la sucursal que se encuentra en la celda del registro actual, y también toma la celda que representa el combo.
Con las anteriores dos selecciones procede a realizar una consulta a los datos y cargar en el combo los teléfonos de esa sucursal.
private void frmSucursales_Load(object sender, EventArgs e) { SucursalesEntities sucursalesContext = new SucursalesEntities(); dgvScursales.AutoGenerateColumns=false; dgvScursales.DataSource = sucursalesContext.Sucursales; // // Luego de bindear la grilla, cargo el contenido de cada fila // en el combo de telefonos para cada sucursal // LoadGrillaComboBoxTelefonos(); } private void LoadGrillaComboBoxTelefonos() { foreach (DataGridViewRow row in dgvScursales.Rows) { int idSucursal = Convert.ToInt32(row.Cells["IdSucursal"].Value); DataGridViewComboBoxCell comboboxCell = row.Cells["Telefonos"] as DataGridViewComboBoxCell; SucursalesEntities sucursalesContext = new SucursalesEntities(); comboboxCell.DataSource = sucursalesContext.Telefonos.Where(x => x.IdSucursal == idSucursal); comboboxCell.ValueMember = "Id"; comboboxCell.DisplayMember = "Numero"; } }
Algunos Comentarios
Durante la realización del ejemplo se realizaron varias pruebas, con algunos eventos que se adaptaran a la situación y evitaran tener que recorrer en un “foreach” cada registro del DataGridView.
Después de investigar un poco los únicos dos eventos que se adaptarían a este caso serian el RowsAdded y el CellFormatting, pero ambos trajeron problemas, lo que impidió su uso.
El CellFormatting, tiene como problema que se ejecuta contantemente, ya que es lanzado al redibujar la celda, y como esta operación requiere la consulta a los datos, generaba un efecto de bloqueo en la pantalla, el cual no es deseado.
El RowsAdded, si bien se ejecuta por cada fila agregada en la operación de bindeo de los datos, no había forma interna en el evento de detectar que fila se estaba agregando, ya que el argumento del evento e.RowIndex o e.RowCount, no devuelven un valor correcto.
Como conclusión se dejo de lado los eventos y se hizo uso del “foreach”, implementado esto en un método, cuya utilización se realiza luego que se bindearon los datos en el control.
[C#]
|
[VB.NET]
|
Hola Sr. Leandro, lo hice de esta forma, en el foro de msdn publique el error que tengo ahora y de la forma que estoy intentando.
ResponderEliminarhola kalith
ResponderEliminarCreo haberte contestado en el foro, pero no pude encontrar el link al mensaje, asi quedaba relacionada la consulta.
Igualmente espero haber contestado tu consulta.
saludos
pues aún tengo otra duda este es el link, de igual manera muchisimas gracias por tomar tiempo y ayudarme :)
ResponderEliminarhttp://social.msdn.microsoft.com/Forums/es-ES/vcses/thread/148f3eae-9c39-4f68-aa14-87f10efeb1b6/#f4597784-3619-4db9-be8c-5e471e737b55
ResponderEliminardisculpe lo que pasa es q tengo un codigo de esta forma pero no me actualiza el columncombobox pero he visto q en debbuging si que pasa?
ResponderEliminarFor Each r As DataGridViewRow In Me.DataGridView1.Rows
Dim id_pregunta As Integer = Convert.ToInt32(r.Cells("Id").Value)
Dim comboboxCell As DataGridViewComboBoxCell = CType(r.Cells("Respuestas"), DataGridViewComboBoxCell)
objPregunta.Id = 10 'row.Cells("Id").Value
objPregunta.TipoPregunta = 1 'row.Cells("TipoPregunta").Value
comboboxCell.DataSource = objPregunta.Todas_quest_ansert_x_Id
comboboxCell.ValueMember = "RespuestaCerrada"
comboboxCell.DisplayMember = "RespuestaCerrada"
Next
por su atencion gracias
hola backspeed
ResponderEliminarporque no defines algo como esto
For Each r As DataGridViewRow In Me.DataGridView1.Rows
Dim id_pregunta As Integer = Convert.ToInt32(r.Cells("Id").Value)
Dim tipo As Integer = Convert.ToInt32(row.Cells("TipoPregunta").Value)
Dim comboboxCell As DataGridViewComboBoxCell = CType(r.Cells("Respuestas"), DataGridViewComboBoxCell)
comboboxCell.DataSource = Pregunta.Todas_quest_ansert_x_Id(id_pregunta, tipo)
comboboxCell.ValueMember = "RespuestaCerrada"
comboboxCell.DisplayMember = "RespuestaCerrada"
Next
O sea que el metodo Todas_quest_ansert_x_Id() reciba por parametro los filtos que aplicara para obteenr los items que se cargaran en el combo
Ademas no necesitas crear una instancia define ese metodo como Shared asi puedes accederlo desde la clase
saludos
Hola Sr. Leandro Antes que nada lo Felicito por su blog me ha sido de mucha ayuda para mi proyecto de la Universidad, y bueno, queria saber si me podia ayudar con una cuestio lo que pasa es que quiero llenar un comboboxcolumn de forma variante dependiendo de la fila pero el caso es que no es desde base de datos sino es para cantidad de productos en una factura ya que cada producto debe llegar a un limite de venta segun la cantidad que aya en stock de antemano le agradezco y le deseo muchos éxitos Att. Jhonsson Córdova
ResponderEliminarhola Jhonsson Cordova
ResponderEliminardices que no es una base de datos, pero el stock del producto como lo determinas ?
o sea si es algo referente a ventas y el negocio, mas que nada cuando tiene que ver con el stock, a veces plantear restricciones de este tipo son complejas, porque no dejas que la persona que hace el pedido escriba el nuemro y al momento de confirmar la transaccion aplcias las validaciones, y en caso de alguna no pasar muestras los mensajes de problemas todos juntos para ser corregidos
los sistemas de invetario no limitan tanto el input sino que aplican als validacion al confirmar
saludos
Gracias por la acotacion, ya habia pensado igual la verdad que resulto muy complejo lo que deseaba hacer pero quedo bien con un textboxcolumn y con las validaciones pertinentes se obtiene un muy buen funcional formulario gracias por la ayuda le agradezco
ResponderEliminarhola Leandro, gracias por la ayuda. trate de implementar lo que has propuesto, pero sigo teniendo el mismo problema que te comente anteriormente: al realizar el filtrado en el combo para un concepto en particular, este filtrado me toma para todos los combos.
ResponderEliminarconsultas utilizadas en ambos procedimientos son:
Dim consulta1 As String = "SELECT valoracion FROM VALORES_CRITERIO_PERITAJE where borrado_logico=0"
Dim consulta2 As String = "SELECT Id_estado_mctp,descripcion FROM MOTOR_CAJA_TRANS_POTE where borrado_logico=0"
La carga de la grilla seria asi:
Sub SubCargarconceptos()
Dim VAR As String = ""
Dim conceptosss As conceptos
Dim lectura As Data.SqlClient.SqlDataReader
'conex.ConnectionString = NombreConexion
Abrir()
comandos.Connection = conex
comandos.CommandType = CommandType.Text
comandos.Parameters.Clear()
comandos.CommandText = consulta2
lectura = comandos.ExecuteReader
cmbvaloracion.Items.Clear()
While lectura.Read()
conceptosss.id = CInt(lectura.Item("Id_estado_mctp"))
conceptosss.conc = CStr(lectura.Item("descripcion"))
array_conceptos.Add(conceptosss)
End While
lectura.Close()
Cerrar()
dgvperitaje.Rows.Add(array_conceptos.Count)
Dim concp_valo As conceptos
For i As Integer = 0 To array_conceptos.Count - 1
concp_valo = array_conceptos(i)
dgvperitaje.Rows(i).Cells(0).Value = concp_valo.id
dgvperitaje.Rows(i).Cells(1).Value = concp_valo.conc
'SubCargarValoracion(concp_valo.id)
Next
end sub
La carga de mi combobox segun el concepto seria asi:
Sub SubCargarValoracion(ByVal id_concep As Integer)
Abrir()
Dim da As New SqlClient.SqlDataAdapter("SELECT V.id_valoracion, V.valoracion FROM MOTOR_CAJA_TRANS_POTE M INNER JOIN DETALLE_MOTOR_VALORES D ON M.Id_estado_mctp = D.Id_estado_mctp INNER JOIN VALORES_CRITERIO_PERITAJE V ON D.id_valoracion = V.id_valoracion WHERE D.Id_estado_mctp =" + CStr(id_concep), conex)
Dim ds As New DataSet
da.Fill(ds)
cmbvaloracion.DataSource = ds.Tables(0)
cmbvaloracion.DisplayMember = "valoracion"
cmbvaloracion.ValueMember = "id_valoracion"
Cerrar()
End Sub
Private Sub LoadGrillaCombovaloracion()
For Each row As DataGridViewRow In dgvperitaje.Rows
Dim mctp As Integer = Convert.ToInt32(row.Cells("id").Value)
Dim comboboxCell As DataGridViewComboBoxCell = TryCast(row.Cells("cmbvaloracion"), DataGridViewComboBoxCell)
'Dim sucursalesContext As New SucursalesEntities()
SubCargarValoracion(mctp)
Next
End Sub
En el load del form yo llamo al cargar conceptos y luego llamo al LoadGrillaCombovaloracion. Espero que me puedas ayudar. Gracias.
Como puedo enviarte una imagen de mi pantalla para que puedas visualizar bien el problema?
ResponderEliminarLeandro aca te paso una imagen: http://img843.imageshack.us/img843/9128/pantallaperitaje.jpg
ResponderEliminarEl concepto Ruidos.. tiene como valoracion "SI" y "NO". Pero como veras todos los combos se setean con BUENO-MALO-REGULAR.
hola Piloni
ResponderEliminarpero si ese concepto deberia tener las opcioens si-no en el combo podrias cargarlas detectando que concepto se esta editando, tomarias la fila detectando la celda de valoracio y cargando las opciones que necesitas para ese registro
esto lo menciono en el articulo como lograrlo a la celda si la detectas puede asignrle la info que necesites
saludos
Tengo un problema tengo un datagridview con N colunas ya tengo una columna con comboboxcolum cargado con una base de datos, ahora lo que se requiere es usar otras 2 columnas con comboboxcolum de igual manera llenada con bases de datos eso ya lo tengo pero lo que no tengo es que cuando seleccione en cualquier columna se ejecuta una consulta y que en las columnas de comobobox me despliegue el texto como una columna de textbox, no se como hacerlo en la cosulta yo agrego el item a las columnas comobobox pero esta mal porque ya con elelmanto tambien me deberia hacer consultas de lamisma manera perono lo hace
ResponderEliminarhola jose
ResponderEliminarno se si entendi del todo el planteo, pero si podria recomendarte que si vas a realizar edicion compleja en un grid no tomes ese camino, el datagridview no es un control que este prepatado para por ejemplo relacionar combos en uan linea, si es eso lo que buscas
es conveniente seelccionar la row y editar por fuera en controles simples del formulario
quiza hace tiempo relaiconar combos en cascada en la row del grid y no pude lograrlo
saludos
este es un wjwmplo wur encontre en internet
ResponderEliminarDataGridViewComboBoxColumn cmb = new DataGridViewComboBoxColumn ();
cmb.HeaderText = "Seleccionar datos";
cmb.Name = "CMB";
cmb.MaxDropDownItems = 4;
cmb.Items.Add ("True");
cmb.Items.Add ("Falso");
dataGridView1.Columns.Add (cmb);
DataGridViewComboBoxColumn cmb2 = new DataGridViewComboBoxColumn();
cmb2.HeaderText = "Seleccionar datos";
cmb2.Name = "CMB";
cmb2.MaxDropDownItems = 4;
cmb2.Items.Add("True");
cmb2.Items.Add("Falso");
dataGridView1.Columns.Add(cmb2);
DataGridViewComboBoxColumn cmb3 = new DataGridViewComboBoxColumn();
cmb3.HeaderText = "Seleccionar datos";
cmb3.Name = "CMB";
cmb3.MaxDropDownItems = 4;
cmb3.Items.Add("True");
cmb3.Items.Add("Falso");
dataGridView1.Columns.Add(cmb3);
es lago asi pero con conexion a base de datos es una misma tabla
en estos ejemplos son 3 comobobox los tres debe de consultar de 3 diferentes maneras pero el resultado siempre ba ser el mismo misma tabla mismos resultados si por ejemlo
fila = new String [] {"2", "producto 2", "2000"};
dataGridView1.Rows.Add (fila);
fila = new String [] {"3", "Producto 3", "3000"};
dataGridView1.Rows.Add (fila);
fila = new String [] {"4", "Producto 4", "4000"};
cuando yo aga una conuslta en cada combobox me deneria desplegar estos resultados pero tambien me deberia hacer consultas nuevamente por dichos pero no me queda
hola jose
ResponderEliminarla verdad no se si entendi el planteo
porque alli veo 3 columnas de tipo combo del grid
pero la forma en que asignas lo valores no es correcta, para que la seleccion funcione debes asignar el Datasource de la columna del combo y no el Items.Add() porque despues cuando pones un valo no sabe cual seleccionar
ademas cuando haces el Rows.Add() no veo que alli asignes ningun valor que sea true o false para que seleccione del combo
saludos
por alguna razon siempre que comento en tu block alguna duda, termio resolviendola gracias por contestar
ResponderEliminarHola muy Buenas. Estimado Leandro me gustaria saber como pagino una consulta sql la cual tiene más de 20 millones de datos, o como hacer enmascaramientoa una base de datos usando windows form C#.
ResponderEliminarGracias te agradesco la ayuda.
hola
ResponderEliminarpero de los 20 millones siempre vas a traer todos los registros, no aplicas filtros de busqueda, quizas por rango de fecha o algun otro campo para redicir la cantidad de informacion
por lo general cuando se trata ese volumen de datos se suele proporcionar filtros que permita trabjar mejor la informacion
es mas tambien se emepiza a pensar en usar algun Datawerehouse para realizar mineria de datos y poder extraer informacion de ese volumen de registros
saludos
Eso de la mineria lo estava viendo, pero la cuestion es que estoy desarrollando enmascaramiento de datos a una DB pero como es gran tamaño de datos el for y el foreach se me rebientan ya que tengo que recorrer una tabla con ciertas condiciones y aun así son demasiados datos para compararlos y realizar el enmascaramiento, y lo que se me viene a la cabeza es paginado en un formulario para que no se me caiga el winform aqui es donde estoy atascado. si tienes un ejemplo sencillo de paginar la consulta en windows form de forma sencilla y facil de enterder te agradeceria mucho. Danke Shönn ;)
ResponderEliminarhola
ResponderEliminarpodrias paginar en la base de datos
http://social.msdn.microsoft.com/Forums/es/vbes/thread/058fd915-7e48-4dd5-aab1-7b04b86d41a1
http://social.msdn.microsoft.com/Forums/es/vcses/thread/f3ab62c7-1824-44f7-a4ab-c0837333793d
saludos
Doy click a boton de Imprimir Etiqueta para que me mande la forma donde esta el crystalreportviewer1 y al cargarme la pantalla de la impresion me pide accesar id inicio de seion y contrasela para conexion a base de datos pero mi etiquetasset.xsd no esta enlazado a mi BD.
ResponderEliminarhola Erick
ResponderEliminarde casualidad el reporte en algun momento lo coenctaste directo a la db, pero depsues cambiaste a sataset ? lo pregunto proque quizas aun quedo conectado por eso solicuta la informacion de login cuando lo lanzas desde codigo
valida ademas que desde codigo asignas el datasource de forma correcta
saludos
Leandro!!! Un millón de gracias desde Colombia.
ResponderEliminar