【问题标题】:CellFormatting event in C# is really slowC# 中的 CellFormatting 事件真的很慢
【发布时间】:2012-02-01 11:23:14
【问题描述】:

我一直在为 CellFormatting 事件苦苦挣扎,它太慢了。

我有一个类似这样的 DataGridView:

我编写了一个函数,当您单击标题中的复选框时会触发它,它会使所有复选框都选中该列....

private void checkboxHeader_CheckedChanged(object sender, EventArgs e)
    {
        for (int i = 0; i < dataGridView1.RowCount; i++)
        {
            dataGridView1[0, i].Value = ((CheckBox)dataGridView1.Controls.Find("checkboxHeader", true)[0]).Checked;
        }
        //dataGridView1.EndEdit();
    }  

当我有 10 行之类的东西时,这个功能可以正常工作,但是当我有 300 行时,我应该有一些东西......有一个像 9 秒的延迟来检查所有复选框,我发现这是由于 CellFormating 事件。

我的 CellFormating 事件代码是:

private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {

            DataGridViewCellStyle _myStyle = new DataGridViewCellStyle();
            int index = gdv_row.FindIndex(p => p.log == (string)dataGridView1.Rows[e.RowIndex].Cells[1].Value);
            if (index != -1 && dataGridView1.Columns[e.ColumnIndex] is DataGridViewTextBoxColumn && e.RowIndex != -1)
            {
                //e.CellStyle = _myStyle;
                _myStyle.Font = gdv_row[index].font;
                _myStyle.BackColor = gdv_row[index].backgroundcolor_color;
                _myStyle.ForeColor = gdv_row[index].foregroundcolor_color;
                dataGridView1.Rows[e.RowIndex].Cells[1].Style = _myStyle;
            }
        }

我用过DoubleBuffering for DataGridView。现在我不知道该怎么处理这个 CellFormatting 事件......

【问题讨论】:

    标签: c# performance cell-formatting


    【解决方案1】:

    您是否已经尝试过SuspendLayout()ResumeLayout()

    这会暂时暂停控件的布局逻辑,以便在填充网格时不会重绘网格。

    如果您使用 DoubleBuffering,Grid 仍然会重新排列自己,这仍然很慢。但是,如果您在填充网格时根本不重绘,这应该会带来显着的提升。

    您的第一个函数可能如下所示:

    private void checkboxHeader_CheckedChanged(object sender, EventArgs e)
        {
            dataGridView1.SuspendLayout();
    
            for (int i = 0; i < dataGridView1.RowCount; i++)
            {
                dataGridView1[0, i].Value = ((CheckBox)dataGridView1.Controls.Find("checkboxHeader", true)[0]).Checked;
            }
    
            dataGridView1.ResumeLayout();
        }  
    

    [编辑 1]

    添加了代码示例。

    [编辑 2] 为了尽量减少对行的必要绘制,不要为每一行创建一个新的DataGridViewCellStyle 对象,而是尝试直接设置现有样式的属性:

        private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            int index = gdv_row.FindIndex(p => p.log == (string)dataGridView1.Rows[e.RowIndex].Cells[1].Value);
            if (index != -1 && dataGridView1.Columns[e.ColumnIndex] is DataGridViewTextBoxColumn && e.RowIndex != -1)
            {
                dataGridView1.Rows[e.RowIndex].Cells[1].Style.Font = gdv_row[index].font;
                dataGridView1.Rows[e.RowIndex].Cells[1].Style.BackColor = gdv_row[index].backgroundcolor_color;
                dataGridView1.Rows[e.RowIndex].Cells[1].Style.ForeColor = gdv_row[index].foregroundcolor_color;
            }
        }
    

    最后,寻找一些解决方案,我找到了这个 MSDN 文章文档: Best Practices for Scaling the Windows Forms DataGridView Control

    [编辑 3](以下回应 Ehsan 的评论)

    这是因为“a”是一个立即显示在网格中的值,而原始行做了一些重要的工作: * 搜索所需的值,包括所有子控件 * 使用找到的结果创建一个数组 * 将对象转换为 CheckBox * 它对网格中的每一行都执行所有这些操作

    很明显,DataGridView 中的项目越多,这就越耗时。

    如果我正确理解了您的代码,它应该可以帮助您将方法更改为:

      CheckBox headerBox = ((CheckBox)dataGridView1.Controls.Find("checkboxHeader", true)[0]);
      for (int i = 0; i < dataGridView1.RowCount; i++)
      {
        dataGridView1[0, i].Value = headerBox.Checked;
      }
    

    通过这样做,您只需执行一次搜索。

    【讨论】:

    • SuspendLayout 会在您在表单上添加新对象时为您提供帮助。根据 MSDN,SuspendLayout Temporarily suspends the layout logic for the control.
    • 感谢您的回复,由于我不知道如何使用这些功能以及在哪里使用,请您提供更详细的答案或类似的答案吗?
    • 实际上我按照你说的做了,但即使我看到更多延迟,仍然有延迟!但我该怎么办?你认为也许 dataGridView1[0,i] 有一些错误并导致延迟?:(
    • 当您使用函数获取控件时,如果您要多次使用它,则应始终将其存储到变量中(对于组合框来说,内存不会成为问题)。跨度>
    • @Sensei76:在您的第三次编辑中,它应该是 CheckBox headerBox = ((CheckBox)dataGridView1.Controls.Find("checkboxHeader", true)[0]); (去掉末尾的“.Checked”)
    【解决方案2】:

    如果您想在检查所有行时停止绘制控件,您应该查看以下帖子中的 DrawingControl 类:https://stackoverflow.com/questions/487661/...

    【讨论】:

      【解决方案3】:

      在我的情况下,问题是由 DataGridView 属性 AutoSizeColumnsMode=AllCells 引起的。可能在单元格格式化后,列和标题单元格中的所有其他单元格必须重新绘制以使其尺寸适合新的单元格尺寸。在我将属性值更改为默认值“无”后,立即绘制网格。

      【讨论】:

        猜你喜欢
        • 2012-11-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-11-10
        • 2010-12-28
        • 2013-01-25
        • 1970-01-01
        相关资源
        最近更新 更多