DataGridView… Quiero saltar de de Columna!!! no de fila

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

22 pensamientos en “DataGridView… Quiero saltar de de Columna!!! no de fila”

  1. 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

  2. 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

  3. 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,

  4. 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….

  5. 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.

  6. 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

  7. 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,

  8. 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

  9. 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,

  10. 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.

  11. 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,

  12. 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..

  13. 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];
    }

  14. 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.

  15. 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}"); } }

  16. 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…

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *