lunes, 1 de marzo de 2010

[DataGridView] – Cálculos Totales en las filas y columnas

 

Introducción


Muchas de las veces que se opera con el control DataGridView es necesario realizar cálculos sobre el mismo, por lo general estos requieres del input del usuario de ciertos valores que trabajaran sobre otros ya cargados en el control

En este articulo tratare de de mostrar como hacer uso del control DataGridView para poder realizar estos cálculos, reflejando el resultado como totales de filas y columnas.

 

Carga de los datos en la grilla


Esta será la primer operación ha realizar, la carga de los datos de los productos en la grilla.

private void frmPedidos_Load(object sender, EventArgs e)
{
    //
    // Se recupera los datos de los productos desde la tabla
    //
    dtoProductos datos =  ProductoDAL.ProductosGetAll();

    //
    // Se agrega un registro adicional al DataTable, para representar la fila de totales
    //
    dtoProductos.ProductosRow rowTotal = datos.Productos.NewProductosRow();
    datos.Productos.Rows.Add(rowTotal);  

    //
    // Se bindean los datos a la grilla
    //
    dataGridView1.AutoGenerateColumns = false;
    dataGridView1.DataSource = datos;
    dataGridView1.DataMember = "Productos";

    //
    // Se selecciona la ultima fila de Totales y se marca como readonly
    // para evitar la seleccion por el usuario
    //
    DataGridViewRow row = dataGridView1.Rows[dataGridView1.Rows.Count - 1];
    row.ReadOnly = true;

    //
    // Se asigna el evento para detectar los cambios que el usuario realice
    //
    dataGridView1.CellValueChanged +=new DataGridViewCellEventHandler(dataGridView1_CellValueChanged); 
}

Como se puede apreciar se realizan algunas operaciones programáticamente sobre los datos antes de bindearlos, por ejemplo una de las principales es al agregado de una fila adicional al final del datatable ,esta operación es importante ya que permitirá visualizar la fila de totales al final de la grilla.

Otra operación importante es realizada luego de bindear, en donde se pone en readonly la ultima fila para evitar que el usuario la edite.

Algo a remarcar es la asignación del evento manuablemente en la ultima línea del evento Load del formulario, esta asignación es realizada en este punto ya que si se realiza por medio del cuadro de propiedades del Visual Studio, el evento “CellValueChanged” será lanzado varias veces cuando se carga la grilla, lo cual se evita al no asignar el el evento al comienzo, este evento solo es necesario ante la edición del usuario y no en la carga del mismo.

 

Calculo de totales


Ante la edición del campo de “pedido” o la selección de uno de los check de la columna de “selección”, es que se disparara este evento.

 

private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
    //
    // Solo se trabaja ante los cambios en la columan de los checkbox 
    // y el ingreso de una canifad por el usuario
    //
    if (dataGridView1.Columns[e.ColumnIndex].Name == "Seleccion" ||
        dataGridView1.Columns[e.ColumnIndex].Name == "Pedido")
    {
        decimal totalColumna = 0;

        //
        // Se recorre fila a fila para recalcular el total despues del cambio
        //
        foreach (DataGridViewRow row in dataGridView1.Rows)
        {
            //
            // Se selecciona la celda del checkbox
            //
            DataGridViewCheckBoxCell cellSelecion = row.Cells["Seleccion"] as DataGridViewCheckBoxCell;

            //
            // Se valida si esta checkeada
            //
            if (Convert.ToBoolean(cellSelecion.Value))
            {
                //
                // Se valida si el usuario ingreso un valor en la celda de pedido
                //
                decimal pedido = 0;
                if (!decimal.TryParse(Convert.ToString(row.Cells["Pedido"].Value), out pedido))
                    continue;

                //
                // Se realiza el calculo para la fila, asignado el total en la celda "Total"
                // de la misma 
                //
                decimal totalFila = Convert.ToDecimal(row.Cells["PrecioUnitario"].Value) * pedido;
                row.Cells["Total"].Value = totalFila;

                //
                // Se aumula el total de cada una de las filas
                //
                totalColumna += totalFila;
            }
        }

        //
        // Se toma la ultima fila del total general, asignando el valor acumulado en el calculo
        //
        DataGridViewRow rowTotal = dataGridView1.Rows[dataGridView1.Rows.Count - 1];
        rowTotal.Cells["Total"].Value = totalColumna;

    }
}

En este evento se recorrerá cada una de las filas de la grilla realizando los cálculos a nivel de la propia fila, pero también de la columna de totales.

Adicionalmente se agrego el evento de validación, ante una entrada incorrecta del usuario en la celda de pedidos, si el usuario ingresa letras se mostrara un alerta en la fila.

private void dataGridView1_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
{
    if (dataGridView1.Columns[e.ColumnIndex].Name == "Pedido")
    {
        //
        // Si el campo esta vacio no lo marco como error
        //
        if (string.IsNullOrEmpty(e.FormattedValue.ToString()))
            return;

        //
        // Solo se valida ante el ingreso de un valor en el campo
        //
        decimal pedido = 0;
        if (!decimal.TryParse(e.FormattedValue.ToString(), out pedido))
        {
            DataGridViewRow row = dataGridView1.Rows[e.RowIndex];
            row.ErrorText = "Debe ingresar un número valido";
            e.Cancel = true;
        }
    }
}

//
// Este evento es usado al presiona ESC cancelando la edicion
// se elimine el mensaje de error en la fila
//
private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
    dataGridView1.Rows[e.RowIndex].ErrorText = String.Empty;
}

 

Nota: Hay un problema en  las validaciones en la grilla. Si por alguna razón cuando usa las validaciones en el DataGridView, no visualiza el icono con el mensaje del error esto se puede deber a que la propiedad AutoSizeRowsMode  no esta asignada con el valor None.

DataGridView1.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.None

tenga en cuanta este punto cuando use las validaciones

 

[C#]
[VB.NET]

58 comentarios:

  1. Hola Leandro,

    al probar el ejemplo en C# en un sistema de 64 bits, los cuales no incoporan OLEDB, he tenido que modificar para que la compilación se haga en x86, revisar este enlace:
    http://support.microsoft.com/default.aspx/kb/942977/es

    Saludos.

    Saludos.

    ResponderEliminar
  2. hola leandro queria preguntarte si son necesarios los checkbox y en caso de que no los utilize que partes de codigo debo omitir

    ResponderEliminar
  3. hola Ascencio

    los checkbox no son obligatorios, podrias aplciar la misma tecnica sin estos

    solo se usaron los check para no calculoar el total de todas las filas sino solo aquellas que interesaban

    el tema es que sino hay un evento, vas a tener que usar algun foreach para recorrer todas las filas y sumar el resultado, como se hace alli en el evento CellValueChanged pero sin evento porque ya no tienes los checks

    saludos

    ResponderEliminar
  4. Hola tengo un grid con un gridcombobox el detalle es que inicia en blanco eso es corecto ya que si no seleeciono un valor del combo en el grid no me muestra nada el detalle es que cuando el usuario da clic en una celda se agrga una nueva fila no se como corregir este detalle que no me queda

    ResponderEliminar
  5. hola jempdulintre

    no entendi
    que es lo que no queda? no queda el combo en blanco?

    no has evaluado poner un item adicional que refleje esta situacion, un item por fuera de los datos que indique la no seleccion

    ComboBox - DropDownList – Opción “Todos”


    saludos

    ResponderEliminar
  6. Hola gracias por responderme.
    ya resolví la incógnita.

    era un evento para validar columnas en readOnly() en el load y únicamente la columna del combobox no es No readonly. cuando yo selecciono un elemento del combobox con el evento selectcominchange agrego otro evento para que mi quite el valor del readOnly() a noReadOnly();
    a si únicamente me deja editar la fila seleccionada y ya no me permite escribir en la fila consecutiva que se agrega automáticamente repito el mismo evento readOnly(); cuando dicha se agrega.
    ese era mi problema
    :)
    saludos

    ResponderEliminar
  7. Buenas tardes Leandro,
    Tu blog esta muy bueno, estoy programando en C# y en cuanto a este post, apliqué los codigos para la suma del campo del gridView pero sin los CheckBox.. solo multiplico "Precio" por "Cantidad"
    pero tengo un problema, la primera fila arroja un resultado correcto, pero en la segunda fila hace el calculo y le adiciona el resultado de la fila anterior a la nueva fila
    Si me podes ayudar por fa

    Saludos

    ResponderEliminar
  8. hola Sergio

    que raro esto que comentas porque si analizas el ejemplo veras que en la linea

    decimal totalFila = Convert.ToDecimal(row.Cells["PrecioUnitario"].Value) * pedido;
    row.Cells["Total"].Value = totalFila;

    se asigna a una variable local del foreach el valor del total de la fila, has validado que la variable no la estes acumulando o declarando por fuera del foreach
    saludos

    ResponderEliminar
  9. tengo una duda sobre como validar las columnas de mi gridview en c# y sobre webform no winform

    saludos mi correo es cora.ben@gmail.com

    ResponderEliminar
  10. hola

    y cual seria la duda ?

    quizas podrias plantearla en el foro

    Foro C#

    ResponderEliminar
  11. Que tal Sr. Leandro. Mi consulta es la siguiente para una validacion de existencias de producto, por decir si tengo en stock 8 manzanas y quiero ingresar 10 manzanas para vender. El programa me dice que no hay esa cantidad, pero = agrega al datagrid. ¿Como haría para evitar que agrege ese item?

    ResponderEliminar
  12. hola Henry

    pero si logras hacer la validacion para que no ingrese ese item porque continuas la ejecucion, deberias cortar y salir


    if(!validacion()){
    MessageBox.Show("mensaje");
    return;
    }
    //resto codigo

    o sea sino valida muestras el mensaje y sales, si continuas es logico que agregara el item

    si esto lo haces en una celda deberias usar el evento CellValidating, en este con el e.Cancel = true
    podrias detener la ejecucion

    saludos

    ResponderEliminar
  13. Hola Leandro,

    A ver si me puedes orientar con está duda.

    Lo que quiero es sumar una columna en un Textbox y lo hago con un botón con el siguiente codigo:

    Dim total As Double
    For i As Integer = 0 To dgvVender.RowCount - 1
    total = total + CDbl(dgvVender.Item(DcSubtotal.ToString, i).Value)
    Next

    txtTotal.Text = total

    Y funciona bien, pero lo que yo quiero es que se sume sin la necesidad del botón, sino que se valla sumando al ir agregando nuevas filas a la columna.

    Espero haberme explicado.


    Pd. Uso Vb.NET 20

    ResponderEliminar
  14. hola Ivan

    para que sume sin el boton podrias ver que evento utilizar, como podrias ser el CellEndEdit

    al terminar de editar realizar la suma

    saludos

    ResponderEliminar
  15. y como puedo hacer para al seleccionar la fila.del total. no me elimine al presionar delete ?

    ResponderEliminar
  16. y como se podria hacer para que al presionar la tecla tab salte de la celda editable a check , y del check a la celda editable

    ResponderEliminar
  17. y como puedo hacer para al seleccionar la fila.del total. no me elimine al presionar delete ?

    ResponderEliminar
  18. hola Maicol8k

    para no eliminar la fila podrias validarlo, o sea que se presione la tecla de eliminar o como lo estes realizando, solo que validas que no sea la ultima row la que este seleccionada que se ejecuta la accion, si lo es no realizas la operacion

    o sea lo evitas aplicando validacion en el codigo que defines para eliminar

    saludos

    ResponderEliminar
  19. Hola Leandro!.

    Tu ejemplo esta muy claro. pero en mi caso es distinto como le puedo hacer si quiero sacar promedio pero no de una columna, mas bien los promedios de todas las filas x ejemplo:

    tengo las siguiente columnas:
    nom_com mat1 mat2 mat3 mat4 prom.

    en el primer registro tengo en la columna mat1 un 10 y en la columna mat4 un 9, ahora quiero sacar promedio pero solo de los valores de la columna mat1 y mat4 por que son los que tienen un valor, es decir (contar simplemente las columnas con un valor, sumarlos y dividirlo solamente entre el numero de columnas que tengan un valor, pero no el total de las columnas.

    espero haberme explicado. Gracias!

    ResponderEliminar
  20. hola Lazaro

    la tenica es la misma, solo que en tu caso cuando recorras los registros tomaras los valores de esas dos columnas
    al aceder a la row usarias

    string val = row.Cells["mat1"].Value.ToString();
    string val2 = row.Cells["mat4"].Value.ToString();

    con estos valores son con los cuales ocumularas para poder realizar el promedio

    saludos

    ResponderEliminar
  21. lo que pasa es que necesito que cuando selecciono un dato de un comboBox, este consulta en la base de datos y me trae y almacena en un datagridview datos del nombre seleccionado,,, ya consulto en la base de datos pero como hacer para que en el datagridview se almacene cada vez que selecciono.
    Gracias

    ResponderEliminar
  22. hola Elessar

    o sea en cada busqueda quieres ir agregandola a los resultados de la busqueda anterior
    lo que no quieres es que cada vez que buscas pisa los registros de la busqueda anterior?

    si es asi podrias en cada busqueda cargar un datatable, donde su variable la defines a nivel del form, con lo cual podrias usar

    DataTable.Merge

    para asi ir agregando los datos a los que ya tenias, cuando unes estos datos en la variable global del form luego lo asignas al datasource del grid

    saludos

    ResponderEliminar
  23. Hola Leandro
    Como podria hacer lo del DataTable.Merge
    cuando selecciono el dato del combobox
    private void cBoxTipoConsulta_SelectedIndexChanged(object sender, EventArgs e)
    { dataGridView1.DataSource = miProcedimiento.getListClientes1(nombre);
    }

    me carga los datos de la BD a un datagridview, pero cuando selecciono otro dato del combobox me lo sobreescribe y no me lo coloca en la segunda posicion.

    lo de datatable.merge me podrais explicar como funciona o darme un ejemplo

    gracias por la atencion

    ResponderEliminar
  24. hola Elessar

    podrias no asignar directamente los datos al datasource, sino alli hacer el merge

    private DataTable dt;

    private void cBoxTipoConsulta_SelectedIndexChanged(object sender, EventArgs e)
    {
    DataTable dtTemp = miProcedimiento.getListClientes1(nombre);

    dt.Merge(dtTemp);

    dataGridView1.DataSource = dt;

    }

    por supuesto antes al dt deberias instanciarlo y crear la estructura de campo

    saludos

    ResponderEliminar
  25. Hola leandro
    tengo un problema
    DataTable dtTemp = miProcedimiento.getListClientes1(nombre);
    dice algo asi como que esto miProcedimiento.getListClientes1(nombre); no se puede convertir implicitamente en system.data.datatable

    ResponderEliminar
  26. hola Elessar

    el metodo getListClientes1() que tipo de dato retorna?
    no sera una lista, coleccion o quizas un dataset

    debes verificar que tipo defines en el metodo para devolver como respuesta

    ademas miProcedimiento imagino es una clase que tu creas, o sea trata de un dataset tipado, o sea proviene de un TableAdapter

    saludos

    ResponderEliminar
  27. Hola Leandro gracias por tu aporte queria hacerte una consulta para empezar tengo un datagridview llamado dgvFacturas (Facturas de Compra) con DataGridViewCheckBoxColumn, que al darle click me carga otro llamado dgvPagosFacturas (pagos realizados a las facturas), ahora al marcar el checkbox me pasa el numero de factura del dgvFacturas valor del y el saldo del dgvPagosFacturas a un tercer datagridview llamado dgvComprobanteEgreso hasta ahi todo bien, solo que el evento CellValueChanged se me esta ejecutando 2 veces y por ende todo calculo ejecutado dentro del mismo se duplica

    ResponderEliminar
  28. lo estoy haciendo de la siguietne forma:
    Private Sub dgvComprobantesCompra_CellClick(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles dgvComprobantesCompra.CellClick
    Try
    If dgvComprobantesCompra.CurrentRow.Cells.Item(0).Value Is DBNull.Value Then
    lblIdComprobanteCompra.Text = "..."
    Else
    lblIdComprobanteCompra.Text = dgvComprobantesCompra.CurrentRow.Cells.Item(1).Value
    cargarPagosComprobantesCompra()
    End If
    Catch ex As Exception
    End Try
    End Sub

    Private Sub dgvComprobantesCompra_CurrentCellDirtyStateChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles dgvComprobantesCompra.CurrentCellDirtyStateChanged
    If dgvComprobantesCompra.IsCurrentCellDirty Then
    dgvComprobantesCompra.CommitEdit(DataGridViewDataErrorContexts.Commit)
    End If
    End Sub

    Private Sub dgvComprobantesCompra_CellValueChanged(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles dgvComprobantesCompra.CellValueChanged
    Try

    ' Solo se trabaja ante los cambios en la columan deseada
    '
    If dgvComprobantesCompra.Columns(e.ColumnIndex).Name = "chk" Then
    objetoPagosComprobantesCompra.BuscarMayorSaldoPagosComprobantesCompraXIdComprobante(dgvComprobantesCompra.CurrentRow.Cells(1).Value)
    If objetoPagosComprobantesCompra.saldoPagosComprobantes <> 0 Then
    cargarComprobanteEgreso()
    sumarTotalComprobante()
    Else
    MsgBox("ESTA FACTURA YA CANCELADA", MsgBoxStyle.Exclamation, "MENSAJE DE VALIDACIÓN")

    End If
    End If
    Catch ex As Exception
    End Try
    End Sub

    Private Sub dgvComprobantesCompra_CellEndEdit(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles dgvComprobantesCompra.CellEndEdit
    ' Este evento es usado al presiona ESC cancelando la edicion
    ' se elimine el mensaje de error en la fila
    dgvComprobantesCompra.Rows(e.RowIndex).ErrorText = [String].Empty
    End Sub

    ResponderEliminar
  29. hola Patricio

    si pones un breakpoin en el evento CellValueChanged y al detenerse en cada accion analiza la ventana de "Call Stack" desde donde puedes observar se produce la invocacion? esto para poder determinar quien invoca al evneto la primer y segunda vez

    saludos

    ResponderEliminar
  30. HOLA LEANDRO
    GRACIAS POR TU RESPUESTA ESTO ES LO QUE OBTUVE DE LA "PILA DE LLAMADAS" LA PRIMERA VEZ QUE SE EJECUTA:

    > Sys - Cisepro.exe!SysCisepro.FormComprobanteEgresoBanco.dgvComprobantesCompra_CellValueChanged(Object sender, System.Windows.Forms.DataGridViewCellEventArgs e) Línea 711 Basic

    Sys - Cisepro.exe!SysCisepro.FormComprobanteEgresoBanco.dgvComprobantesCompra_CurrentCellDirtyStateChanged(Object sender, System.EventArgs e) Línea 696 + 0x20 Bytes Basic

    Y ESTO PASA LA SEGUNDA VEZ:
    > Sys - Cisepro.exe!SysCisepro.FormComprobanteEgresoBanco.dgvComprobantesCompra_CellValueChanged(Object sender, System.Windows.Forms.DataGridViewCellEventArgs e) Línea 711 Basic

    Sys - Cisepro.exe!SysCisepro.FormComprobanteEgresoBanco.dgvComprobantesCompra_CurrentCellDirtyStateChanged(Object sender, System.EventArgs e) Línea 696 + 0x20 Bytes Basic

    SON LOS MISMOS EVENTOS EN LAS DOS OCACIONES

    ResponderEliminar
  31. hola Patricio

    el evento lo asignas solo en el grml como una propiedad del gridview
    o tambien lo defines desde codigo

    la verdad esta raro que sea invocado dos veces

    defines algun otro evento con respecto al dirty de la celda ? porque eso podria estar afectando, prueba solo dejar el evento CellChange y nada mas

    saludos

    ResponderEliminar
  32. Hola Leandro, soy nuevo en ASP.NET pero este aportación me soluciono un problema que tenia hace dos semanas.

    Este codigo es cuando quieren usar dos textbox:


    $(document).ready(function () {

    $("#<%=Gridview1.ClientID%> [id*='TextBox3']").change(function () {

    var tr = $(this).parent().parent();
    var a = $("td:eq(2) :text", tr).val();
    var b = $(this).val();
    var total = a * b ;

    $("td:eq(4) :text", tr).val(total);

    });



    });

    ResponderEliminar
  33. hola yamalmay

    pero en este articulo estos usando un datagridview, no tiene nada que ver con asp.net

    ademas pones el codigo peor no veo cual es el problema, en principio parce estar correcto
    si pones la linea

    debugger;

    para que se deternian la ejecucion, podrias evaluar como resuelve

    saludos

    ResponderEliminar
  34. saludos podria subir el proyecto que no lo puedo descargar

    ResponderEliminar
  35. Hola Leandro, tengo datagridview de historiales donde muestro las ventas con su forma de pago de la siguiente manera:
    Cliente Forma de Pago Total $
    lo que estoy intentando es poder sumar los totales según la forma de pago pero usando linq y mostrarlos en un label, la cosa es que no se me esta dando resultado, mi pregunta seria en que evento podría realizar esto y establecer la condición de pago en mi caso la condición la tengo del tipo string 'CONTADO', 'TARJETA', etc.
    Estoy haciendo algo como esto:

    foreach (DataGridViewRow row in dgvVentas.Rows)
    {
    DataGridViewCell formaPago = row.Cells["FORMA"];


    if (Convert.ToString(formaPago.Value) == "CONTADO")
    {
    decimal result = dgvVentas.Rows.Cast().Sum(x => Convert.ToDecimal(x.Cells["TOTAL"].Value));
    txtTotalContado.Text = result.ToString();
    }
    if (Convert.ToString(formaPago.Value) == "TARJETA")
    {
    decimal result = dgvVentas.Rows.Cast().Sum(x => Convert.ToDecimal(x.Cells["TOTAL"].Value));
    txtTotalTarjeta.Text = result.ToString();
    }
    }

    si bien el método funciona pero me suma el total no pasa por la condicion. Desde ya gracias

    ResponderEliminar
  36. hola Augusto

    pero alli estas sumando a nivel de row, si son totales no deberias sumar por columna ?

    o podrias sumer directamente usando linq, asi evitas el foreach

    decimal totalContado = dgvVentas.Rows.Cast<DataGridViewRow>()
    .Where(x=>x.Cells["FORMA"].Value.ToString() == "CONTADO")
    .Sum(x => Convert.ToDecimal(x.Cells["TOTAL"].Value));

    txtTotalContado.Text = totalContado.ToString("N2");

    saludos

    ResponderEliminar
  37. Gracias por tu ayuda Leandro me a servido un monton. Saludos.

    ResponderEliminar
  38. Hola Leandro siguiendo tu algoritmo como podria implementar el cambiar una columna a partir de un valor es decir que desde un texbox multiplique el valor de cada celda de la columna y guardarla en mysql

    ResponderEliminar
  39. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  40. buenas noches maestro leandro, tengo una pregunta, tengo un grid que carga los datos de la BD, de esa grid tengo dos columnas, una de existecias y otra de cantidad_ajustada,en el cual el campo existencias de la tabla que corresponde se deberá actualizar de acuerdo a la resta de las existencias con la cantidad_ajustada, esto viéndolo como si fuese una factura la cual el objetivo final es actualizar N lineas de articulos de acuerdo a esa resta.
    Espero me halla explicado bien, y de ayudarme con esto sería de mucha ayuda de antemano te agradezco maestro. saludos !!!

    ResponderEliminar
  41. hola Jaime

    como es que realizas la actualizacion de los datos del grid?
    recorres uno a uno las rows del gris y vas realizando el UPDATE de los datos

    update/insert a un tabla desde datagridview

    Utilizar campos de una grilla para realizar un update en vb.net y sql server

    saludos

    ResponderEliminar
  42. buenos dias Leandro, soy un poco nuevo en esto de las grid, y pues yo pensaba recorrer con el foreach cada uno de los registros para realizar el update en cada registro, puedes guiarme un poco en este tema maestro? te agradezco la respuesta, saludos !!!

    ResponderEliminar
  43. hola Jaime

    por este medio poner codigo se puede complicar, quizas deberias plantear el tema en el foro de msdn

    Foro Lenguaje C#

    y seguimos desde alli.

    los link que puse en la respuesta anterior pudiste revisarlos

    saludos

    ResponderEliminar
  44. Gracias leandro, si los revisé y no me habia percatado de algunos detalles, seguiré el tema en el link que me dejastes.

    ResponderEliminar
  45. Aca les dejo mi solucion:

    Private Function SumarFilas(ByVal dtWork As DataTable) As DataTable
    'Lógica para agregar la sumatoria de cada fila
    dtWork.Columns.Add("Total", Type.GetType("System.Int32"))
    Dim totalfilaTmp As Integer
    Dim totalcolTmp As Integer
    For Each fila As DataRow In dtWork.Rows
    totalfilaTmp = 0
    For i As Int16 = 9 To dtWork.Columns.Count - 2
    totalfilaTmp = totalfilaTmp + fila(i)
    Next
    fila("Total") = totalfilaTmp
    Next
    'Lógica para agregar la sumatoria de cada columna de las tallas
    Dim rowTotal As DataRow = dtWork.NewRow
    For i As Int16 = 9 To dtWork.Columns.Count - 1
    totalcolTmp = 0
    For Each fila As DataRow In dtWork.Rows
    totalcolTmp = totalcolTmp + fila(i)
    rowTotal(i) = totalcolTmp
    Next
    Next
    dtWork.Rows.Add(rowTotal)

    Return dtWork
    End Function

    ResponderEliminar
  46. Hola Leandro, tengo un datagridview que lleno con 6 columnas de datos, y necesito el subtotal de 3 de esas columnas en un reglon al final del ultima registro. Como puedo hacerle?

    ResponderEliminar
    Respuestas
    1. hola
      Debo mencionarte que el DataGridView no tiene concepto de footer, por lo tanto si puede evitar definir un ultimo registro seria mejor,quizas poner labels o textbox donde mostrar esos datos.
      Igualmente si lo necesitas integrado al grid se puede lograr, simplemente te ayudas de linq para sumar las columnas

      var result = from row in DataGridView1.Rows.Cast().Sum(x=> Convert.ToDecimal(x.Cells["nombreColumns"].Value));

      asi sumarias cada columna
      Lo que no se es como asignas los datos al grid, si lo haces con el DataSource el nuevo registro deberias agregarlo al origen de datos, o sea al datatable o lista que asignas al grid
      saludos

      Eliminar
    2. Hola Leandro, al final he decidido hacerlo como sugieres al principio en textbox y ya quedo sulucionado, igual tendre en cuenta el segundo metodo que me comentas, solo me quedo la duda de como anexarlo al datasource jeje soy nuevo en c#. Igualmente muchas gracias por la ayuda!

      Eliminar
  47. Buenas amigo alejandro. Llevo 2 años creando un sistema administrativo en VB.net. Gracias a usted, sus buenos conocimientos y oficios, he podido avanzar un monton con mi proyecto. De verdad le deseo muchos exitos y Suerte.

    P.D: usted tiene alguna red social para chatear con usted o un correo para hacerle algunas consultas??? Muchisimas Gracias desde Venezuela

    ResponderEliminar
    Respuestas
    1. hola
      Es un gusto poder ayudar, me alegro que el desarrollo avance.
      Mi mail lo puedes obtener del link en mi perfil de mvp, debo decirte que por ese medio no soy muy rapido en la respuesta, por eso sino es un tema que requiera confidencalidad podrias plantearla en los foros de msdn alli sino soy yo seguro alguien de la comunida te responde a la brevedad
      saludos

      Eliminar
  48. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  49. Hola Leandro, tengo un problema con un datagridview y la columna checkbox, resulta que quiero guardar nada mas las celdas seleccionadas pero me recorre el datagrid las veces que se han marcado ejemplo 3 y me guarda las tres veces el mismo valor los mismos datos de las columnas!!

    Este es mi codigo para guardar

    foreach (DataGridViewRow fila in this.dataGridView1.Rows) // recorro el datagrid
    {

    // si esta seleccionado
    if (Convert.ToBoolean(fila.Cells["Seleccione"].Value))
    {
    // Toma los valores de las columnas
    agregar.IDBeneficiario = Guid.Parse(this.txtIDBen.Text);
    agregar.IDProyecto = Guid.Parse(dataGridView1.CurrentRow.Cells["IDProyecto"].Value.ToString());
    agregar.presentacion = Convert.ToString(dataGridView1.CurrentRow.Cells["Presentacion"].Value.ToString());
    agregar.MontoIndividual = Convert.ToDecimal(dataGridView1.CurrentRow.Cells["Monto"].Value);

    // y guarda
    miServicio.GuardarProyectoBen(agregar);


    }


    }



    Agradeceria inmensamente tu ayuda!!

    Saludos!!

    ResponderEliminar
  50. Saludos Leandro, antes que nada gracias por compartirnos tus conocimientos con nosotros los mortales jeje, este ejemplo me ha servido mucho para lo que quería hacer y me ha funcionado, pero quería hacerte una consulta de primer grado escolar jejeje, pero quiero entender.

    Esta sentencia
    dataGridView1.CellValueChanged +=new DataGridViewCellEventHandler(dataGridView1_CellValueChanged);

    ¿Por qué debe de agregarse en el load? es decir quiero entender que hace en el programa ¿porque es necesaria? porque el trigger cellvaluchanged ya existe en el control no debo definirla de nuevo ¿o si?. ¿me explico?

    Si puedes ilustrarme o enviarme algún link donde pueda leer mas acerca de esto te lo voy agradecer
    saludos

    ResponderEliminar
  51. hola
    Adjuntar un evento depende de donde lo realices, si lo haces por medio del diseñador el evento lo veras en el Designer.cs relacionado con el form, pero si queires tu controlar en que momento asignarlo lo realizas desde codigo.
    En este caso queria reflejar en el codigo la asignacion del evento, pero si lo haces desde el diseñador esa linea en el load no la necesitas

    Si defines tu un evento que quieres este desde la carga del form entonces lo pondrias en el Load, es por eso que esta alli. Si defines el evento desde el diseñador ya no seria necesaria, por lo que no la vuelves a adefinir

    saludos

    ResponderEliminar
  52. mmm interesante gracias por la excelente explicación, queda muy claro
    saludos

    ResponderEliminar
  53. Hola Leandro

    Espero me puedas ayudar yo tengo un datagridview en el cual hago cálculos o mas bien una suma este es mi código
    entonces yo tengo varios conceptos en la 1er columna aproximadamente 19 conceptos llamada la columna Impuestos y en la 2da columna tengo el total y llamada Total, entonces cuando yo voy ingresando cantidades y en tiempo de ejecución voy haciendo la suma en la columna llamada Total entonces en la celdas ingreso una cantidad y en la fila 5 ahi voy haciendo la suma, entonces mi problema o que no puedo solucionar es que si ingreso varias cantidades en las celdas por ejemplo celda 1 = 33.00, celda 2 = 22.00 y celda 3 = 15.00 la suma seria 70 pero si me regreso a la celda 2 o celda 1 a modificar y se vuelve a recalcular la suma en vez de darme la cifra correcta me sigue sumando con lo anterior si la celda la modifique la celda 1 = 50 y recalcular la suma que seria celda 1= 50.00, celda 2=22.00 y celda 3=15.00 seria 87 y no, me pone 70 + lo de la celda 1 que fue 50 + 70 = 120 y deberia ser 87 bueno espero me haya dado a entender y me puedas dar una pequeña solucion de antemano muchas gracias

    Saludos!!!


    private void Dgv_Presupuesto_CellEndEdit(object sender, DataGridViewCellEventArgs e)
    {

    Dgv_Presupuesto.Columns[1].DefaultCellStyle.Format = "N2";
    Valor = Convert.ToInt32(Dgv_Presupuesto[e.ColumnIndex,e.RowIndex].Value);
    this.Dgv_Presupuesto[e.ColumnIndex, e.RowIndex].Value = Valor;

    Valor1 += Valor;
    Dgv_Presupuesto[1, 5].Value = Valor1; //Aqui voy haciendo la suma

    }

    ResponderEliminar
  54. hola Leandro Tuttini una consulta tengo un datagridview que me carga desde el sql lo que quiero hacer es que me sume todas las columnas en una fila al final del mismo. gracias

    ResponderEliminar
  55. Hola Leandro
    estoy desarrollando una aplicacion con vb.net en mi trabajo, parta poder organizarme mejor, pero necesito hacer un reporte con el cual necesito con una consulta a mysql poder saber de todos los libros y manuales que se han consultado el reporte me muestre en un datagridview los datos sin repetirlos, eso ya lo tengo, lo que metiene estancado es como poder hacer en la misma consulta que por cada nombre que encuentre sume las horas que este libro ha acumulado con cada visita, no se si me puedes ayudar pero esto me tiene superado.

    cualquier ayuda te lo agradesco

    ResponderEliminar