Muchos de nosotros aprovechamos el control DataGridView como visualizador, sin embargo además puede ser una excelente ayuda para añadir nuevas filas a nuestras estructuras de datos.
En un proceso donde la información se estructura mediante columnas y líneas, el objetivo es introducir nuevas filas con la mayor facilidad posible, es entonces cuando nos percatamos de que por defecto el DataGridView actúa de una forma un tanto inconveniente para nuestro cometido. Cada vez que pulsamos ‘enter’ ya sea en modo ‘edición’ el efecto es que nos crea una nueva fila desplazándose acto seguido a la primera celda de la misma (como en Excel), entonces nos obliga a utilizar los cursores para reubicar el ‘foco’ a la celda donde va a continuar nuestra próxima entrada. Realmente es un inconveniente, pues nos hace perder muchísimo tiempo empleándolo en pulsaciones simplemente inútiles.
Dicho esto, para poder introducir datos de izquierda a derecha tal y como estamos acostumbrados en la mayoría de situaciones en la que manejamos información, podemos recurrir a varios recursos, os proponemos ver como anulando las funciones ‘ProcessDialogKey’ ‘OnKeyDown’ y rescribiendo el código para que la pulsación de una tecla ‘enter’ sea substituida por un ‘tab’ utilizando un ‘sendkeys’, pudiendo conseguir una mejora increíble en la funcionalidad. También en una segunda propuesta os introducimos a como manejar el direccionamiento de selección de las ‘celdas’ de un DataGridView capturando las pulsaciones en el ‘PreProcessMessage’, ambas heredando la funcionalidad DataGridView y añadiendo a esta personalidad propia.
Esperamos que os sea de utilidad… solo tenéis que ¡cortar y pegar!
Pep Lluis y Rafael.
'' (c) Pep Lluis & Rafa Vargas
'' Ambos ejemplos vienen derivados de una inquietud compartida en
'' el ultimo Code Camp del Escorial en el 2006 entre Rafa Vargas y
'' Pep Lluis… no cabe duda del lema 'Comparte y Aprenderas'.
''
Public Class form1
Private WithEvents _MiDGView1 As New DgvPlus 'Mi DGV, que traduce el 'Enter' en 'Tab'
Private WithEvents _MiDGView2 As New MiDGView 'Mi DGV, que controla la posicion de la celda actual
'
' al lanzar nuestro form (en el momento de carga)
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
'
'Construir el primer DGV
_MiDGView1.Dock = DockStyle.Left 'Acoplarlo a la izquierda
_MiDGView1.ColumnCount = 4 'con cuatro columnas
_MiDGView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill 'Ajustarlo al tamaño
_MiDGView1.Columns(0).HeaderText = "Caso A" 'Etiquetar columna
Me.Controls.Add(_MiDGView1) 'Añadirlo al form
'
'Construir el segundo DGV
_MiDGView2.Dock = DockStyle.Right
_MiDGView2.ColumnCount = 4
_MiDGView2.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill
_MiDGView2.Columns(0).HeaderText = "Caso B"
Me.Controls.Add(_MiDGView2)
'
'La ventana (aspecto)
Me.Width = Me._MiDGView1.Width + Me._MiDGView2.Width + 25 'Ajustar el ancho del form
Me.Text = "Pep/Rafa DataGridView" 'Ponerle titulo
End Sub
End Class
'
' Nuestra personalizacion para MiDGView —————————————————————
'
Public Class MiDGView
Inherits DataGridView 'Heredar del DataGridView
'
'Prepocesar mensajes
Public Overrides Function PreProcessMessage(ByRef msg As System.Windows.Forms.Message) As Boolean
If msg.Msg = 257 And msg.WParam.ToInt32 = 13 Then 'Si es 'KeyDown' y 'Enter'
Dim MiCol As Integer = 0
Dim MiFil As Integer = Me.CurrentCell.RowIndex – 1
If Me.CurrentCell.ColumnIndex < Me.ColumnCount – 1 Then 'Si noSalimos del limite
MiCol = Me.CurrentCell.ColumnIndex + 1 'Siguiente columna
End If
If MiFil > -1 Then Me.CurrentCell = Me(MiCol, MiFil) 'Posicionar columna
End If
Return MyBase.PreProcessMessage(msg)
End Function
End Class
'
' Nuestra personalizacion para DGVPlus —————————————————————
'
Public Class DgvPlus
Inherits DataGridView 'Heredar del DataGridView
'
'en el 'processDialogKey'… cuando estamos en edicion
Protected Overrides Function ProcessDialogKey(ByVal keyData As System.Windows.Forms.Keys) As Boolean
If keyData = Keys.Enter Then 'Si es 'enter'
SendKeys.Send(Chr(Keys.Tab)) 'Enviar un 'Tab'
Return True 'Marcar como procesado
Else 'en caso contrario
Return MyBase.ProcessDialogKey(keyData) 'devolver KeyData
End If
End Function
'
' en 'OnKeyDown'… cuando no estamos en edicion
Protected Overrides Sub OnKeyDown(ByVal e As System.Windows.Forms.KeyEventArgs)
If e.KeyData = Keys.Enter Then 'Si es 'enter'
SendKeys.Send(Chr(Keys.Tab)) 'Enviar un 'Tab'
Else
MyBase.OnKeyDown(e) 'Devolver el KeyEventArgs
End If
End Sub
End Class
solo ejecutar elgo en el evento de enter que no salte de fila no puedo capturar su valor se desplaza ni restando uno , porque si se encuentra en la ultima fila ya no restaria uno
Hola PepLluis
Creo que para ingresar los datos de izquierda a derecha dentro de un datagridview existe una alternativa mas simple. Capturar la pulsacion de la tecla Enter, «anularla» y «reemplazarla» por un TAB; es decir, «engañar» al .NET para que interprete un Enter como un TAB.
Aqui va el codigo para un datagridviev cualquiera en el evento KeyDown
Private Sub dataGridView1_KeyDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles dataGridView1.KeyDown
If (e.KeyCode = Keys.Return) Then
‘indicar que la tecla enter ya fue procesada
e.Handled = True
‘enviar la tecla TABULADOR para que sea procesada
SendKeys.Send(«{TAB}»)
End If
End Sub
Hola Robert!
Excelente aportacion… aunque creo recordar que de esta forma el refresco del datagridview, tenia un efecto de parpadeo pues el cursor salta a la siguente linea para despues recuperar la posicion y recibir el nuevo sendkeys… aunque no me hagas mucho caso pues te hablo de memoria.
Saludos,
Pep Lluis,
Amigo quisiera haceret una consulta esta muy bueno tu ejemplo es justo lo que estaba buscando, pero que pasa cuando ya inicie la edicion en una celda es decir yua escribi cualquier tecla en una celda y pulso el enter, ahi no me salta a la sigueinte columna ocmo lo puedo soulionar….
mira Robert probe lo que pones pero no me funciona, o hay alguna propiedad por cambiar desde ya gracias lo necesito con urgencia…
Despues de revisar y tratar mucho encontre una solucion, no se si sea muy estetica, pero funciona!
Private Sub DataGridView1_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles DataGridView1.KeyDown
If e.KeyCode = Keys.Enter Then
e.SuppressKeyPress = True
SendKeys.Send(«{TAB}»)
End If
End Sub
Ademas adicionarle esto para que funcione en modo de edicion:
Private Sub DataGridView1_CellEndEdit(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DataGridView1.CellEndEdit
SendKeys.Send(«{UP}»)
SendKeys.Send(«{TAB}»)
End Sub
Creo que el código es claro, era una tontería cierto? ahora que lo vemos es una tontería pero al tratar de encontrarle solución no es tan tonto.
excelente hermano, la solucion a mis problemas que tanto andaba buscando ahora si a botar el vb6 y meterle al vb2005… millon de gracias… ahora solo em keda validar la celda en cada pulsacion ojala me salga saludos desde Ya.. muy buen aporte
Para validar… puedes utilizar algo similar a esto :
AddHandler Me.DataGridView2.CellValidating, AddressOf FormatoCelda
End Sub
‘
Private Sub FormatoCelda(ByVal sender As Object, ByVal e As DataGridViewCellValidatingEventArgs)
‘Aqui tu codigo
End If
End Sub
Saludos,
Buenos Dias
Mi pregunta es la siguiente este codigo me sirve para cambiar el valor de una celda del datagridview?.
Es decir yo tengo un DGV y cambio el valor de una celda seguidamente pulso un botón que lo que hace es recorrer el DGV y obtener los valores de la primera columna de DGV, pues cuando hago esto me muestra los valores antiguos no el valor nuevo que he introducido en la celda, por eso lo de mi pregunta este codigo modifica el valor de la celda cuando picamos un boton.
Un saludo,
Esteban
Hola Esteban,
El codigo de este ejemplo lo unico que realiza es capturar la pulsacion del enter y cambiar su comportamiento, de esa forma cuando pulsamos ‘intro’ en vez de saltar de fila, saltamos de columna.
En tu caso, provablemente ese efecto viene forzado por no actualizar los datos de la tabla o lo que tengas enlazado al DGV.
Deberias verificar o hacer un ‘update’ de esa informacion antes de volver a recorrer los valores de la primera columna.
Espero que esto te ayude,
Saludos,
Pep Lluis,
Hola
Gracias por la información, ya he solucionado el tema, he hecho un focus sobre otro objeto del form y se me actualiza el DVG.
Tambien tengo una duda que no se si podras ayudarme, resulta que el DVG se carga con los datos de un DATATABLE que le paso de otro formulario, pero cuando modifico un dato del DVG se me modifica el DATATABLE que le he pasado, tu sabrias decirme si hay alguna manera de pasar un datatable a otro formulario y modificarlo desde ese formulario sin que se modifique el datatable que le he pasado. Se lo he pasado de dos maneras por referencia y por valor pero no hay manera.
Muchas gracias por tu tiempo.
Esteban,
Disculpa mi torpeza, pero no entiendo la situacion. Si tenemos un datatable enlazado en dos DGV’s es logico que si actualizamos el origen este muestre la misma información en ambos. Si deseo tener dos origenes con diferentes contenidos, debere utilizar dos fuentes…
Supongo que no estoy entendiendo el escenario, me gustaria si ello no es molestia, me especificaras un poco mas concretamente el caso concreto. Si te parece contacta conmigo a traves de la opcion [Contact] al inicio del Blog. Creo que sera la forma mas rapida.
Saludos,
Pep Lluis,
hola soy nuevo en el foro
pero les cuento que este articulo esta
super bueno se merecen un 10 .
gracias por ser solidarios con los demas
y compartir sus conocimientos…
pelluis por favor dame una mano en una pequeña
aplicacion que deseo hacer :
quiero que cada vez que presione un boton
en su evento click en el datagridview
aparezca un campo con la fecha actual del sistema, otro campo con hora del sistema,
y otro con la fecha aumentada dos horas y media.
bueno hasta un cierto punto la aplicacion
esta muy bien pero cuando llego al dia
siguiente en el campo de solo hora me aparece la fecha y hora algo que no deseo.
2) una ultima pregunta en un datagridview los datos son tenporales cuando no estan enlazados
a un origen de datos?
es decir si en el primer debug almaceno cierta
cntidad de registros
como hago para que estos datos sigan almacenados?
desde ya muchas gracias..
En cuanto a la primera pregunta, dificil de contestar sin saber que version estas utilizando y ver una muestra del codigo que realiza esa operacion.
En cuanto a la segunda respuesta, tienes un ejemplo de como seleccionar un grupo de registros y crear un nuevo DataSet
http://msmvps.com/blogs/peplluis/archive/2009/04/02/guardar-el-resultado-de-una-vista-en-una-tabla.aspx
Espero que esto te sea util.
Pep Lluis,
Saludos muy bueno el articulo pero tengo una duda, lo estuve probando y por ejemplo tu mi datagridviewplus que en la fila que me encuentre cuando me salga de ella me mande a otra celda, por decir si yo ingreso en la celda 0 columna 0 de mi datagridview el numero 1, entonces que me salte a la fila 0 pero a la columna 6, asi como esta ahora el ejemplo que pusieron no lo hace, alguien sabe como hacerlo? la validacion que les indico lo hago en el evento CellEndEdit y mi codigo es el siguiente
if (datagridView_Plus1.Rows[e.RowIndex].Cells[0].Value.ToString() == «1»)
{
datagridView_Plus1.CurrentCell = datagridView_Plus1[6, e.RowIndex];
}
Hola Rafael,
Creo que tu pregunta se responde en el siguiente enlace :
http://msmvps.com/blogs/peplluis/archive/2008/07/22/como-puedo-posicionar-el-currentcell-de-mi-datagridview.aspx
Ya nos diras si es asi,
Pep Lluis,
Holas Pep, estuve probando el salto segun el codigo q me pasaste http://msmvps.com/blogs/peplluis/archive/2008/07/22/como-puedo-posicionar-el-currentcell-de-mi-datagridview.aspx
pero no hace el salto hacia otra columna que yo le diga por ejemplo
if (dgvPlus.Rows[e.RowIndex].Cells[«Q10.1»].Value.ToString() == «»)
{
dgvPlus.CurrentCell = dgvPlus[«Q11.1», e.RowIndex];
}
pero no se va a la columna que quiero sino a la q le sigue nomas. hay una solucion para esto, igual estoy buscando la forma de hacerlo, gracias por la respuesta.
Hola de nuevo pep,bueno la unica solucion que encontre al problema que te indico fue esta, no se si sea la mas óptima, pero la pongo por si les sirve 🙂
if (dgvPlus.Rows[e.RowIndex].Cells[«10.1»].Value == null)
{
//dgvPlus.CurrentCell = dgvPlus[«10.1», e.RowIndex];
//49 es el numero de celdas que quiero q se desplaze a la derecha
for (int i = 0; i < 49; i++) { SendKeys.Send("{TAB}"); } }
Lamento decir que no funciona este código que insertó Alvaro:
Private Sub DataGridView1_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles DataGridView1.KeyDown
If e.KeyCode = Keys.Enter Then
e.SuppressKeyPress = True
SendKeys.Send(«{TAB}»)
End If
End Sub
Private Sub DataGridView1_CellEndEdit(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DataGridView1.CellEndEdit
SendKeys.Send(«{UP}»)
SendKeys.Send(«{TAB}»)
End Sub
Cuando estás en modo edición y tratas de pasar de una columna a otra pulsando ENTER, aparece mensaje de error…
José, el código funciona correctamente.
Si fiunciona lo hay colocar en CellValueChanged que no se adicione filas hasta no terminar de editar los campos requeridos
Excelente aporte, no sabes lo mucho que me ayudo, Gracias y Saludos!