带数据虚拟化的DataGrid行请求模式

带数据虚拟化的DataGrid行请求模式

问题描述:

我使用CodePlexBea Stollnitz的博客以及Vincent Da Ven Berhge的论文(同一链接)的一些想法实施了数据虚拟化解决方案。不过,我需要一种不同的方法,所以我决定写我自己的解决方案。带数据虚拟化的DataGrid行请求模式

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

关于解决方案

我写了一份清单,完成所有繁重的工作。它是一个通用类,名称为VirtualList<T>.它实现了ICollectionViewFactory接口,因此集合视图创建机制可以创建一个​​实例来包装它。这个类继承自ListCollectionView。我没有按照建议编写自己的ICollectionView实现。继承似乎也很好。

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

数据请求模式

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

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

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

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

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

  • 如果CanSelectMultipleItemsTrue并且用户选择使用SHIFT键或鼠标拖动多个项目,则DataGrid枚举从列表中选择的端部的开始的所有行。无论IList是否实施,此枚举都通过IEnumerable接口进行。

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

我的问题

  • 我很纳闷,为什么DataGrid请求不可见行,因为当成为可见的那些行会再次请求?

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

  • 谁能告诉我如何使DataGrid不使用IEnumerable,除了关闭多项选择?

我至少找到了某种愚弄虚拟列表的方法。你可以阅读它here

如果您发现了另一种解决方案(这比我的更好),请告诉我!

+0

是的,我最终做了类似的事情。我返回了我已经加载的所有物品,没有其他物品。自那以后没有造成问题。谢谢 –