难道Windows窗体DataGridView实现真正的虚拟模式? [英] Does the Windows Forms DataGridView implement a true virtual mode?

查看:127
本文介绍了难道Windows窗体DataGridView实现真正的虚拟模式?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个包含目前是1万行,将随时间而增加一个SQL表。

I have a SQL table containing currently 1 million rows that will grow over time.

有一个具体的用户需求呈现显示所有行,而不可排序网格分页。用户希望能够通过使用滚动条非常迅速地从行到行及顶部跳到底部。

There is a specific user requirement to present a sortable grid that displays all rows without paging. The user expects to be able to very quickly jump from row to row and top to bottom by using the scrollbar.

我所熟悉的虚拟模式网格只呈现整体数据的可视子集。他们可以提供出色的UI性能和最低内存要求,(我甚至实现使用这种技术多年前的应用程序)。

I am familiar with "virtual mode" grids that only present a visible subset of the overall data. They can provide excellent UI performance and minimal memory requirements, (I've even implemented an application using this technique many years ago).

Windows窗体DataGridView提供了一个虚拟模式这看起来应该是答案。但是不像其他的虚拟模式,我遇到了,但它仍然分配内存的每一行(在ProcessExplorer确认)。显然,这将导致总的内存使用,以不必要大大增加,并且同时分配这些行,有一个明显的延迟。滚动的表现也受到1亿多行。

The Windows Forms DataGridView provides a virtual mode that looks like it should be the answer. However unlike other virtual modes I've encountered, it still allocates memory for every row (confirmed in ProcessExplorer). Obviously this causes overall memory usage to needlessly greatly increase and, while allocating these rows, there is a noticeable delay. Scrolling performance also suffers on 1 million + rows.

一个真正的虚拟模式就没有必要分配不显示的行的内存。你只要给它的总行数(例如1,000,000)和所有的网所做的是相应的缩放滚动条。当它第一次显示网格只是数据请求的前n(比方说30)仅可见行,瞬时显示。

A real virtual mode would have no need to allocate any memory for rows not being displayed. You just give it the total row count (eg 1,000,000) and all the grid does is scale the scrollbar accordingly. When it is first displayed the grid simply asks for data the first n (say 30) visible rows only, instantaneous display.

当用户滚动发车,一个简单的排,偏移和提供可见的行数,可用于检索数据存储中的数据

When the user scrolls the grid, a simple row offset and the number of visible rows are provided and can be used to retrieve data from the data store.

下面是我目前使用DataGridView的代码示例:

Here's an example of the DataGridView code I'm currently using:

public void AddVirtualRows(int rowCount)
{
    dataGridList.ColumnCount = 4;


    dataGridList.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None;
    dataGridList.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.None;

    dataGridList.VirtualMode = true;

    dataGridList.RowCount = rowCount;

    dataGridList.CellValueNeeded += new DataGridViewCellValueEventHandler(dataGridList_CellValueNeeded);


}
void dataGridList_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e)
{
    e.Value = e.RowIndex;
}



我在这里缺少什么,或者是DataGridView的虚拟模式没有真正的虚拟呢?

Am I missing anything here, or is the "virtual" mode of the DataGridView not really virtual at all?

[更新]

看起来好老的ListView实现完全排序虚拟模式的我要找的。但不幸的是在ListView不具备单元格格DataGridView的能力,所以我不能使用它。

It looks like the good old ListView implements exactly the sort of virtual mode I'm looking for. But unfortunately the ListView does not have the cell formatting capabilities of the DataGridView, so I can't use it.

有关他人,我与四列的ListView(详情模式)测试它可能有能力,VirtualMode = True和VirtualListSize =亿行。

For others that might be able to, I tested it with a four column ListView (in Detail mode), VirtualMode= True and VirtualListSize =100,000,000 rows.

与第一30行可见立即显示该列表。然后我就可以快速滚动到无延迟列表的底部。内存使用量是恒定的10 MB在任何时候。

The list is displayed immediately with the first 30 rows visible. I can then scroll rapidly to the bottom of the list with no delay. The memory usage is constant 10 MB at all times.

推荐答案

我们刚刚有过类似的要求,能够显示任意的,没有索引的在我们的应用程序1M +排表用非常好的表现,采用了股票 DataGridView的。起初我还以为这是不可能的,但有足够的头部划伤,我们想出了一些花天浇在反射器和.NET探查后,效果非常好。 这是很难做到的,但结果是值得的。

We just had a similar requirement to be able to display arbitrary, unindexed 1M+ row tables in our application with "very good" performance, using the stock DataGridView. At first I thought it wasn't possible, but with enough head scratching, we came up with something that works very well after spending days pouring over Reflector and .NET Profiler. This was difficult to do, but the results were well worth it.

我们解决这个问题的方法是通过创建一个类实现 ITypedList IBindingList的(你可以把它叫做 LargeTableView ,例如)来管理从数据库异步检索和信息高速缓存。我们还建立了一个单一的PropertyDescriptor,继承类(如 LargeTableColumnDescriptor )来检索每一列的数据。

The way we tackled this problem was by creating a class that implements ITypedList and IBindingList (you can call it LargeTableView, for example) to manage the asynchronous retrieval and caching of information from the database. We also created a single PropertyDescriptor-inheriting class (e.g. LargeTableColumnDescriptor) to retrieve data from each column.

DataGridView.DataSource 属性设置为实施 IBindingList的 A类,它进入一个伪虚拟模式,从常规VirtualMode,其中当每一行画(例如,当用户滚动)不同,在DataGridView访问上的 IBindingList的和索引[]根据需要每一列的的PropertyDescriptor 来检索值分别的GetValue 方法。在 CellValueNeeded 事件不会引发。在我们的例子中,我们访问数据库时,索引器访问,然后缓存值,以便后续重新油漆不打数据库。

When the DataGridView.DataSource property is set to a class implementing IBindingList, it goes into a pseudo-virtual mode that differs from regular VirtualMode, where as when each row is painted (such as when the user scrolls), the DataGridView accesses the indexer [] on the IBindingList and the respective GetValue methods on each column's PropertyDescriptor to retrieve the values as needed. The CellValueNeeded event is not raised. In our case, we access the database when the indexer is accessed, and then cache the value, so that subsequent re-paints don't hit the database.

我执行类似的测试重新:内存使用情况。在的DataGridView 确实分配一个数组,它是该列表(即,1M的行)的大小,但在阵列中最初引用单个的DataGridViewRow每个项目,所以存储器使用率acceptible。我不知道,如果行为是相同的,当VirtualMode是真实的。 我们能够通过立即返回的String.Empty 的GetValue 方法消除滚动滞后如果该行没有被缓存,然后异步执行数据库查询。当异步请求完成,可以提高 IBindingList.ListChanged 事件发出信号到DataGridView它应该重绘细胞,但这次从中很容易读取缓存可用。这样一来,用户界面​​是永远不会阻塞,等待数据库调用。

I performed similar tests re: memory usage. The DataGridView does allocate an array that is the size of the list (i.e. 1M rows), however each item in the array initially references a single DataGridViewRow, so memory usage is acceptible. I am not sure if the behavior is the same when VirtualMode is true. We were able to eliminate scroll lag by immediately returning String.Empty in the GetValue method if the row is not cached, and then performing the database query asynchronously. When the async request is finished, you can raise the IBindingList.ListChanged event to signal to the DataGridView that it should repaint the cells, except this time reading from the cache which is readily available. That way, the UI is never blocked waiting for database calls.

我们注意到一件事是性能显著更好,如果你设置DataSource或虚拟的行数<强>在添加在DataGridView的形式 - 它切初始化时间缩短了一半。此外,请确保您有行和列自动调整大小设置为,否则你将拥有更多的性能问题。

One thing we noticed is that performance is significantly better if you set the DataSource or number of virtual rows before adding the DataGridView to the form - it cut initialization time in half. Also, make sure that you have both Row and Column autosizing set to None or else you will have additional performance problems.

边注:我们完成了道路加载这么大的在我们的.NET应用程序表被上市所需的排序顺序主键具有IDENTITY沿着SQL服务器上创建临时表(行号),然后持续后续行请求的连接。这自然需要时间来初始化(约3-5S一个相当快的SQL服务器上),但没有可用索引的知识,我们有没有更好的选择。然后,在我们的ITypedList实现中,我们要求的行中100行,其中,第50行是被绘的行的页面,因此,我们限制每次索引被访问时进行查询的数量,并且我们得到外观具有在我们的应用程序中的所有数据可用

延伸阅读:

<一个HREF =htt​​p://msdn.microsoft.com/en-us/library/ms404298.aspx> http://msdn.microsoft.com/en-us/library/ms404298.aspx

http://msdn.microsoft。 COM / EN-US /库/ system.componentmodel.ibindinglist.aspx

这篇关于难道Windows窗体DataGridView实现真正的虚拟模式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆