Dan*_*zen 11 wpf datagrid data-virtualization
我使用CodePlex的一些想法和Bea Stollnitz的博客以及Vincent Da Ven Berhge的论文(同一链接)实现了数据虚拟化解决方案.但是我需要一种不同的方法,所以我决定编写自己的解决方案.
我DataGrid用这个解决方案来显示大约一百万行.我也在使用UI虚拟化.我的解决方案是可行的,但我在某些情况下遇到了一些奇怪的行为,这些行为是关于如何DataGrid从源头请求数据的.
关于解决方案
我最终编写了一份列表来完成所有繁重的工作.它是一个名为VirtualList<T>.It 的泛型类,它实现了ICollectionViewFactory接口,因此集合视图创建机制可以创建一个VirtualListCollectionView<T>实例来包装它.这个类继承自ListCollectionView.我没有按照建议编写我自己的ICollectionView实现.继承似乎也很好.
在VirtualList<T>分裂整个数据到页.它获取总项数,每次DataGrid通过列表索引器对行进行请求时,它会加载相应的页面或从缓存中返回.页面在内部回收,并DispatcherTimer在空闲时间处理未使用的页面.
数据请求模式
我学到的第一件事就是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枚举从列表开头到选择结尾的所有行.IEnumerable无论IList是否实现,此枚举都通过接口发生.
如果所选行不可见且当前可见区域与所选行"远",则有时DataGrid会开始请求从所选行到可见区域末尾的所有项目.包括其间甚至不可见的所有行.我无法弄清楚这种行为的确切模式.也许我的实施就是这个原因.
我的问题
我想知道,为什么DataGrid不可见行的请求,因为这些行将在可见时再次请求?
为什么有必要要求每一行两到三次?
任何人都可以告诉我如何使DataGrid不使用IEnumerable,除了关闭多个项目选择?