You have to handle the event CellValueChanged
. However your approach is a little bad because each time a cell's value changes, you have to loop through all the rows to update the sum. You should track your cell change to store the last value, then you can update the sum easily. The sum needs to be calculated initially using the loop. It's just done 1 time.
//This is used as CellTemplate for your interested column
public class TrackedValueDataGridViewCell : DataGridViewTextBoxCell {
public object OldValue { get; set; }
protected override bool SetValue(int rowIndex, object value) {
OldValue = Value;
return base.SetValue(rowIndex, value);
}
}
public partial class Form1 : Form {
public Form1(){
InitializeComponent();
//init your grid
dataGridView1.DataSource = yourDataSource;
dataGridView1.Columns["sumColumn"].CellTemplate = new TrackedValueDataGridViewCell();
sum = InitSum(dataGridView1,"sumColumn");
textBox9.Text = sum.ToString();
dataGridView1.CellValueChanged += (s,e) => {
if(dataGridView1.Columns[e.ColumnIndex].Name != "sumColumn") return;
var cell = ((TrackedValueDataGridViewCell) dataGridView1[e.ColumnIndex, e.RowIndex]);
sum -= ((double?) cell.OldValue).GetValueOrDefault();
sum += ((double?)cell.Value).GetValueOrDefault();
textBox9.Text = sum.ToString();
};
}
double sum;
public double InitSum(DataGridView grid, string colName) {
return grid.Rows.OfType<DataGridViewRow>()
.Sum(row => ((double?) row.Cells[colName].Value).GetValueOrDefault());
}
}
NOTE: I suppose the column you want to sum up is named sumColumn
, we should use Name
to reference column because it's more readable. The code above doesn't count the cases when adding new rows and removing existing rows from grid. In fact, whenever adding and removing programmatically, you should update the sum
easily right before adding and removing. For adding we can handle the RowsAdded
event. All the following event handler registrations should be placed in some Form.Load
event handler:
dataGridView1.RowsAdded += (s, e) => {
for (int i = e.RowIndex; i < e.RowIndex + e.RowCount; i++) {
sum += ((double?)dataGridView1["sumColumn", i].Value).GetValueOrDefault();
}
textBox9.Text = sum.ToString();
};
However for removing rows, it's very tricky. The RowsRemoved
doesn't work well, we can't refer the removed rows anymore in the RowsRemoved
event handler, so we may have to loop through all the rows and update the sum:
dataGridView1.RowsRemoved += (s, e) => {
sum = InitSum(dataGridView1,"sumColumn");
textBox9.Text = sum.ToString();
};
That's for removing rows by both code and user. Another option which is better is you have to handle the UserDeletingRow
(but this works only for removing rows by user, not by code). To handle removing rows by code, I think you can always insert code updating the sum
before any code removing the rows, here it is:
//for user removing rows
dataGridView1.UserDeletingRow += (s, e) => {
sum -= ((double?) e.Row.Cells["sumColumn"].Value).GetValueOrDefault();
textBox9.Text = sum.ToString();
};
//for code removing rows, use some method to remove rows like this:
public void RemoveRows(DataGridView grid, int startIndex, int count){
for(int i = startIndex; i <= startIndex + count; i++){
//update the sum first
sum -= ((double?)grid.Rows[i].Cells["sumColumn"].Value).GetValueOrDefault();
//then remove the row
grid.Rows.RemoveAt(startIndex);
}
textBox9.Text = sum.ToString();
}
Note that all the event handlers should be registered after your grid has been initialized with some initial data following by the sum
initialization.