DataGridView性能与BindingList数据源结合使用

时间:2012-05-08 07:54:38

标签: c# performance datagridview drawing bindinglist

我正在构建一个必须显示从外部系统接收的数据的应用程序。这些数据可以非常快速地进入,而每行占用的字节数相对较小。这意味着每个时间单元必须添加许多行。我目前正处于这样一个阶段:我收到数据的速度比我能处理的速度快,这意味着我的内存使用率正在上升。

我认为这很大一部分与绘制实际的dataGridView有关。我对dataGridView做了一些调整,希望它能提高性能。 (例如禁用自动尺寸,特殊样式等)

在最近的一次添加中,我添加了行的颜色,这是必需的。目前我的申请表如下:

  1. 我从外部系统接收数据
  2. 我通过线程
  3. 将数据放入队列(ConcurrencyQueue)
  4. 另一个线程从该队列获取数据,处理它并将其添加到绑定到该表的BindingList。
  5. 实际添加发生在具有2个参数的函数中: 1.包含列(项目)项目的列表 2.行的颜色。(颜色)

    它看起来如下(半伪):

    /* Store the color for the row in the color list so it is accessible from the event */  
    
    rowColors.Add(rowColor);    //Class variable that stored the colors of the rows used in the DataGridCellFormatting event
    
    /* Create the row that is to be added. */
    ResultRow resultRow = new ResultRow();
    
    foreach(item in items)
    {
        resultRow.Set(item); /* It's actually a dictionary because some fields are optional, hence this instead of a     direct constructor call) */
    }
    
    bindingList.Add(resultRow);
    
    /* Row coloring based on error is done in the OnCellFormatting() */
    
    
    /* Auto scroll down */
    if (dataGrid.Rows.Count > 0)
    {
        dataGrid.FirstDisplayedScrollingRowIndex = dataGrid.Rows.Count - 1;
    }
    

    如上面的代码所示,我收到的颜色被添加到List中,该列表在datagridview的事件中使用,如下所示:

    void DataGridCellFormattingEvent(object sender, DataGridViewCellFormattingEventArgs e)
    {
        // done by column so it happens once per row
        if (e.ColumnIndex == dataGrid.Columns["Errors"].Index)
        {
            dataGrid.Rows[e.RowIndex].DefaultCellStyle.BackColor = rowColors[e.RowIndex];
    }
    } 
    

    BindingList定义如下:

    BindingList bindingList;

    其中ResultRow是一个具有如下结构的类:

    public class ResultRow
    {
        private int first = 0;
        private string second = "";
        private UInt64 third = 0;
        private IPAddress fourth = null;
        //etc
    
        public ResultRow()
        {
        }
    
        public void Set (<the values>) //In actuallity a KeyValuePair
        {
            //field gets set here
        }
    
        public UInt64 Third
        {
            get { return third; }
            set { third = value; }
        }
    
        /* etc. */
    

    我可以做些相对简单的事情来提高性能吗?我想在处理繁忙时可能会禁用数据网格的绘制,并在完成时绘制。 (虽然不是首选)另一件事可能是更少频繁更新,而不是在每个收到的项目之后。 (但是,当添加内容时,BindingList似乎会自动更新DataGridView)

    我希望有人愿意/能够提供帮助。

    -edit -

    表单的响应性,因为当它以上述方式处理数据时非常糟糕,特别是在一段时间之后。 (即使上述过程发生在backgroundworker和后台线程中)

2 个答案:

答案 0 :(得分:5)

由于网格中的行数很多,性能可能会在一段时间后下降。你应该试试Virtual Mode

但首先,尝试推迟网格的更新并批量添加新条目,即降低更新频率。因此,在每次批量更新之前:

// stop raising update events
bindingList.RaiseListChangedEvents = false; 

之后:

// restore update events, raise reset event
bindingList.RaiseListChangedEvents = true;
bindingList.ResetBindings() 

在最后一行继续滚动到最后一行之后。

答案 1 :(得分:0)

是的,你可以采取一些措施加快速度。

首先 - 虚拟化数据网格。这是winforms数据网格的内置机制,它只会填充行并为可见的数据项绘制客户端区域。因此,如果您的控件仅显示20行(以及其他行的滚动条),则实际上只有20个项目作为UI处理到数据网格中。 然后,当您滚动网格以查看其他项时,datagrid将按需填充并显示请求的行。 您需要对此进行一些修改(需要订阅CellValueNeeded事件),您可能需要编辑绑定源数据项。 有关详细信息,请参阅http://msdn.microsoft.com/en-us/library/ms171622.aspx

您可以做的第二件事是在填充数据的“块”时暂停UI更新。 正如您已经指出的那样,bindinglist会在您向其添加项目时自动更新网格。但是,通过暂停UI更新,然后以特定间隔(比如每秒)重新启用,您将以较低的速率流式传输数据。 但请注意,仍然需要对数据进行相同的处理,因此这不太可能完全解决您的数据,并且可能更有效地减少屏幕闪烁。 有关详细信息,请参阅Control.SuspendLayout()Control.ResumeLayout()

在我看来,虚拟化将是您最有效的工具,因为它的唯一目的是改善非常大的数据集的网格功能。