2012-05-08 32 views
3

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

我认为这很大一部分与绘制实际的dataGridView有关。我已经对dataGridView做了小小的调整,希望它能够提高性能。 (例如,禁用自动大小,特殊风格等)

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

  1. 我由一个线程
  2. 另一个线程从队列中获取数据从外部系统
  3. 我将数据放在一个队列(ConcurrencyQueue)接收数据,处理它,将其添加到绑定到表的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定义如下:

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时,虽然有东西)

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

CNC中

形式的响应,因为相当糟糕,以及当它在处理上述数据的方式,尤其是在一段时间后。 (即使上述过程发生在后台工作程序和后台线程中)

回答

0

是的,有几件事情可以加快速度。

首先 - 虚拟化数据网格。这是一种内置于Winforms数据网格的机制,它只填充行并为客户区绘制可见的数据项。因此,如果你的控件只显示20行(而其他的滚动条),那么实际上只有20个项目被作为UI处理到数据网格中。 然后,当您滚动网格查看其他项目时,数据网格按需填充并显示请求的行。 您需要做一些修补(CellValueNeeded事件需要订阅),您可能需要编辑绑定源数据项。 有关更多信息,请参阅http://msdn.microsoft.com/en-us/library/ms171622.aspx

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

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

+0

我已经在我的数据网格中应用了挂起/恢复机制。起初这并没有太多帮助。我现在已经创建了一个新的后台工作负责人,负责在相当大的时间间隔内更新数据网格,并为这些数据网格提供帮助。 (但更多的线程和更多的调用,不知道这是否是一件好事..)我实际上碰到了刚刚在数据加载文章之前,它似乎很复杂,所以我希望不必这样做。这个例子也是基于数据库的,所以我不能直接应用它。但我想我将不得不试图找出进一步提高性能的方法。 – Arnold4107176

+0

很高兴帮助。毫无疑问,MSDN教程并不总是最有帮助的。 http://www.codeproject.com/Articles/23937/Paging-Data-with-DataGridView-in-VirtualMode是一个更好的资源,它不是有史以来最好的codeproject文章,但应包含正确的信息。虚拟化相对简单,如果您努力通过CellValueNeeded为网格提供数据对象属性,那么您将立即开始运行。 –

+0

这似乎很容易理解。我确实感觉这篇文章缺少一些信息,但是它能够正常工作。我目前实现它,但我的数据网格保持空白。我在这里发布了我的问题的详细信息:http://stackoverflow.com/questions/10512981/datagridview-virtual-mode-with-a-simple-list-as-a-source – Arnold4107176

3

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

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

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

而且算账:

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

最后一行之后进行带滚动到最后一行。