使用 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,直到您完成对列表的处理
我正在开发一个用于处理 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,直到您完成对列表的处理