4

我想得到一列 datagridview 的总和并在文本框中显示。每次输入后,总和应动态更改。为此,我正在使用文本框的 textChanged 事件,但是当输入时它不显示任何结果。我想在文本框中动态获取结果。我想避免使用按钮进行求和。

这是文本框 textChanged 事件的一段代码:

private void textBox9_TextChanged(object sender, EventArgs e)
        {
            double sum = 0;
            for (int i = 0; i < dataGridView2.Rows.Count; ++i)
            {
                sum += Convert.ToDouble(dataGridView2.Rows[i].Cells[5].Value);
            }
            textBox9.Text = sum.ToString();
        }
4

5 回答 5

9

你的代码是正确的,但是我把它放在 CellValueChanged 事件中并检查以确保它是你正在寻找的同一个单元格。如果单元格的值发生更改,或者添加新行并随后获得分配的值,这将被触发。

    private void dataGridView2_CellValueChanged(object sender, DataGridViewCellEventArgs e)
    {
        if (e.ColumnIndex == 5)
            textBox9.Text = CellSum().ToString();
    }

    private double CellSum()
    {
        double sum = 0;
        for (int i = 0; i < dataGridView2.Rows.Count; ++i)
        {
            double d = 0;
            Double.TryParse(dataGridView2.Rows[i].Cells[5].Value.ToString(), out d);
            sum += d;
        }
        return sum;
    }

我将您的逻辑拆分为一个单独的方法,因此如果您想获得其他东西的总和,您可以简单地调用该方法。我想您可以只阅读 textbox.Text,但是...

我还使用了 Double.TryParse,因为它提供了一些基本保护,以防给定单元格中的值实际上不是数字。我不知道数据的来源是什么(用户输入/来自外部来源?)所以我想我会添加一些保护。

编辑格兰特提出了一个很好的观点,编辑了我的解决方案以包括正在修改的单元格值。我使用了 CellValueChanged 事件而不是 CellEndEdit,以防用户以外的东西可以改变它的值。

于 2013-11-13T20:13:12.740 回答
3

这是最好的简单方法:

private void your_name()
{

    Double your_variable = dataGridView1.Rows.Cast<DataGridViewRow>().Sum(x => Convert.ToDouble(x.Cells["Column4"].Value));

    this.textBox1.Text = your_variable.ToString("N2");
}
于 2014-08-09T01:02:10.183 回答
2

如果您需要考虑用户可能编辑网格行中现有值的可能性,您可以订阅该CellEndEdit事件。

在这里,我正在检查列索引,因此如果编辑了任何其他不相关的列,您就不会重新计算总和。(如果有人输入字母,我也会验证输入并将值设置为 0。)

private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
    if (e.ColumnIndex == 5)
    {
        decimal result;
        if (!Decimal.TryParse(Convert.ToString(dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value), out result))
            dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = 0;

        textBox1.Text = dataGridView1.Rows.Cast<DataGridViewRow>()
                                     .Sum(x => Convert.ToDecimal(x.Cells[5].Value))
                                     .ToString();
    }
}

其他人可能有更好的解决方案……这只是一种可能性。

于 2013-11-13T20:14:38.650 回答
1

你必须处理事件CellValueChanged。但是,您的方法有点糟糕,因为每次单元格的值发生变化时,您都必须遍历所有行以更新总和。您应该跟踪您的单元格更改以存储最后一个值,然后您可以轻松更新总和。最初需要使用循环计算总和。刚做了1次。

//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());
  }
}

注意:我想你要总结的列是命名sumColumn的,我们应该使用Name引用列,因为它更具可读性。上面的代码不计算添加新行和从网格中删除现有行的情况。事实上,无论何时以编程方式添加和删除,您都应该sum在添加和删除之前轻松更新。对于添加,我们可以处理RowsAdded事件。以下所有事件处理程序注册都应放置在某个Form.Load事件处理程序中:

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();
};

但是对于删除行,这是非常棘手的。RowsRemoved效果不好,我们不能再在事件处理程序中引用已删除的行,RowsRemoved因此我们可能必须遍历所有行并更新总和:

dataGridView1.RowsRemoved += (s, e) => {
  sum = InitSum(dataGridView1,"sumColumn");
  textBox9.Text = sum.ToString();      
};

这是为了按代码和用户删除行。另一个更好的选择是您必须处理UserDeletingRow(但这仅适用于按用户删除行,而不是按代码)。要通过代码处理删除行,我认为您始终可以sum在删除行的任何代码之前插入更新代码,这里是:

//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();
}

请注意,所有事件处理程序都应在您的网格初始化注册,并在初始化之后使用一些初始数据sum

于 2013-11-13T20:49:21.377 回答
1
private void dataGridView2_CellEndEdit(object sender, DataGridViewCellEventArgs e)
    {
        if (e.ColumnIndex == 5)
        {
            summition();
        }
    }
    void summition() 
    { 
        double sum = 0;
        foreach (DataGridViewRow row in dataGridView2.Rows)
        {
            if(!row .IsNewRow )
                sum += Convert.ToDouble(row.Cells [5].Value .ToString () );
        }


        textBox9.Text = sum.ToString();
    }
于 2013-11-13T20:51:40.523 回答