So I’ve been doing some UI work in the last 6 months or so – experimenting with MVVM and the like. Mostly with WPF, but also some win forms.
Until the last few days I had managed to avoid working with BindingList, for one reason or another. Either because I was using ObservableCollection in WPF or because my lists were static, or they always updated in bulk. As part of my investigation into BindingList I found that it supports something which ObservableCollection does not. That is, cascade notification of changes to elements. So if an element type supports INotifyPropertyChanged, then BindingList will raise events when an element raises its PropertyChanged event, saying which element changed and more specifically which property on that element changed. Seems like a kind of nifty feature, at first glance…
But the implementation does not scale, it is slow, it performs terribly with larger lists. If your element type supports INotifyPropertyChanged, every time one of those elements raises the property changed event the entire list is walked to work out the index in the list of the item which raised the event! I was in shock when I first realised this. You see BindingList is truly just a rather thin wrapper over Collection<T>, so there is no metadata associated with each entry, all of the binding of the element PropertyChanged event is directed to a single handler, and all it gets given is the source and the name of the changed property, so there is no way to include the NewIndex parameter in ListChangedEventArgs without doing a search. (By default this search even uses the default object comparator, so if you happen to have two different but sometimes equal objects in your list, enjoy the results…)
Another side note – AddNew, the other feature which BindingList has which Collection<T> does not – also does not scale. It has to use IndexOf to find out where in the list the newly added item ended up in case it needs to cancel the add, because it supports auto sorting in derived types. (BindingList does not support auto sorting itself…)
Morale of the story… don’t use BindingList for more than a hundred or so items which support INotifyPropertyChanged – write your own. If you do write your own, consider just not supporting the cascading modify events at all (even though you can do it efficiently if you have to). Item presentation should bind to the items, not to the list which holds them. But alas, not every control agrees…
(PS – BindingSource internally creates a BindingList in many scenarios…)
(PPS – Heh, I just realized this is immediately after my Contains rant, and is effectively an IndexOf rant, which I said I hadn’t seen misused much…)
I am not sure I see this. Since the underlying collection will be implemented as a linear array, if the collection contains a reference type with default equality, walking the list should be fairly efficient. On my machine (64 bit, 2GHz) a binding list with 10 million items can raise an event on the last item in about 100msec, which does not seem terrribly slow to me for something binding to the UI.
Lets drop that size back to 100k elements to be more reasonable. Now your updates only take 1 milisecond each.
If you have 1 update per minute for each element, you are using 150% cpu. That is only 1 update a minute per element.
Drop it back to 10k elements, definitely not uncommon at all, now you can do 1 update per element every second.
In the high performance environments I’m in, 5 updates per second per element on average, is probably more likely (and desired to be shown, so batching the event raising in the back-end won’t help). I might be able to manage 3k elements max, and that is pegging 1 cpu completely just passing the events through the binding list. That doesn’t account for any drawing cost for the UI, any ability for the user to perform actions if there is some small extra high spike of activity.
And this 100% cpu usage can be dropped to practically 0, just by taking a small hit to memory overhead and using the proper data structure.
Are you saying you have in the region of 5K changes per second and you wish to show these “live”? This sounds more like an animation than a data binding.
I won’t go into the specifics, but yes it is a lot of updates. The vast majority of them will be of no use to the user, but any specific one could be – depending on where the user is looking. Yes there could be more complex design strategies which work better, and if the number of changes gets a lot worse it would be crazy not to investigate them – but for the point I am at, a simple replacement of BindingList fixes its scaling problem and gives me plenty of scope for even more updates.
OK, thanks for your reply.