WPF data virtualization issues
I need to display about few million items in WPF ListBox (I am aware how bad idea this is, but I have to do it this way). New items are arriving very quickly, thousands per second, but apart from that no changes are made to the list: items are never removed or modified. I need the LisBox control to be refreshed at least once per second.
I understand that I get UI virtualization "for free" in WPF (I'm using VirtualizedStackPanel
in Recycle
mode and deferred scrolling), but I have to virtualize the data. I'm completely new to WPF so I tried to leverage the best existing solution that I found. It works but flickers each time the count is refr开发者_如何学编程eshed, and SelectedItem is lost on each reload (I assume this is because it fires the CollectionChanged
of "Reset" type that reloads the whole collection). I tried to use "Add" event instead of "Reset" but it requires list of items that were actually added to the collection and it doesn't really make any sense to fetch several thousand of objects per second just to pass them to the event and throw them away because they're virtualized anyway. I also tried to just fire PropertyChanged
for Count
property, so that the ListBox would update it's index range/adjust scrollbar, bizzare things started to happen: the scrollbar would adjust to the new count, though list items wouldn't display and still plenty of flickering.
In other words: how do I inform the ListBox control that N
new items were added to the bound collection so that the ListBox will just adjust the scrollbar range (and won't ask me for the added items until they're actually displayed).
I'm using .NET 4.0 and Caliburn.Micro in this project but I doubt that this will affect potential solutions.
I had a similar situation wherein my cached list of objects (in millions) were bound to multiple ListBoxes across application (loaded on various pages), and when a cached item would be added, deleted or edited I had to maintain the selection and update the changes across the application without scroll or selection flicker.
I implemented it this way...
I got a thread safe
ObservableCollection
calledFastObservableCollection
... Updating an ObservableCollection in a separate threadI added support for
AddRange()
in the aboveFastObservaleCollection
for bulk inserts withoutCollectionChanged
Notifications.CollectionChanged
notification would fire ONLY once for the last item added from the bulk.... http://peteohanlon.wordpress.com/2008/10/22/bulk-loading-in-observablecollection/Used Thread safe
CollectionViews
. You can customize a collection view and dispatch the event ofSourceCollection.CollectionChanged
on correct thread by raising a custom 'Refreshed' event.
This link provides the guide for the dispatched collection changed notification... Where do I get a thread-safe CollectionView?
I changed my ListBoxes to use
SelectedValue
bindings instead ofSelectedItem
binding and made sure thatSelectedValue
is a primitive type (value type). This maintains the selection by value.I would call
ListBox.SelectedValue
's binding expression'sUpdateSource()
andUpdateTarget()
when ListBox ItemsSource i.e. a custom refresh event raised from the CollectionView is handled through an attached behavior.
Now it works like charm without any filckering and maintains selection as well.
you need to create a custom collection that implements the non-generic IList interface as well as the generic IList. If you do this then a listbox control wont enumerate the collection but use the this[] interface which give you an opportunity to load rows in a paged style automatically when the user scrolls.
Here is a similar solution I posted on my blog: http://www.deanchalk.me.uk/post/WPF-e28093-DataContext-Virtualization-With-Paged-Services.aspx
精彩评论