Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net WPF数据虚拟化问题_.net_Wpf_Mvvm_.net 4.0 - Fatal编程技术网

.net WPF数据虚拟化问题

.net WPF数据虚拟化问题,.net,wpf,mvvm,.net-4.0,.net,Wpf,Mvvm,.net 4.0,我需要在WPF列表框中显示大约几百万个项目(我知道这是一个多么糟糕的主意,但我必须这样做)。新项目以每秒数千个的速度快速到达,但除此之外,列表中没有任何更改:项目永远不会被删除或修改。 我需要LisBox控件每秒至少刷新一次 我知道我在WPF中“免费”获得UI虚拟化(我在Recycle模式下使用VirtualizedStackPanel并延迟滚动),但我必须虚拟化数据。我是WPF的新手,所以我试着利用我发现的最好的。它可以工作,但每次刷新计数时都会闪烁,并且每次重新加载时SelectedItem

我需要在WPF列表框中显示大约几百万个项目(我知道这是一个多么糟糕的主意,但我必须这样做)。新项目以每秒数千个的速度快速到达,但除此之外,列表中没有任何更改:项目永远不会被删除或修改。 我需要LisBox控件每秒至少刷新一次

我知道我在WPF中“免费”获得UI虚拟化(我在
Recycle
模式下使用
VirtualizedStackPanel
并延迟滚动),但我必须虚拟化数据。我是WPF的新手,所以我试着利用我发现的最好的。它可以工作,但每次刷新计数时都会闪烁,并且每次重新加载时SelectedItem都会丢失(我假设这是因为它触发了重新加载整个集合的“Reset”类型的
CollectionChanged
)。我尝试使用“添加”事件而不是“重置”,但它需要实际添加到集合中的项的列表,并且每秒获取数千个对象只是为了将它们传递到事件并将它们扔掉是没有任何意义的,因为它们无论如何都是虚拟化的。我还试着为
Count
属性触发
PropertyChanged
,这样列表框就会更新它的索引范围/调整滚动条,奇怪的事情开始发生:滚动条会调整到新的计数,尽管列表项不会显示,而且仍然会大量闪烁

换句话说:我如何通知ListBox控件已将
N
新项目添加到绑定集合中,以便ListBox仅调整滚动条范围(并且在实际显示之前不会向我请求添加的项目)


我在这个项目中使用了.NET 4.0和Caliburn.Micro,但我怀疑这会影响潜在的解决方案。

您需要创建一个自定义集合来实现非通用IList接口和通用IList。如果执行此操作,则listbox控件将不会枚举集合,而是使用this[]界面,这样您就有机会在用户滚动时自动加载分页样式的行

以下是我在博客上发布的类似解决方案:

我也遇到过类似的情况,我的缓存对象列表(以百万为单位)被绑定到应用程序中的多个列表框(加载在不同的页面上),当一个缓存项被添加、删除或编辑时,我必须在应用程序中保持选择并更新更改,而不会出现滚动或选择闪烁

我是这样实现的

  • 我得到了一个线程安全的
    ObservableCollection
    名为
    FastObservableCollection

  • 我在上面的
    FastObservaleCollection
    中添加了对
    AddRange()
    的支持,用于无
    CollectionChanged
    通知的批量插入
    CollectionChanged
    对于从批量添加的最后一个项目,通知将只触发一次

  • 使用线程安全的
    collectionview
    。您可以自定义集合视图,并通过引发自定义的“刷新”事件,在正确的线程上调度
    SourceCollection.CollectionChanged
    事件

  • 此链接提供已发送集合更改通知的指南

  • 我将列表框更改为使用
    SelectedValue
    绑定,而不是
    SelectedItem
    绑定,并确保
    SelectedValue
    是基本类型(值类型)。这将按值维护选择

  • 当ListBox项资源(即从CollectionView引发的自定义刷新事件)通过附加行为处理时,我将调用ListBox.SelectedValue的绑定表达式的
    UpdateSource()
    UpdateTarget()


  • 现在,它像魅力一样工作,没有任何干扰,也保持了选择。

    你能详细说明一下第2点和第3点吗?我的收藏是由另一个进程更新的,我只有两个方法的接口
    fetchItems(begin,end)
    getCount()
    ,所以我不知道
    AddRange
    如何帮助我,或者我可能误解了什么。关于“SourceCollection.CollectionChanged”-您指的是哪个线程正确?我的自定义“刷新”事件将在哪里处理?我不确定您的意图。此解决方案与我以前尝试的解决方案存在类似的问题。滚动范围扩大,但项目仅被枚举一次(通过
    GetEnumerator
    ),滚动第一批中加载的项目下方只会恢复滚动到第一个项目(而不是获取新项目)。我可以强制重新枚举我的集合吗?如果实现IList(非泛型),Listbox将只调用GetEnumerator来枚举整个集合中的第一项。它将专门使用Count和这个[]索引器,这使您能够实现简单的virtualizationIndeed!(虽然当我的列表同时实现了
    IList
    IList
    ——这很奇怪)但我在
    Count
    方面仍然存在问题(和以前一样),我正在实现
    INotifyPropertyChanged
    ,但我的
    属性更改
    事件始终是
    null
    :再看一看您的实现,这是一个bog标准解决方案,绝对有效。收集类上的Listbox调用计数()。