2013-11-13 3 views
4

Я хочу получить сумму столбца datagridview и показать это в текстовом поле. После каждой записи сумма должна быть изменена динамически. Для этого я использую событие textChanged текстового поля, но когда запись выполнена, он не показывает никакого результата. Я хочу получить результат динамически в текстовом поле. Я хочу избежать использования кнопки для суммы.Как получить динамическую динамику столбца datagridview в текстовом поле

Вот кусок кода для текстового поля 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(); 
     } 
+0

Если вы хотите, чтобы обновить значение в 'TextBox', когда строка добавляется в' DataGridView', это не имело бы больше смысла попытаться подключиться к событию на сетке? –

+1

Если вы хотите обновить его в текстовом поле? 'TextChanged' не является правильным местом –

+0

Я хочу, чтобы textBox9 автоматически вычислял сумму независимо от того, сколько строк в Datagridview ... –

ответ

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, выставляя что-то другое, кроме того, что пользователь может изменить его значение.

+0

Это сработало, но когда первая запись сделана, в текстовое поле отображается значение 0, а не значение записи ... при отправке записи в текстовое поле отображается значение первой записи, когда третий добавляется ... как будто это на 1 шаг ниже ... –

+0

@HaiderKhattak Я считаю, что это было потому, что общая сумма сгенерировалась * до * ячейка имела значение. Если вы поместите контрольную точку в цикл for, вы можете сами проверить свойство Value. Я также изменил свой код на ** только **, полагаясь на событие CellValueChanged, которое может быть лучше. Попробуйте это вместо этого. – sab669

+0

извините, я не обновил страницу и не видел изменений в коде ... ну, теперь это сработало ... спасибо ... –

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

Другие могут иметь лучшие решения ... это только одна возможность.

+0

, это не сработает, если значение Cell изменилось ** кодом **. –

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.

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

Это действительно менее сложная вариация ответа Гранта. Он по-прежнему восприимчив к проблеме, о которой говорил Кинг Кинг (что, если значение изменяется программно?). Мой ответ решает эту проблему, но, как он снова указал, мое решение становится медленнее, потому что оно запускается для каждой ячейки подряд при добавлении новой строки. Вы по крайней мере разбиваете логику на отдельный метод, но также чувствительны к недвойственным типам в ячейке. – sab669

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

Почему это лучший простой способ? Объяснение – rayryeng

+0

Rufuss - Это помогает очень и очень просто, потому что вам нужно просто вызвать этот метод внутри метода загрузки Grid. –

 Смежные вопросы

  • Нет связанных вопросов^_^