目前我有两个 WPF 列表框模仿以下功能
(来源:psu.edu)
我使用 2 个 ObservableCollections 来允许用户选择他们需要的任何项目(灵活性是这里的关键)。主要问题是我有数千 个项目分组在两个列表框中。总而言之,设计效果非常好(有几十个项目),但我的绊脚石是当用户在屏幕冻结时从左到右复制所有可用项目时(在不同线程上运行的时间?)。
看看 ObservableCollection,它缺少 AddRange 方法,并且互联网上有各种可用的实现。我还知道 CollectionChanged 事件是不必要的,因为每个项目都被复制,导致性能严重下降。
将来我很可能必须允许用户从超过 10 000 个项目的组中进行选择,这听起来像是一个坏主意,但这是不可协商的,因为列表框(CollectionViewSource)上的分组效果非常好,但有关闭两个列表框的虚拟化的副作用
当数据绑定到 ObservableCollection 时,加载包含数千个项目的列表框时,我可以做些什么来提高性能?您是否有推荐的 AddRange 类型实现?我唯一的选择是在后台线程上运行它,这似乎很昂贵,因为我没有从数据库加载数据?
At present I have two WPF listboxes imitating the following functionality
(source: psu.edu)
I am using 2 ObservableCollections to allow users to select whatever items they require (flexibility is the key here). The main issue is that I have thousands of items that are grouped in both listboxes. All in all the design works really well (with a few dozen items), but my stumbling block is when a user copies all the available items from the left to the right as the screen freezes (time to run on a different thread?).
Looking at ObservableCollection it lacks an AddRange method and there are various implementations available on the internet. I also know the CollectionChanged event is needlessly being fired as each item is copied over draining performance horribly.
It may well be that I have to allow users to choose from groups of over 10 000 items in the future, which sounds like a bad idea, but is non-negotiable as the grouping on the listbox (CollectionViewSource) works really well, but has the side effect of switching off the Virtualising of both the listboxes
What can I do to improve the performance when loading a listbox with thousands of items when databound to an ObservableCollection? Are there any AddRange type implementations that you would recommend? Is the only choice I have here to run this on a background thread which seems expensive because I am not loading data from a database?
发布评论
评论(4)
我已经删除了 CollectionViewSource 和分组,并且项目在 1/2 秒内复制完毕,但是使用分组可能需要长达一分钟的时间,因为虚拟化不适用于分组。
我需要决定是否使用 CollectionViewSource
I have removed the CollectionViewSource and the grouping and the items are copied over in 1/2 a second, but with the grouping on it can take up to a minute because virtualisation does not work with the grouping.
I will need to decide whether to use the CollectionViewSource
我忍不住回答这个问题。我认为您不再需要这个答案,但也许其他人可以使用它。
不要想太多(不要接近这个多线程(这会使事情容易出错并且不必要的复杂。仅使用线程进行硬计算/IO),所有这些不同的操作类型将使其很难缓冲。最烦人的部分是,如果您删除或添加 10000 个项目,您的应用程序(列表框)将非常忙于处理 ObservableCollection 引发的事件。该事件已经支持多个项目,所以......
您可以缓冲这些项目,直到它更改。因此,如果“用户”更改操作或刷新操作,“添加”操作将被缓冲并作为批处理引发。
还没有测试过,但你可以这样做:
玩得开心!,J3R03N
I couldn't resist answering this. I don't think you won't need this answer anymore, but maybe somebody else can use it.
Don't think too hard (do not approach this multithreaded (this will make things error-prone and unnecessary complicated. Only use threading for hard calculations/IO), all those different actiontypes will make it very difficult to buffer. The most annoying part is, that if you remove or add 10000 items your application (listboxes) will be very busy with handling the events raised by the ObservableCollection. The event already supports multiple items. So.....
You could buffer the items until it changes the action. So Add actions will be buffered and wil be raised as batch if the 'user' changes action or flushes it.
Haven't test it, but you could do something like this:
Have fun!, J3R03N
您可能可以继承
ObservableCollection
(或直接实现INotifyCollectionChanged
)来添加BeginUpdate
和EndUpdate
方法。对BeginUpdate
和EndUpdate
的调用之间所做的更改将排队,然后组合成一个(或多个,如果有单独的范围)NotifyCollectionChangedEventArgs
对象,该对象将调用EndUpdate
时传递给CollectionChanged
事件的处理程序。You could probably inherit from
ObservableCollection<T>
(or directly implementINotifyCollectionChanged
) to addBeginUpdate
andEndUpdate
methods. Changes made between calls toBeginUpdate
andEndUpdate
would be queued, then combined into one (or several if there are separate ranges)NotifyCollectionChangedEventArgs
object that would be passed to the handlers of theCollectionChanged
event whenEndUpdate
is called.您可以在此处找到线程安全的可观察集合。确保您的 Observable 集合线程安全并将其绑定到列表框。
You can find a Thread safe observable collection here. Make your Observable collection thread safe and bind it to listbox.