使用 CreateDerivedCollection 进行分页

Paging with CreateDerivedCollection

我正在开发一个用于处理 WPF 列表框中显示的 20k 多个项目的应用程序,因此显然需要将它们分成页面。

我目前的解决方案有点滞后:

我使用带有 Paraller.ForEach 的异步命令对所有项目应用过滤器,并设置 MatchesFilter 属性。这很好用:

 FilteredItems = _allItems.CreateDerivedCollection(x => x, x
=> x.MatchesFilter, scheduler: RxApp.TaskpoolScheduler);

_count =FilteredSignatures.CountChanged.StartWith(0).ToProperty(this, x => x.Count);

这很快,保持 UI 响应,您可以看到 WPF 标签中的计数变化很快。

当过滤结束时,我(在主线程上):

Items.Clear();
foreach (var s in FilteredItems.Skip((CurrentPage - 1) * temsPerPage).Take(ItemsPerPage))
                        Items.Add(s);

这就是我的问题所在。每个项目都与图像一起显示,图像是从 url 异步加载的。 Clear() 部分以明显的方式冻结了 UI。我每页有 250 个项目(应该不会少,因为用户应该能够用眼睛搜索基于图像的项目)。

有更好的方法吗?我知道 DynamicData,但它使用 RxUI 6.x.

您可以在 RxUI 7.0 中使用 DynamicData

Dynamic Data 4 与 RxUI 6.5 配合得很好,这也是我通常使用的。话虽如此,我只想 post 一个使用 RxUI 的代码示例。主要是因为不需要clear然后re-add更新DerivedList。

[TestMethod]
    [TestCategory("Reactive")]
    public async Task PagingReactiveUITest()
    {

        ReactiveList<int> SourceList = new ReactiveList<int>();
        for (int i = 0; i < 100; i++)
        {
            SourceList.Add(i);
        }

        Tuple<int, int> pageWindow = new Tuple<int, int>(0, 10);


        //ReactiveComamnd that triggers paging
        ReactiveCommand<Unit> updatePaging =
            ReactiveCommand.CreateAsyncObservable<Unit>((_) =>
            {

                pageWindow = new Tuple<int, int>(10, 20);
                return Observable.Return(Unit.Default);
            });


        var PagedList =
            SourceList
            .CreateDerivedCollection(
                x => x,
                filter: (item) => item >= pageWindow.Item1 && item < pageWindow.Item2,
                signalReset: updatePaging);



        Assert.AreEqual(PagedList.First(), 0);
        Assert.AreEqual(PagedList.Last(), 9);

        //Trigger Paging
        await updatePaging.ExecuteAsync(null);

        Assert.AreEqual(PagedList.First(), 10);
        Assert.AreEqual(PagedList.Last(), 19);
    }

另请注意.. 如果您计划对列表进行大量更改,您还可以执行

using (SourceList.SuppressChangeNotifications())
{ 
      //DO STUFF
}

这将阻止消息进入 UI,直到您完成对列表的处理