Cómo sumar una columna del control DataGridView |
Por Enrique Martínez Montejo |
Última revisión: 23/07/2011 |
Se pueden utilizar varias técnicas para sumar una columna concreta del control DataGridView, dependiendo si el control se encuentra o no enlazado a un objeto DataTable.
En éste supuesto, la manera más fácil y rápida de obtener la suma total de una columna del objeto DataTable, es utilizar su método Compute, método al que se le puede especificar un filtro para que solamente se sumen los valores de la columna de aquellos registros o filas que cumplan con el criterio especificado. Si al filtro le especificamos la palabra clave Nothing, se sumarán los valores de todas las filas del objeto DataTable.
' Referenciamos el objeto DataTable enlazado con el
' control DataGridView.
'
Dim dt
As DataTable =
DirectCast(DataGridView1.DataSource, DataTable)
' Sumamos todas las filas de la columna
TotalFactura.
'
Dim resultado
As Object = dt.Compute("Sum(TotalFactura)",
Nothing)
TextBox1.Text =
String.Format("{0:N2}", resultado)
' Sumamos todas las filas de la columna
TotalFactura
' donde el campo Fecha esté comprendido entre el día
'
01/02/2011 y 28/02/2011.
'
resultado = dt.Compute("Sum(TotalFactura)",
_
"Fecha >= #02/01/2011# And Fecha <= #02/28/2011#")
TextBox2.Text =
String.Format("{0:N2}", resultado)
Para más información sobre las funciones de agregado y criterios de filtro que puede utilizar con el método Compute, consulte en la ayuda de Visual Studio la propiedad Expression de un objeto DataColumn.
Al no estar el control enlazado a un objeto DataTable, no nos va a quedar más remedio que ir sumando los valores individuales de las celdas de la columna conforme recorremos la colección de filas del control DataGridView, o bien utilizar una consulta LINQ to Objects.
Para los usuarios que no conozcan lo suficientemente LINQ como para utilizarlo con soltura, lo mismo se sentirán más cómodos ejecutando el siguiente bucle:
Dim resultado
As Decimal = 0D
For Each row
As DataGridViewRow
In DataGridView1.Rows
' Obtenemos el valor de la celda.
'
Dim value
As Object = row.Cells("Column1").Value
Dim d
As Decimal
Dim
bln
As Boolean =
Decimal.TryParse(Convert.ToString(value),
d)
' Si el valor alfanumérico no se puede convertir a
número,
' continuamos el bucle.
'
If (Not bln) Then Continue For
' Sumamos el valor.
'
resultado += Convert.ToDecimal(d)
Next
TextBox1.Text =
String.Format("{0:N2}", resultado)
Y los usuarios que prefieran utilizar LINQ (se necesita .NET 3.5 o superior), obtendrían la suma de una columna del control DataGridView de la siguiente manera:
Try
' Ejecutamos la consulta LINQ.
'
Dim query
As IEnumerable(Of
Object) = _
From row As
DataGridViewRow In
DataGridView1.Rows.Cast(Of
DataGridViewRow)() _
Where ( _
(row.Cells("Column1").Value
IsNot Nothing)
AndAlso _
(row.Cells("Column1").Value
IsNot DBNull.Value) _
) Select row.Cells("Column1").Value
' Obtenemos la suma.
'
Dim
resultado As Decimal = _
query.Sum(Function(row)
Convert.ToDecimal(row))
TextBox1.Text =
String.Format("Resultado:
{0:N2}", resultado)
Catch ex
As Exception
MessageBox.Show(ex.Message)
End Try
Si el control DataGridView no se encuentra enlazado a datos, hay que tener cuidado con los valores Nothing que puedan tener las celdas de las columnas. Pero si el control se encuentra enlazado a un objeto DataTable, entonces también hay que tener cuidado con los valores NULL. Tenga presente que un valor Nothing es distinto a los valores NULL de las bases de datos.
A partir de la versión 3.5 del marco de trabajo de .NET, podemos añadir nuevos métodos a las clases existentes, incluidas las del propio marco de trabajo de .NET.
Mediante lo que se conoce como métodos de extensión, podemos ampliar las clases ya existentes añadiéndole nuevos métodos, a los cuales llamaríamos de igual manera que llamamos a cualquier otro método de una clase, es decir, como si fuera otro método de instancia de una clase o tipo de dato existente.
Únicamente podemos definir como métodos de extensión, a los procedimientos Sub y Function, por tanto, estarían fuera del concepto los procedimientos de propiedad y evento, así como las definiciones de campo que se incluyan dentro de una clase (variables con ámbito de visibilidad a nivel de la propia clase donde se definen).
Todos los métodos de extensión, necesariamente tienen que estar marcados con el atributo Extension, el cual se encuentra incluido dentro del espacio de nombres System.Runtime.CompilerServices, por tanto, al comienzo del módulo importaríamos dicho espacio de nombres:
Imports System.Runtime.CompilerServices
Otro requisito que debe cumplir cualquier método de extensión, es que su primer parámetro siempre tiene que estar definido con el mismo tipo de dato de la clase que se desea extender. Si vamos a añadir a la clase DataGridView un método de extensión llamado SumColumn, su primer parámetro deberá estar definido como DataGridView. Pero si el método de extensión lo vamos a añadir a la clase DataTable, entonces su primer parámetro deberá estar definido del tipo DataTable. En definitiva, el primer parámetro del método de extensión define la clase a la cual se va añadir dicho método.
En Visual Basic .NET, los métodos de extensión necesariamente deben declararse dentro de un módulo con un ámbito de visibilidad Public; no pueden existir dentro de la definición de una clase. En C# sí se encuentran dentro de una clase, al igual que cualquier otro procedimiento, pero tanto el método de extensión como la propia clase, tienen que estar definidos como estáticos mediante el modificador static.
A continuación vamos a añadir cuatros métodos de extensión para sumar una columna cualquiera: dos métodos de extensión para el objeto DataTable, y otros dos para el control DataGridView:
Imports
System.Runtime.CompilerServices
Public
Module MetodosExtension
''' <summary>
''' Devuelve la
suma de los valores de una columna de un objeto DataTable.
''' </summary>
''' <param name="dt">Objeto
DataTable.</param>
''' <param name="columnName">El
nombre de la columna cuyos valores se desean sumar.</param>
''' <returns></returns>
''' <remarks></remarks>
<Extension()> _
Public
Function SumColumn(ByVal dt
As DataTable, _
ByVal columnName
As String)
As Decimal
Return dt.SumColumn(columnName, Nothing)
End Function
''' <summary>
''' Devuelve la suma de los valores de una columna de un objeto DataTable.
''' </summary>
''' <param name="dt">Objeto
DataTable.</param>
''' <param name="columnName">El
nombre de la columna cuyos valores se desean sumar.</param>
''' <param name="filter">Filtro que limitará las filas que se sumarán.</param>
''' <returns></returns>
''' <remarks></remarks>
<Extension()> _
Public
Function SumColumn(ByVal dt
As DataTable, _
ByVal columnName
As String, _
ByVal filter
As String)
As Decimal
If ((dt Is
Nothing) OrElse (String.IsNullOrEmpty(columnName)))
Then _
Return 0D
Try
Dim
expression
As String =
String.Format("Sum({0})", columnName)
Dim value
As Object =
Nothing
If (String.IsNullOrEmpty(filter))
Then
' Sumamos todas las filas.
'
value = dt.Compute(expression, Nothing)
Else
' Sumamos las filas que coincidan con el criterio
especificado.
'
value = dt.Compute(expression, filter)
End If
If (value Is
DBNull.Value) Then
Return 0D
Else
Return Convert.ToDecimal(value)
End If
Catch ex
As Exception
Return 0D
End
Try
End Function
''' <summary>
''' Devuelve la suma de los valores de una columna del control DataGridView.
''' </summary>
''' <param name="dgv">Control
DataGridView.</param>
''' <param name="columnName">El
nombre de la columna cuyos valores se desean sumar.</param>
''' <returns></returns>
''' <remarks></remarks>
<Extension()> _
Public
Function SumColumn(ByVal dgv
As DataGridView, _
ByVal columnName
As String)
As Decimal
Return dgv.SumColumn(columnName,
Nothing)
End Function
''' <summary>
''' Devuelve la
suma de los valores de una columna del control DataGridView.
''' </summary>
''' <param name="dgv">Control
DataGridView.</param>
''' <param name="columnName">El
nombre de la columna cuyos valores se desean sumar.</param>
''' <param name="selectedRows">Colección de filas que se sumarán.</param>
''' <returns></returns>
''' <remarks></remarks>
<Extension()> _
Public
Function SumColumn( _
ByVal dgv
As DataGridView, _
ByVal columnName
As String, _
ByVal selectedRows
As DataGridViewSelectedRowCollection)
As Decimal
If
((dgv Is Nothing)
OrElse (String.IsNullOrEmpty(columnName)))
Then _
Return 0D
Try
' Si no hay filas seleccionadas, indicamos la
intención de
' sumar todas las filas del control DataGridView.
'
If ((selectedRows
IsNot Nothing)
AndAlso _
(selectedRows.Count = 0)) Then _
selectedRows = Nothing
Dim query
As IEnumerable(Of
Object) = Nothing
If (selectedRows Is Nothing)
Then
' Se desea sumar todas las filas.
'
query = From row
As DataGridViewRow
In dgv.Rows.Cast(Of
DataGridViewRow)() _
Where ( _
(row.Cells(columnName).Value IsNot Nothing)
AndAlso _
(row.Cells(columnName).Value IsNot
DBNull.Value) _
) Select row.Cells(columnName).Value
Else
' Se desea sumar las filas seleccionadas.
'
query = From row
As DataGridViewRow
In dgv.Rows.Cast(Of
DataGridViewRow)() _
Where ( _
(row.Selected) AndAlso _
(row.Cells(columnName).Value IsNot Nothing)
AndAlso _
(row.Cells(columnName).Value IsNot
DBNull.Value) _
) Select row.Cells(columnName).Value
End If
' Devolvemos la suma.
'
Return query.Sum(Function(row)
Convert.ToDecimal(row))
Catch ex
As Exception
Return 0D
End Try
End Function
End Module
Para llamar a los métodos de extensión de un objeto DataTable que se encuentra enlazado a un control DataGridView, ejecutaría alguna de las siguientes líneas:
' Referenciamos el objeto DataTable enlazado con el
' control DataGridView.
'
Dim
dt As DataTable =
DirectCast(DataGridView1.DataSource,
DataTable)
' Sumamos todas las filas de la
columna Total.
'
Dim
resultado As Decimal = dt.SumColumn("Total")
TextBox1.Text = String.Format("{0:N2}",
resultado)
' Sumamos todas las filas de la columna
Total
' donde el campo Fecha esté comprendido entre el día
'
01/02/2011 y 28/02/2011.
'
resultado = dt.SumColumn("Total",
"Fecha >= #02/01/2011# And Fecha <= #02/28/2011#")
TextBox2.Text = String.Format("{0:N2}",
resultado)
Y para llamar a los métodos de extensión del control DataGridView para sumar una columna cualquiera, ejecutarías éstas otras líneas de código:
' Sumamos los valores de
todas las filas de la columna Column1.
'
Dim resultado
As Decimal = DataGridView1.SumColumn("Column1")
TextBox1.Text = String.Format("{0:N2}",
resultado)
' Sumamos los valores de la
columna Column1 cuyas filas estén seleccionadas.
'
resultado =
DataGridView1.SumColumn("Column1",
DataGridView1.SelectedRows)
TextBox2.Text =
String.Format("{0:N2}",
resultado)
Otros enlaces de interés:
Índice de la colección de ejemplos de las clases del marco de trabajo de .NET
Enrique Martínez Montejo - 2011
NOTA: La información contenida en este artículo, así como el código fuente incluido en el mismo, se proporciona COMO ESTÁ, sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo explicado, recomendado o sugerido en el presente artículo.
NOTE: The information contained in this article and source code included therein, is provided AS IS without warranty of any kind, and confers no rights. You assume any risk to implement, use or run it explained, recommended or suggested in this article.