3

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

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

在最近的一次添加中,我添加了行的着色,这是必需的。目前我的应用程序工作如下:

  1. 我从外部系统接收数据
  2. 我通过一个线程将数据放在一个队列(ConcurrencyQueue)中
  3. 另一个线程从该队列中获取数据,对其进行处理并将其添加到绑定到表的 BindingList 中。

实际添加发生在具有 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;
}

如上面的代码所示,我收到的颜色被添加到一个列表中,该列表用于 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 定义如下:

绑定列表绑定列表;

其中 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)

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

-编辑-

当它以上述方式处理数据时,尤其是在一段时间之后,表单的响应能力也很差。(即使上述过程发生在后台工作人员和后台线程中)

4

2 回答 2

5

由于网格中的行数过多,性能可能会在一段时间后下降。你应该试试虚拟模式。

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

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

之后:

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

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

于 2012-05-08T08:25:02.980 回答
0

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

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

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

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

于 2012-05-08T08:18:55.873 回答