miércoles, 2 de diciembre de 2009

[DataGridView] KeyPress detectar ENTER y búsqueda

 

El objetivo del artículo es demostrar como mediante la edición de una celda se puede detectar la presión de la tecla ENTER, la cual será capturada para realizar una búsqueda con la información ingresada en la celda

Se debe aclarar que las columnas que no se requiere búsqueda deberá asignarse la propiedad readonly para evitar problemas, pues por defecto también entraran en la lógica que controla la pulsación del enter, salvo que se agregue validaciones para que no actué sobre estas celdas.

 

private void dataGridView1_CellEnter(object sender, DataGridViewCellEventArgs e)
{
    dataGridView1.BeginEdit(false);
}

private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
    DataGridViewTextBoxEditingControl dText = (DataGridViewTextBoxEditingControl)e.Control;
    dText.KeyUp -= new KeyEventHandler(text_KeyUp);
    dText.KeyUp += new KeyEventHandler(text_KeyUp);
}

void text_KeyUp(object sender, KeyEventArgs e)
{
    int rowIndex = ((System.Windows.Forms.DataGridViewTextBoxEditingControl)(sender)).EditingControlRowIndex;
    
    if (e.KeyCode == Keys.Enter)
    {
        int valueEntered = Convert.ToInt32(dataGridView1.Rows[rowIndex - 1].Cells["cuenta"].Value);

        dataGridView1.Rows[rowIndex - 1].Cells["descripcion"].Value = this.Search(valueEntered);
    }
}

Como se observa hay varios eventos asociados al DataGridView necesarios para poder controlar la pulsación del enter en las celdas.

Al editar la calda esta asocia el evento una clase de nombre DataGridViewTextBoxEditingControl, la cual representa un TextBox control asociado a una DataGridViewTextBoxCell.

Se vera además que se realiza una operación de búsqueda, en este caso para simplificar el ejemplo se realiza sobre un datatable cargado previamente, para lo cual se ha utilizado LinQ

 

 

private DataTable GetDataTable()
{
    DataTable dt = new DataTable();

    dt.Columns.Add("cuenta");
    dt.Columns.Add("descripcion");
    

    DataRow row = dt.NewRow();
    row["cuenta"] = "1001";
    row["descripcion"] = "cuenta 1001";
    dt.Rows.Add(row);

    row = dt.NewRow();
    row["cuenta"] = "1002";
    row["descripcion"] = "cuenta 1002";
    dt.Rows.Add(row);

    row = dt.NewRow();
    row["cuenta"] = "1003";
    row["descripcion"] = "cuenta 1003";
    dt.Rows.Add(row);

    return dt;


}

private string Search(int cuenta)
{
    string descripcion = (from item in this.GetDataTable().AsEnumerable()
                         where Convert.ToInt32(item["cuenta"]) == cuenta
                         select item["descripcion"].ToString()).FirstOrDefault<string>();

    return descripcion;
}

[C#]
 

28 comentarios:

  1. Buenas Leandro :D

    Me queda una duda sobre el porque al rowIndex en el handler text_KeyUp hay que restarle uno? no se supone que debería regresar un valor que se pueda usar directamente?? yo obtengo el indice de la fila con :
    dgvBusqueda.CurrentCell.RowIndex
    Lo cual básicamente es lo mismo pero he notado que si invoco esa propiedad dentro del evento EditingControlShowing si me regresa el verdadero valor del indice de la fila a diferencia del text_KeyUp que me devuelve un numero mas que el verdadero valor del indice de la fila ( si en el evento EditingControlShowing el indice es 3 en text_KeyUp es 4). Me podrías explicar a que se debe eso?

    Muchas gracias y saludos

    ResponderEliminar
  2. hola Edalo

    recuerda que al darse ese evento, al presionar enter se esta confirmando la celda que en ese momento editas y el foco pasa a la siguiente.

    pero tu no quieres la siguiente, sino que necesitas la anterior, la que estaba en edicion previo al enter, por eso es el -1
    para poder recuperar la que estaba en edicion

    o sea la presionar enter el rowindex pasa a la fila siguiente, esto no puede evitarlo, por eso le restas uno para obtener la que estaba en edicion en su momento

    bueno espero haberme explicado bien

    saludos

    ResponderEliminar
    Respuestas
    1. Me manda un error al.invocar textkeyup por los parámetros que pide el método

      Eliminar
  3. Gracias Leandro , se me había pasado ese pequeño detalle :S ,solo un par de consultas mas:
    1.¿Para que es necesaria la llamada a BeginEdit dentro del evento CellEnter? la ayuda básicamente me dice que "Pone la celda actual en modo de edición", pero no me queda muy claro cuando debo o no usarlo :( y también en notado que resulta indiferente usar true o false :S
    2.Hay alguna manera de alterar el comportamiento de la perdida de foco en la celdas, osea que al dar enter en ellas en lugar de saltar a la sgte fila salte a la sgte celda de la misma fila hasta alcanzar la ultima celda de dicha fila y solo en ese momento saltar a la siguiente fila??

    Gracias de antemano y espero no causar molestias con tanta pregunta :$

    ResponderEliminar
  4. hola Edalo

    1-
    sino recuerdo mal ese evento cambiaba a edicion la celda cuando ponias el foco o ingresabas en ella

    pero igual me entran dudas sino tenia un objetivo adicional
    no has realizado la prueba de comentar al linea del BeginEdit y ver que sucede ? de esta forma es como se aprender, se comenta y se ve que reaccion toma el codigo


    2-
    creo que te refieres a algo como esto

    http://social.msdn.microsoft.com/Forums/es-ES/vbes/thread/f84e29ef-1ceb-459f-80be-ec798858037a/


    saludos

    ResponderEliminar
  5. Disculpa :S ya había comentado la linea antes, pero solo noté que ya no se producía ningún cambio en la celda adyacente, no repare en el detalle de que al llamar a BeginEdit la celda que recibía el enfoque automáticamente entraba en modo de edición, como si se tratara de un simple textbox.

    Y el enlace que me pasaste si era lo que andaba buscando.

    De verdad muchas gracias y disculpa el inconveniente

    ResponderEliminar
  6. Hola!
    me gustaria que me pudiera ayudar
    resulta que necesito hacer una busqueda en vb.net 2008 y me la muestre en un datagridview
    estoy trabajando con sqlite
    la busqueda consiste en que me muestre varios campos de distintas tablas
    de la tabla
    authors necesito el campo de nombre
    books el campo title
    comments el campo de etiquetas
    data el campo de formats

    el caso es que solo estoy ultilizando un textbox para la busqueda

    ResponderEliminar
  7. hola Deisy

    bueno son varios puntos que mencionar, imagino usas el proveedor de ado.net para sqllite, no ?

    http://sqlite.phxsoftware.com/

    el tema de mostrarias campos de fiferentes tablas lo logras por medio del INNER JOIN en la query

    despues filtrar lo podrias usar similar a esto
    http://social.msdn.microsoft.com/Forums/es/vcses/thread/2aa0a484-3329-4061-a881-2c38b9b6545e

    solo que en tu caso usarias las clases del proveedor del primer link

    saludos

    ResponderEliminar
  8. HOLA AMIGO QUISIERA SAVER COMO HAGO PARA QUE EN MI DATAGRID SOLO ACEPTE EN UNA COLUMNA NUMEROS Y QUE SI YO PONGO UN NUMERO COMO '0' ME DA UN MSM DE ERROR O QUE ME DIGA QUE DICHO VALOR NO ES COMPATIBLE Y QUE SI ESCRIVO 0 EN ES COLUMNA ME DE ERROR Y QUE DEVUELVA COMO VALOR 1 EN LA CELDA DE LA COLUMNA DE GRID, BUENO ESPERO QUE AYUDES CON ESTO

    ResponderEliminar
  9. hola

    aqui respondo un tema similar

    http://social.msdn.microsoft.com/Forums/es/vcses/thread/e3471f65-fc4b-456e-a58a-391fa7e83471

    http://social.msdn.microsoft.com/Forums/es/vbes/thread/da04dbf6-1e4e-48bf-840e-3306cb66ea54

    saludos

    ResponderEliminar
  10. Hola, gracias por el código, pero me gustaría que me orientes como hacer esto con una tabla que esta guardada en mi bd . gracias

    ResponderEliminar
  11. hola Luis

    solo tienes que cambiar el metodo Search() alli donde use linq tu usarias un SELECT a la tabla para obtener los datos

    auqnue no se si la pregunta venia porque no conoces sobre ado.net para ejecutar ese select

    saludos

    ResponderEliminar
  12. hola leandro me ah sido de gran ayuda. tus post. pero el problema ahora es que no puedo pásarlo a vb.net ya intente con los traductores y no me funciona me marcan errores. no se si seria mucho pedir una version en vb.net??? gracias

    ResponderEliminar
  13. hola luis

    que errores estas obteniendo ?


    saludos

    ResponderEliminar
  14. hola denuevo leandro. trate de corregir en lo mas posible mi código.

    ahora me da error aqui


    Private Function Search(ByVal cuenta As Integer) As String
    Dim descripcion As String = (From item In Me.GetDataTable().AsEnumerable() Where Convert.ToInt32(item("cuenta")) = cuentaitem("descripcion").ToString()).FirstOrDefault(Of String)()

    Return descripcion
    End Function


    ===================================
    error con la variable cuentaitem no sé como declararlo o convertirlo

    gracias

    ResponderEliminar
  15. hola luis

    pero cuentaitem de donde sale ?

    no sera que tenias que usar el parametro del metodo? o sea

    Where Convert.ToInt32(item("cuenta")) = cuenta)

    saludos

    ResponderEliminar
  16. Muchísimas gracias era exactamente lo que buscaba, el primer bloque de código me ayudo.

    ResponderEliminar
  17. hola Hector

    la verdad no sabria decirte cual puede ser el problema, ni siquiera mencionas cual es el mensaje del error que se produce

    saludos

    ResponderEliminar
  18. Hola buenas tardes, solo para preguntarte si no tienes un buen manual para le manejo y manipulacion de tablas dentro de visual studio
    Espero que me puedas ayudar.
    Gracias y saludos buen dia

    ResponderEliminar
    Respuestas
    1. hola
      Por manipulacion te refieres a programar en ado.net ? o a la administracion de la db usando el Server Explorer
      La verdad es que manual no conozco pero con solo buscas ado.net hay muchisima data sobre el tema
      Tutorial: Crear una aplicación de datos sencilla mediante ADO.NET
      saludos

      Eliminar
  19. Hola buen dia.

    Como podria hacer que me busque en mi base de datos. Lo he intentado cargando los registros a una datatable pero no me funciona.

    Este es el codigo que utilice

    private DataTable GetDataTable()
    {
    DataTable dt = new DataTable();

    using (SqlConnection _Cnn =
    new SqlConnection("Data Source=.;Initial Catalog=FACTURACION;Integrated Security=True"))
    {
    _Cnn.Open();
    using (SqlDataAdapter a = new SqlDataAdapter("SELECT * FROM PRODUCTOS", _Cnn))
    {
    // DataTable dt = new DataTable();
    a.Fill(dt);
    return dt;
    }
    }
    }

    Tengo poca experiencia y agradeceria tu ayuda.

    Saludos

    ResponderEliminar
    Respuestas
    1. hola
      Pero porque no funciona? se genera algun mensaje de error
      Porque comantaste la linea de codigo donde realizas el new del DataTable? es alinea es necesaria para poder realizar el Fill()
      saludos

      Eliminar
    2. Gracias. Ya habia encontrado mi error del porque no me envia informacion. Era que no hacia la conversion de tipo string cuando comparaba el dato.

      Saludos

      Eliminar
  20. Buen dia Agradeceria tu apoyo para saber como mostrar una columna mas cuando encuentre coincidencias de la busqueda. Es decir que aparte de la columna descripcion, me muestre una columna mas como fecha o precio por asi decirlo.

    ResponderEliminar
    Respuestas
    1. hola
      Creo que deberias explicarte un poco mejor proque la verdad es que no entedi del todo el planteo
      Las columnas se definen de forma dinamica o lo haces en tiempo de diseño? porque podrias definir las columnas en diseño y asignar el DataPropertyName con el campo que se mostrara en esa columna, de esta forma podrias definir columnas adicionales
      saludos

      Eliminar
    2. Las columnas las genero en tiempo de diseño. El nombre de las columnas son Producto,Descripcion,Precio.

      Pero no se como hacer para que durante la consulta me muestre la columna precio al momento de hacer el select

      Eliminar
    3. hola
      Como es eso de "al momento de hacer el select" ?
      Si la tabla tiene una columan precio simplemente defines ese campo en el SELECT que ejecutas de sql
      Aunque la verdad sigo sin entender del todo el problema
      saludos

      Eliminar
  21. una pregunta leandro es posible imprimnir 2 datagridview dentro de un form o es mejor utilizar crystal report para eso

    ResponderEliminar