C# 如何在文本框中动态获取datagridview列的总和

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19963074/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 16:14:50  来源:igfitidea点击:

how to get sum dynamically of datagridview column in textbox

c#winformsdatagridviewtextboxtextchanged

提问by Haider Khattak

I want to get the sum of a column of datagridview and show that in textbox. After each entry the sum should be changed dynamically. For that I am using textChanged event of a textbox but when the entry is made it does not show any result. I want to get the result dynamically in the textbox. I want to avoid the use of button for sum.

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

Here is a piece of code for the textbox textChanged event:

这是文本框 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();
        }

采纳答案by sab669

You've got your code right, but instead I've put it in the CellValueChanged event and check to make sure it was the same cell you're looking for. This will get fired if the cell's value changes, or if a new row is added and subsequently gets a value assigned.

你的代码是正确的,但我把它放在 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;
    }

I split up your logic into a separate method, so incase you ever want to get the sum for something else, you can simply call that method. I suppose you could just read textbox.Text, but...

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

I've also used Double.TryParse as it provides some basic protection incase the value in that given cell is not actually a number. I don't know what the source of the data is (user entered / from an outside source?) so I figured I'd add a little protection.

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

EditGrant raises a great point, editted my solution to include cell value being modified. I used the CellValueChanged event instead of CellEndEdit, incase something other than the user can change its value.

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

回答by vivat pisces

If you need to take into account the possibility that a user may edit existing values in the grid rows, you can subscribe to the CellEndEditevent.

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

Here, I'm checking the column index so you're not recalculating the sum if any other unrelated columns are edited. (I'm also validating the input and setting the value to 0 if, say, someone enters letters.)

在这里,我正在检查列索引,因此如果编辑了任何其他不相关的列,您就不会重新计算总和。(我也在验证输入并将值设置为 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();
    }
}

Others may have better solutions... this is just one possibility.

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

回答by King King

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 trackyour 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.

您必须处理该事件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());
  }
}

NOTE: I suppose the column you want to sum up is named sumColumn, we should use Nameto 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 sumeasily right before adding and removing. For adding we can handle the RowsAddedevent. All the following event handler registrations should be placed in some Form.Loadevent handler:

注意:我想您要总结的列名为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();
};

However for removing rows, it's very tricky. The RowsRemoveddoesn't work well, we can't refer the removed rows anymore in the RowsRemovedevent handler, so we may have to loop through all the rows and update the sum:

但是对于删除行,这是非常棘手的。该RowsRemoved工作不正常,我们不能再参考删除的行中RowsRemoved所有的行记录的事件处理程序,所以我们可能要循环和更新的总和:

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 sumbefore any code removing the rows, here it is:

这是用于通过代码和用户删除行。另一个更好的选择是您必须处理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();
}

Note that all the event handlersshould be registered afteryour grid has been initialized with some initial data following by the suminitialization.

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

回答by ???? ???????

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

回答by Rufuss Carnegie

this is the best simple way :

这是最好的简单方法:

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