Total a column in a .NET WinForms DataGrid
One way is to loop through rows in the grid and sum the values for the column of
interest. This is what the code below does. It then displays the total in a
label control. The code assumes column 1 in our datagrid contains a decimal
value to be totalled.
There are a few tricks to watch for. If the grid is not read only the user can
edit a cell in the column you are summing and change its value. You need to
react to the underlying textbox's TextChanged event
and keep your total accurate as the user is editing the data. To do this I use
a GridTableStyle to format the DataGrid and hook
into the TextChanged event for the DataGridTextBoxColumn
associated with the column. When this event fires the AmountChanged handler
is invoked to total the values.
When the grid is initially populated and when deleting and inserting rows the
total also needs to be adjusted. In these cases you must also call the AmountChanged
routine.
The AmountChanged method loops through the grid, pulls the values from
it, and sums them. If the cell is being edited the value will not yet be
available in the DataGrid so you it is retrieved from the DataGridTextBoxColumn
tied to the cell. On deletes and inserts special processing is also required.
You can inform AmountChanged how it was called by passing in different
values for its sender parameter.
Lastly, before summing the value we must test that it is numeric. The IsDecimal
function accomplishes this.
. . .
// Code to format the grid.
// Create a GridTableStyle.
DataGridTableStyle aGridTableStyle = new DataGridTableStyle();
aGridTableStyle.MappingName = "MyTable";
// Create a TextBox GridColumnStyle.
DataGridTextBoxColumn aCol1 = new DataGridTextBoxColumn();
aCol1.MappingName = "MyAmount";
aCol1.Alignment = HorizontalAlignment.Left;
aCol1.TextBox.Enabled = true;
aGridTableStyle.GridColumnStyles.Add(aCol1);
// Add the GridColumnStyle to the Table Style.
dataGrid.TableStyles.Add(aGridTableStyle);
// Hook into the TextChanged event.
DataGridTextBoxColumn tbc = (DataGridTextBoxColumn)aGridTableStyle.GridColumnStyles[1];
tbc.TextBox.TextChanged += new EventHandler(AmountChanged);
. . .
private void AmountChanged (object sender, EventArgs e)
{
// Get the number of rows in the grid.
int numRows = dataGrid.BindingContext[dataGrid.DataSource, dataGrid.DataMember].Count;
double dblAmt = 0;
string strAmt = "";
// Sum the amount on each row.
for (int i = 0; i < numRows; i++)
{
// Use the amount from the datagrid.
strAmt = dataGrid[i, 1].ToString();
//
// If called from the TextChanged event of a TextBox in the
// DataGrid corresponding to a cell that is currently being
//edited the value will not be available in the grid yet.
// Get it from the textbox.
//
if ((sender.ToString().ToUpper().IndexOf("TEXTBOX") > 0) &&
(i == dataGrid.CurrentRowIndex))
{
// If the cell is being edited the value will not be
// available in the grid yet. Get it from the textbox.
DataGridColumnStyle dgc =
dataGrid.TableStyles[0].GridColumnStyles[1];
DataGridTextBoxColumn aTxt = (DataGridTextBoxColumn) dgc;
strAmt = aTxt.TextBox.Text;
}
// If the value is not numeric don't add it.
if (IsDecimal(strAmt) == false)
strAmt = "0";
dblAmt += Convert.ToDouble(strAmt);
}
lblTotal.Text = dblAmt.ToString();
}
After the grid is initially populated and when a rows is deleted you can call
the AmountChanged methods like this:
AmountChanged("GridLoaded", e);
. . .
AmountChanged("DeleteDataRow", e);
Here is the routine to test for decimal values.
public static bool IsDecimal(string theValue
{
try
{
Convert.ToDouble(theValue);
return true;
}
catch
{
return false;
}
} //IsDecimal
|