【发布时间】:2012-09-03 13:14:35
【问题描述】:
我使用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>接口。DataGrid经常询问索引为 0 的行。它似乎用于视觉项目测量(根据调用堆栈)。所以,我只是把这个缓存起来。-
DataGrid内部的缓存机制使用可预测的模式来查询它显示的行。首先它从上到下询问可见行(每行两次),然后在可见区域(包括第一个可见行)之前以降序查询几行(取决于可见区域的大小)顺序如此,从下到上。之后,它从上到下在可见行(包括最后一个可见行)之后请求相同数量的行。如果可见行索引是 4,5,6。数据请求将是:4,4,5,5,6,6,4,3,2,1,6,7,8,9。
如果我的页面大小设置正确,我可以从当前和以前加载的页面处理所有这些请求。
1234563无论是否实现了 如果所选行不可见且当前可见区域与所选行“远”,有时 DataGrid 会开始请求从所选行到可见区域末尾的所有项目。包括其间的所有行,甚至不可见。我无法弄清楚这种行为的确切模式。也许我的实现就是原因。
IList,此枚举都是通过IEnumerable 接口发生的。
我的问题
我想知道,为什么
DataGrid请求不可见的行,因为这些行在变得可见时会再次被请求?为什么要每行请求两三次?
谁能告诉我如何让 DataGrid 不使用
IEnumerable,除了关闭多项选择?
【问题讨论】:
标签: wpf datagrid data-virtualization