【问题标题】:Calculating Sum - Datagridview's CellFormating event too slow performance计算总和 - Datagridview CellFormatting 事件性能太慢
【发布时间】:2019-02-20 09:19:03
【问题描述】:

我正在使用 dataGridView1_CellFormatting 对我的每一列进行求和。但这使我的 datagridview 滚动速度很慢。特别是当我有大量数据时。

 private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
    {

        Decimal sum = 0, sum2 = 0, sum3 = 0;
        for (int i = 0; i < CustomersGrid.Rows.Count; ++i)
        {

                sum += Convert.ToDecimal(CustomersGrid.Rows[e.RowIndex].Cells[7].Value);
                sum2 += Convert.ToDecimal(CustomersGrid.Rows[e.RowIndex].Cells[6].Value);
                sum3 += Convert.ToDecimal(CustomersGrid.Rows[e.RowIndex].Cells[8].Value);
        }

        Quantitytxt.Text = sum2.ToString() + "   ";
        Sumtxt.Text = string.Format("{0:0.00}", sum).Replace(",", ".") + "€" + "   ";
        DiscountSumtxt.Text = string.Format("{0:0.00}", sum3).Replace(",", ".") + "€" + "   ";

    }

有没有更有效的方法呢?仅当我将获得此单元格时才进行总和的示例?或者是否有任何其他事件或方法?我也试过这个。

 private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
    {

        Decimal sum = 0, sum2 = 0, sum3 = 0;
        for (int i = 0; i < CustomersGrid.Rows.Count; ++i)
        {
            if (e.ColumnIndex == 7 || e.ColumnIndex == 6 || e.ColumnIndex == 8)
            {
                sum += Convert.ToDecimal(CustomersGrid.Rows[e.RowIndex].Cells[7].Value);
                sum2 += Convert.ToDecimal(CustomersGrid.Rows[e.RowIndex].Cells[6].Value);
                sum3 += Convert.ToDecimal(CustomersGrid.Rows[e.RowIndex].Cells[8].Value);
            }
        }
        Quantitytxt.Text = sum2.ToString() + "   ";
        Sumtxt.Text = string.Format("{0:0.00}", sum).Replace(",", ".") + "€" + "   ";
        DiscountSumtxt.Text = string.Format("{0:0.00}", sum3).Replace(",", ".") + "€" + "   ";

    }

它看起来性能好一点,但是当我滚动我的 datagridview 时它仍然很慢。

【问题讨论】:

  • 你可以SumDataSource 上的值(*使用类似于 Linq *),然后将其提供给DataGridView。而不是对每个cell 进行操作。
  • CellFormatting 为每个单元格引发。每次需要格式化单元格内容时,您都在解析整个记录集。甚至没有修改。您可以在 DataSource 填充 DGV 时执行计算,然后在添加/删除行或更改 sensible 单元格的内容时执行计算。初始计数也可以由 SQL 执行。也许,也在之后。

标签: c# .net winforms datagridview


【解决方案1】:

documentations中已经提到:

每次绘制每个单元格时都会发生 CellFormatting 事件,因此 处理此事件时应避免冗长的处理。这 当检索到单元格 FormattedValue 或其 调用 GetFormattedValue 方法。

处理所有单元格的CellFormatting 对于计算Sum 来说太多了。

如果您使用DataSource (例如引发ListChanged 事件的DataTable)来计算Sum,则可以依赖ListChanged 事件。

作为另一种选择,您可以依靠DataGridViewRowsAddedRowsRemovedCellValueChanged 事件来计算Sum

示例 - 数据表 - 列的总和

DataTable 引发 ListChange 事件。您可以订阅更新文本框的事件:

private async void Form1_Load(object sender, EventArgs e)
{
    // Define data table
    var dt = new DataTable();
    dt.Columns.Add("Name");
    dt.Columns.Add("Price", typeof(int));

    // Fill data
    dt.Rows.Add("Product 1", 100);
    dt.Rows.Add("Product 2", 200);

    // Set data source of data grid view
    this.dataGridView1.DataSource = dt;

    // Automatically update text box, by SUM of price
    textBox1.Text = $"{dt.Compute("SUM(Price)", ""):F2}";
    dt.DefaultView.ListChanged += (obj, args) =>
        textBox1.Text = $"{dt.Compute("SUM(Price)", ""):F2}";
}

示例 - 列表 - 属性总和

List&lt;T&gt; 不会引发 ListChanged 事件。您可以使用BindingSource 作为数据源,并改为处理BindingSourceListChanged 事件:

public class Product
{
    public string Name { get; set; }
    public int Price { get; set; }
}

private async void Form1_Load(object sender, EventArgs e)
{
    // Define list
    var list = new List<Product>();

    // Fill data
    list.Add(new Product { Name = "Product 1", Price = 100 });
    list.Add(new Product { Name = "Product 2", Price = 200 });

    // Set data source of data grid view
    var bs = new BindingSource();
    bs.DataSource = list;
    this.dataGridView1.DataSource = bs;

    // Automatically update text box, by SUM of price
    textBox1.Text = $"{list.Sum(x => x.Price):F2}";
    bs.ListChanged += (obj, args) =>
        textBox1.Text = $"{list.Sum(x => x.Price):F2}";
}

【讨论】:

    【解决方案2】:

    昨天我解决了滚动时滞后DataGridView 的问题。 在.NET 中有DataGridViewDoubleBuffered 属性,但由于某些未知原因,它被隐藏了。 您可以通过ReflexionDataGridView编写扩展方法来启用它。

    public static class ExtensionMethods
    {
        public static void DoubleBuffered(this DataGridView dgv, bool setting)
        {
            Type dgvType = dgv.GetType();
            PropertyInfo pi = dgvType.GetProperty("DoubleBuffered",
                BindingFlags.Instance | BindingFlags.NonPublic);
            pi.SetValue(dgv, setting, null);
        }
    }
    

    将此代码放在项目中的某个位置,并在初始化表单后,将属性DoubleBuffered 设置为true

    dataGridView1.DoubleBuffered(true);
    

    DataGridView 的表现帮助了我很多。希望对你有帮助。

    【讨论】:

    • 如果您有一个每N 秒(与 UI 相关)刷新 DGV 内容的计时器,这可能会有所帮助。不适用于解析/计算值。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-22
    • 2012-02-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多