jueves, 10 de diciembre de 2009

[DataGridView] Parte 1 – Valor de celda Condicional usando CellFormatting

 

El ejemplo intenta demostrar como una vez que se bindean los datos estos pueden ser acomodados en las celda según cierta condición.

En este ejemplo se toma un origen de datos con tres columnas pero solo dos serán representadas como datos en la grilla, ya que una condición indicara si debe

 

private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
    DataGridViewColumn currentColumn = dataGridView1.Columns[e.ColumnIndex];

    if (currentColumn.Name == "Fracciona")
    {
        DataGridViewRow currentRow = dataGridView1.Rows[e.RowIndex];
        DataRowView data = currentRow.DataBoundItem as DataRowView;

        if (data == null)
            return;

        if(Convert.ToBoolean(data["fracc"]))
            currentRow.Cells["tipoventa"].Value = Convert.ToString(data["FORM_VENT"]);
        else
            currentRow.Cells["tipoventa"].Value = Convert.ToString(data["PRESENTACI"]);
    
    }
}

En este caso la lógica principal se encuentra en el evento CellFormatting, pues este será el encargado de realiza la lógica necesaria para decidir que campo de los datos bindeados deben representarse en la celda.

Se podrá visualizar que un campo que si se ha enlazado a la grilla mediante la propiedad DataPropertyName pero el segunda columnas de la grilla no se le ha asignado este valor ya que será por medio de código quien decida que valor mostrar.

Una de las líneas mas importantes es la 7, ya que esta permite recuperar los datos originales que se están bindeando a esa fila en particular, y por lo tanto trabajar con ellos.

Los datos utilizados para el ejemplo son los siguiente

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

    dt.Columns.Add("fracc", typeof(bool));
    dt.Columns.Add("PRESENTACI");
    dt.Columns.Add("FORM_VENT");


    DataRow row = dt.NewRow();
    row["fracc"] = true;
    row["PRESENTACI"] = "PRESENTACI 1";
    row["FORM_VENT"] = "FORM_VENT 1";
    dt.Rows.Add(row);

    row = dt.NewRow();
    row["fracc"] = false;
    row["PRESENTACI"] = "PRESENTACI 2";
    row["FORM_VENT"] = "FORM_VENT 2";
    dt.Rows.Add(row);

    row = dt.NewRow();
    row["fracc"] = false;
    row["PRESENTACI"] = "PRESENTACI 3";
    row["FORM_VENT"] = "FORM_VENT 3";
    dt.Rows.Add(row);

    row = dt.NewRow();
    row["fracc"] = true;
    row["PRESENTACI"] = "PRESENTACI 4";
    row["FORM_VENT"] = "FORM_VENT 4";
    dt.Rows.Add(row);

    return dt;

}

esto es importante para poder conocer como se accede a la información bideada en la grilla.

Como funcionalidad adicional se permite que el usuario al marcar o desmarcar una celda esta cambie el contenido con respecto al valor que se obtuvo al momento de bindear la fila

private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{

    DataGridViewColumn currentColumn = dataGridView1.Columns[e.ColumnIndex];

    if (currentColumn.Name == "Fracciona")
    {
        DataGridViewCheckBoxCell currentCell = dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex] as DataGridViewCheckBoxCell;

        DataGridViewRow currentRow = dataGridView1.Rows[e.RowIndex];
        DataRowView data = currentRow.DataBoundItem as DataRowView;

        if (data == null)
            return;

        if (Convert.ToBoolean(currentCell.Value))
            currentRow.Cells["tipoventa"].Value = Convert.ToString(data["FORM_VENT"]);
        else
            currentRow.Cells["tipoventa"].Value = Convert.ToString(data["PRESENTACI"]);

        dataGridView1.EndEdit();
    }
}
[C#]
[VB.NET]

28 comentarios:

  1. Hola, tengo una duda, te explico mi problema, tengo 2 DGV una donde se muestran los productos... al dar doble clic en alguno se debe pasar al otro grid que sera donde se acumularan para ser facturados... es muy similar a tu ejemplo de seleccionar y con el boton mandarlos al otro grid... pero no he podido hacerlo... y quisiera pudieras apoyarme... lo agradeceria mucho has sido el mas similar a lo que necesitooo... gracias de ante mano

    ResponderEliminar
  2. hola Maggi´s

    el team es que en este ejemplo se aplica la logica sobre un solo grid, o sea es mas a nivel celda que se trabaja

    En cambio tu caso parece ser mas un maestro-detalle en dodne pulsas en el grid principla y la seelccion se sua de filtro para cargar el segundo grid

    no has probado nel evento CellClick o CellDoubleClick de tu grid maestro y en este tomar el valor de algun campo clave que represente el codigo de ese registro y usarlo como alli mismo para filtar una consulta que cargue los registros del segundo grid de detalle.

    Esta basicamente es la operacion que deberias realizar, en este momento no tengo un ejemplo que demuestree como lograrlo, pero si me das el finde veo de armar uno simple
    imagino usas los objetos de ado.net para conectarte a la db y trabajas con parametros en las consultas


    saludos

    ResponderEliminar
  3. Hola Leandro, estuve buscando en tu blog y creo que no hayo o no se si no he buscado bien (o al menos un ejemplo similar) sobre como poder seleccionar una fila de un datagrid (el cual lo lleno con un ds con datos de sql) para poder desplegar cada uno de sus campos en varios textbox? Te agradezco de antemano, slds

    ResponderEliminar
  4. hola xxx

    podria ser algo como esto

    [WinForms] Edición Empleados

    en donde desplagas la info en un forma separado para editar

    o quizas algo como esto

    http://social.msdn.microsoft.com/Forums/es/vbes/thread/4db66f80-c5b3-485f-a5bf-352fc5c33fee

    http://social.msdn.microsoft.com/Forums/es/vbes/thread/7b94898d-4152-43c7-ba3d-70c627d1ee2b

    en donde asignas la info a los controles del propio formulario, tomando directo de las celdas del grid

    saludos

    ResponderEliminar
  5. Agradecer su empeño en compartir conocimiento. Mi pregunta es la siguiente: Utilizando un TextBox y un DatagridView ¿cómo realizar una búsqueda incremental en el grid al ir tecleando en el textbox. Gracias por su apoyo.

    ResponderEliminar
  6. hola Jorge

    podria ser algo como esto

    http://social.msdn.microsoft.com/Forums/es/vbes/thread/6e2746d6-3613-4893-af8a-2aa4dde918ef

    como veras se usa el like en el select para poder buscar por aproximacion lo que se escribe, recomednaria uses un boton para lanzar esta accion, porque el keypress podria penalizar la db con tantas queries seguidas

    saludos

    ResponderEliminar
  7. Muchas gracias por tu respuesta. Ahora tengo la siguiente duda.

    En c#, como crearía un filtro en el datagridview, que lo haga de manera dinámica, a partir de un textbox y sin utilizar un dataset ya que el mismo está cargado con object collection.

    ResponderEliminar
  8. hola Jorge

    algo como esto

    Filtros Condicionales (1/2)

    analiza el metodo LoadPerson() alli se vuelca un datareade a una entidad

    saludos

    ResponderEliminar
  9. Si muchas gracias. Aprovecho para preguntarte algo que no tengo claro:
    Con este evento obtengo el valor de la celda seleccionada.
    private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
    {
    string val = this.dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value as string;
    if (val != "")
    {
    MessageBox.Show(val);
    }
    }

    Porque con este otro no.
    private void dataGridView1_CellLeave(object sender, DataGridViewCellEventArgs e)
    {
    string val = this.dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value as string;
    if (val != "")
    {
    MessageBox.Show(val);
    }

    ResponderEliminar
  10. hola Jorge

    el tema es que el CellLeave implica que la celda tiene el foco o sea la estas editando

    lo que tu haces es marcar una celda para seleccionarla y para esto hace un click en la misma, el leave se da despues que esta pierde el foco

    saludos

    ResponderEliminar
  11. Saludos don Leandro,

    Tengo un incidente programando el evento CellClick para un DatagridView.

    El problema radica en que tengo registros en el grid, y quiero mostrar en texbox el contenido de la columnas del row seleccionado como le muestro a continuacion:

    DataGridViewSelectedRowCollection row = dgv_DesktopUsers.SelectedRows;

    if (row.Count == 1)
    {
    this.tb_Code.Text = row[0].Cells[Codigo].Value.ToString();
    //this.tb_Name.Text = row[0].Cells["Nombres"].Value.ToString();
    this.tb_LastName.Text = row[0].Cells["Apellidos"].Value.ToString();
    //this.tb_UserLogIn.Text = row[0].Cells["Usuario"].Value.ToString();
    //this.tb_Password.Text = row[0].Cells["Clave"].Value.ToString();
    this.cb_State.Checked = Convert.ToBoolean(row[0].Cells["Activo"].Value.ToString());

    pero el compilador al momento de tratar de leer la fila,columna me da el error {"Referencia a objeto no establecida como instancia de un objeto."}

    Podría orientarme en como resolver esto?

    gracias de antemano por su valiosa ayuda

    ResponderEliminar
  12. Hola Luis
    NO te sirve algo así:

    private void dataGridView1_CellClick(object sender, dataGridViewCellEventArgs e)
    {
    if (e.RowIndex >= 0)
    {
    this.textBox2.Text = this.dataGridView1.Rows[e.RowIndex].Cells[0].Value.ToString();
    this.textBox3.Text = this.dataGridView1.Rows[e.RowIndex].Cells[1].Value.ToString();
    }
    }

    ResponderEliminar
  13. hola leandro nuevamente favor
    necesito hacer una fatura en vb que selecione cierto producto y lo coloque en un datagridview, la pregunta es como capturo del datagrid el id para insertarlo en la base,la idea es un boton añadir y un boton eliminar items e insertar la factura con los items del datagridview


    en segunda instacia como podria en un datagrid de dos columnas id, nombre solo necesito desde un boton cambiar nombre


    gracias cordial saludo

    ResponderEliminar
  14. hola mauricio

    pero no se supone que el grid tiene algun campo id donde puedas tomar el valor cuando quieres operar con este

    podrias definir las columnas en tiempo de diseño

    [DataGridView] – Parte 4 - Uso del DataGridViewComboBoxColumn


    alli veras en la priemr parte como definir las columnas y mapearla a los datos

    saludos

    ResponderEliminar
  15. Hola Leandro.
    Lo segui hasta aqui desde el foro de msdn. Por alguna razon no puedo postear alli, al darle enviar me sale "error inesperado".

    He revisado otros posts del foro y he tratado de usar las soluciones planteadas pero no me resulta.

    Estoy intentando cambiar el color de letra o fondo de una fila de dataGridView segun el valor de un campo.

    Estoy utilizando C# en Visual Studio 2010

    He tratado de modificar las filas luego de cargarlas pero no funciono: (el messageBox dentro del if funciona segun lo esperado)

    //cargar grilla
    this.confirma_turnoTableAdapter.FillBy(this.sAADataSet.Confirma_turno);

    //Colorear filas pendientes
    foreach (DataGridViewRow row in dgvTurnosConfirmados.Rows)
    {
    estadoTemp = (String)row.Cells[5].Value.ToString();
    if (estadoTemp == "Confirmado")
    {
    //MessageBox.Show(estadoTemp, "Name Entry Error",MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
    row.DefaultCellStyle.BackColor = Color.Red;
    }
    }
    //actualizar dgv
    this.dgvTurnosConfirmados.Refresh();
    Luego he tratado de usar el evento cellformatting:

    private void dgvTurnosConfirmados_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
    {
    if (dgvTurnosConfirmados.Columns[e.ColumnIndex].Name == "Estado")
    {
    if (e.Value.ToString() == "Confirmado")
    {
    dgvTurnosConfirmados.Rows[e.RowIndex].DefaultCellStyle.ForeColor = Color.Red;
    }
    }
    }

    En ambos casos simplemente no sucede nada y la grilla se carga sin formateo.

    Desde ya muchas gracias disculpa la molestia.

    ResponderEliminar
  16. hola

    si pones un breakpoint notas que asigna algun color en la row del grid ?

    porque quizas ninguna celda coincida con la palabra Confirmado, recuerda que se compara mayuscular y minusculas, quizas debas poner con ToLower() para poner en minuscula para comparar

    si pones un breakpoint en el codigo por donde notas que pasa la ejecucion?

    lo del foro a veces sucede, si esperas un tiempo despues deberias ponder postear la pregunta, intenta usar algun otro browser como ser firefox o IE a veces con alguno funciona mejor que con otro

    saludos

    ResponderEliminar
  17. Solo quiero darte las gracias por compartir tus conocimiento con nosotros, es una valiosa ayuda.
    Ya me vas salvando de varias.
    saludos desde Perú.

    ResponderEliminar
  18. hola leandro

    en esta ocasion tengo un datagridview con datos de automoviles, lo que quiero es utilizar dos text box y un boton en el cual yo dijite un auto en text box 1 y dijite otro auto en el text box2 y que cuando presione el boton este me lo compare por la categoria *año* y me despliegue un mensaje mostrandome cual es el mejor. e intentado buscar ejemplos pero no encuentro si tienes algun ejemplo de como hacerlo te lo agradeceria mucho ya esa es la etapa final para mi proyecto de automoviles gracias

    ResponderEliminar
  19. Hola Leandro!!!
    Me podrías ayudar con este problema
    tengo dos gridviews uno Clientes y otro facturas ambos se cargan desde archivos de EXCEL, los cuales tienen varios campos en común, lo que necesito es buscar por medio del "ID" cuales clientes facturaron y mostrarlos en otro formulario.

    Gracias por tu ayuda

    ResponderEliminar
  20. hola Ulises

    podrias cargar los datos de ls excel en datatable y luego usar linq con un join para cruzar la informacion por el id

    aqui
    [ADO.NET] Excel y Linq (Union)

    usi el union, lo que planteo es similar solo que usando el join
    Consultas entre tablas (LINQ to DataSet)

    saludos

    ResponderEliminar
  21. Hola Leandro una Consulta quisiera ser una busqueda desde un DataGridView. pero no desde de un textox si no desde una de las celdas de la misma grilla.
    en verdad he estado buscando y no encuentro. Las celdas se pueden editar gracias a una propiedad. pero si se pued ehacer un filtro dentro seria mejor apra hacer la busqueda. por que a veces puede tener cientos de registros.
    Gracias por tu respuesta y me ayudado mucho tus post"

    ResponderEliminar
  22. Muy bueno tu post pero me gustaría hacer lo anterior casi todo igual lo que cambia es que la primera celda no es un combobox sino un textbox como seria y que se pudiera hacer la consulta con el codigo o con el nombre en la misma celda.
    Gacias

    ResponderEliminar
  23. hola Unknown

    si es un textbox podrias usar el evento CellEndEdit para realizar una accion despues de completar la celda

    esto aplica si es una accion que ingresa el usuario, si es una lectura con algun dispositivo no lo realices directo sobre el grid, usa un textbox por fuera y luego de la lectura vuelcas los datos a la row

    saludos

    ResponderEliminar
  24. Hola Leandro, Espero estes muy bien.!
    Te cuento, estoy comenzando en el mundo de la programacion, actualmente estoy realizando en ASP.NET y con C# una gridview y quisiera que al seleccionar una fila compare el contenido en mi database y me avise si ya existe. Espero haberme explicado bien. Por favor si tienes alguna guia que me pueda ayudar seria excelente. Muchisimas Gracias de antemano.!

    ResponderEliminar
    Respuestas
    1. hola
      Pero como estas generando las filas del gridview ? porque si estas las cargas desde la db entonces siempre va a existir el registro en la tabla al seleccionarlo
      Imagino la definicion del evento de seleccion en el grid sabes como definirla, o sea usar el evento SelectedIndexChanged
      Para validar usando ado,net podrias ejecutar una query como ser
      SELECT COUNT(*) FROM Tabla WHERE id = @id
      usando el ExecuteScalar() podrias validar si devuelve cero (no existe) o un valor
      saludos

      Eliminar
  25. Hola Leandro, quisiera ocupar un poco de tu tiempo para resolver una pequeña duda:
    Cargue un datagrid usando interop para importar un excel basico, lo que quiero hacer es que al hacer doble click sobre una casilla me recupere el valor de la celda del excel en un textbox.
    Cree el evento doble click en el data grid ya solo me falta poder recuperar los datos, a todo esto lo estoy haciendo en wpf
    Muchas gracias maestro

    ResponderEliminar
    Respuestas
    1. hola
      si usas el evento CellDoubleClick tienes el e.ColumnIndex y e.RowIndex para poder obtener la celda y recuperar su valor

      string cellvalue = DatagridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value;

      saludos

      Eliminar
  26. Muchas gracias. Fue de mucha ayuda tu explicación.
    Saludos.

    ResponderEliminar