DataGrid行请求模式与数据虚拟化 [英] DataGrid row request patterns with data virtualization

查看:172
本文介绍了DataGrid行请求模式与数据虚拟化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用 CodePlex 的一些想法和 Bea Stollnitz 和Vincent Da Ven Berhge的论文(同一链接)。然而,我需要一种不同的方法,所以我决定编写自己的解决方案。



我正在使用 DataGrid 来显示大约一百万行与这个解决方案。我也使用UI虚拟化。我的解决方案是可行的,但是在某些情况下,我会遇到一些奇怪的行为: DataGrid 如何从其来源请求数据。



关于解决方案



我最终写了一个完成所有繁重工作的列表。它是一个名为 VirtualList< T>的通用类。它实现了 ICollectionViewFactory 接口,因此集合视图创建机制可以创建一个 VirtualListCollectionView< T> 实例来包装它。该类继承自 ListCollectionView 。我没有遵循建议写我自己的 ICollectionView 实现。继承似乎也可以正常工作。



VirtualList< T> 将整个数据分割成页面。它获取总项目数量,并且每次通过列表索引器向 DataGrid 请求一行时,它将加载适当的页面或从缓存返回。这些页面被回收到里面,一个 DispatcherTimer 在空闲时间内处理未使用的页面。



数据请求模式




  • 我学到的第一件事是, VirtualList< T> 应该实现 IList (非泛型)。否则 ItemsControl 将它视为 IEnumerable 并查询/枚举所有行。这是合乎逻辑的,因为 DataGrid 不是类型安全的,所以它不能使用 IList< T> 接口。 / p>


  • c $ c> DataGrid 经常询问具有0索引的行。它似乎被用于视觉项目测量(根据调用堆栈)。因此,我只是缓存这个。


  • DataGrid 中的缓存机制使用可预测的模式查询它显示的行。首先它要求从上到下的可见行(每行两次),然后在下降的可见区域(包括第一个可见行)之前查询几行(取决于可见区域的大小)顺序如此,从下到上。之后,请求从上到下的可见行(包括最后一个可见行)之后的行数相同。



    如果可见行索引为4,5 ,6。数据请求将为:4,4,5,5,6,6,4,3,2,1,6,7,8,9。



    如果我的页面大小正确设置,我可以从当前和以前加载的页面提供所有这些请求。


  • 如果 CanSelectMultipleItems True ,用户使用SHIFT按钮或鼠标拖动来选择多个项目, DataGrid 枚举所有从列表开始到选择结束的行。这个枚举是通过 IEnumerable 界面进行的,而不管 IList 是否被实现。


  • 如果所选行不可见,并且当前可见区域与选定行远,则DataGrid有时会从所选行到可见区域的末尾开始请求所有项目。包括它们之间的所有行甚至不可见。我无法弄清楚这种行为的确切模式。可能我的实现是其原因。




我的问题




  • 我想知道,为什么 DataGrid 请求非可见行,因为这些行会在可见时再次被请求?


  • 为什么有必要请求每一行两三次?


  • 可以任何人告诉我如何使DataGrid不使用 IEnumerable ,除了关闭多个选项?



解决方案

我至少找到了一些愚弄VirtualList的方法。您可以阅读此处



如果您已经找到另一个解决方案(比我更好),请告诉我!



问候,



Qudeid


I implemented a data virtualization solution using some ideas from CodePlex and the blog of Bea Stollnitz and Vincent Da Ven Berhge's paper (same link). However I needed a different approach so I decided to write my own solution.

I am using a DataGrid to display about a million rows with this solution. I am using UI virtualization as well. My solution is feasible, but I experience some weird behavior in certain situations on how the DataGrid requests data from its source.

About the solution

I ended up writing a list which does all the heavy work. It is a generic class named VirtualList<T>. It implements the ICollectionViewFactory interface, so the collection view creation mechanism can create a VirtualListCollectionView<T> instance to wrap it. This class inherits from ListCollectionView. I did not follow the suggestions to write my own ICollectionView implementation. Inheriting seems to work fine as well.

The VirtualList<T> splits the whole data into pages. It gets the total item count and every time the DataGrid requests for a row via the list indexer it loads the appropriate page or returns it from the cache. The pages are recycled inside and a DispatcherTimer disposes unused pages in idle time.

Data request patterns

  • The first thing I learned, that VirtualList<T> should implement IList (non generic). Otherwise the ItemsControl will treat it as an IEnumerable and query/enumerate all the rows. This is logical, since the DataGrid is not type safe, so it cannot use the IList<T> interface.

  • The row with 0 index is frequently asked by the DataGrid. It is seem to be used for visual item measurement (according to the call stack). So, I simply cache this one.

  • The caching mechanism inside the DataGrid uses a predictable pattern to query the rows it shows. First it asks for the visible rows from top to bottom (two times for every row), then it queries a couple of rows (depending on the size of the visible area) before the visible area (including the first visible row) in a descending order so, from bottom to top. After that it requests for a same amount of rows after the visible rows (including the last visible row) from top to bottom.

    If the visible row indexes are 4,5,6. The data request would be: 4,4,5,5,6,6,4,3,2,1,6,7,8,9.

    If my page size is properly set, I can serve all these requests from the current and previously loaded page.

  • If CanSelectMultipleItems is True and the user selects multiple items using the SHIFT button or mouse drag, the DataGrid enumerates all the rows from the beginning of the list to the end of the selection. This enumeration happens via the IEnumerable interface regardless of that IList is implemented or not.

  • If the selected row is not visible and the current visible area is "far" from the selected row, sometimes DataGrid starts requesting all the items, from the selected row to the end of the visible area. Including all the rows in between which are not even visible. I could not figure out the exact pattern of this behavior. Maybe my implementation is the reason for that.

My questions

  • I am wondering, why the DataGrid requests for non visible rows, since those rows will be requested again when become visible?

  • Why is it necessary to request every row two or three times?

  • Can anyone tell me how to make the DataGrid not to use IEnumerable, except turning off multiple item selection?

解决方案

I at least found some way to fool the VirtualList. You can read it here.

If you have found another solution (that is even better than mine), please tell me!

Greetings,

Qudeid

这篇关于DataGrid行请求模式与数据虚拟化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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