11

我使用来自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。

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

  • 如果CanSelectMultipleItemsTrue并且用户使用 SHIFT 按钮或鼠标拖动选择了多个项目,则DataGrid枚举从列表开头到选择结尾的所有行。IEnumerable无论是否实现,此枚举都通过接口发生IList

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

我的问题

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

  • 为什么需要每行请求两三次?

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

4

1 回答 1

5

我至少找到了一些欺骗 VirtualList 的方法。你可以在这里阅读。

如果您找到了另一种解决方案(甚至比我的更好),请告诉我!

于 2013-01-16T08:23:55.117 回答