带数据虚拟化的DataGrid行请求模式
我使用CodePlex和Bea 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。
如果我的页面大小设置正确,我可以从当前页面和先前加载的页面提供所有这些请求。
如果
CanSelectMultipleItems
是True
并且用户选择使用SHIFT键或鼠标拖动多个项目,则DataGrid
枚举从列表中选择的端部的开始的所有行。无论IList
是否实施,此枚举都通过IEnumerable
接口进行。如果所选行不可见并且当前可见区域与所选行相距“很远”,则有时DataGrid会开始请求从选定行到可见区域结束的所有项目。包括它们之间甚至不可见的所有行。我无法弄清楚这种行为的确切模式。也许我的实现是这个原因。
我的问题
我很纳闷,为什么
DataGrid
请求不可见行,因为当成为可见的那些行会再次请求?为什么有必要请求每行两到三次?
谁能告诉我如何使DataGrid不使用
IEnumerable
,除了关闭多项选择?
是的,我最终做了类似的事情。我返回了我已经加载的所有物品,没有其他物品。自那以后没有造成问题。谢谢 –