I hit a performance obstacle when trying to instantiate a Collection by passing it directly the list of Models or by using Collection.reset. It takes about 6000ms to initialize it with 4800 Models with about 200 attributes each. This isn't that large so it's a bit surprising to start off, but going off of this, I tried to speed it up by setting Collection.models directly to the array of models, and setting Collection.length to the length.
The question, other than the initial sorting, what is the difference between these two methods and where are the resources being spent? I use reset to initialize the Collection so there is no need to remove event handlers on the Models or to clean anything up.
USE CASE:
Trying to display a table with infinite scrolling, where each row is a Model and the Collection is the collection of rows. Each row can have about 200 columns. This is a static table except for a single column which contains a checkbox. The Models aren't doing anything else.
There's a bit more to collections than their models and length.
When assigning directly, we're bypassing any other behaviors (sorting, existence-checking, etc) defined by the collection. Both reset and the constructor (which ends up delegating to reset) use the collection's heavy-ish set method to ensure new models are added consistent with the collection's designed behavior.
Direct assignment may be ok if the models will always be reset (i.e., not added or removed individually), but certain collection features may exhibit unexpected behaviors if the models are not set.
Related
Say I have a main database class, TvShowDatabase, which contains a list of Shows. Each Show has a list of Episodes, each of which has a Length. The objects TvShowDatabase, Show and Episode all implement INotifyPropertyChanged.
I would like to compute and show TotalViewingPotential, a property of TvShowDatabase, which sums the Length of each Episode of each Show.
Moreover, let's say the user is looking at this structure in a tree style, and is able to edit the Length of any Show. When they do this, the TotalViewingPotential should update accordingly, and the results be seen on the screen.
My question: in WPF (and specifically, using Prism for MVVM), what is the best way to hook up the plumbing for these change notifications?
I've considered intercepting adds to each list (using ObservableCollection) and giving any new items a Parent. This, however, gets messy, and a top-down approach is preferable.
I've seen hyper-observable collections (http://www.codeproject.com/Tips/694370/How-to-Listen-to-Property-Chang), but I worry about event-subscription based memory leaks with this method, and it still requires a good bit of manual plumbing to raise the OnPropertyChanged(TotalViewingCollection) events where needed.
Is there a pattern for this?
The task, as you describe it, has a simple solution. You do not need to propagate changes along the collections.
TotalViewingPotential is a normal INotifyPropertyChanged property. Make it accessible from your Length properties.
In the setter of the Length property, compute the difference between the new and the old values, and increment the TotalViewingPotential by the difference.
That's all.
To speed up initial loading, in order not to generate notifications for all Lengths, you may set the values of the backing fields of Lengths, and compute and and set TotalViewingPotential based on the values from the DB.
For my setup I have two sub-views (on the same View) that render the same type of Models, however each view uses a totally different set of Model (one displays the latest ones, the other is split in 4 subviews per category). Using filter() on a Collection doesn't work because I need 4 posts per Category and about 20 new ones.
Since they are both on the same page, when I update the model on one view, I want the same model to be updated on the second view.
I tried a couple of things:
Use one Collection on the mainView, fetch inside the mainView and give this common Collection to the subViews. This is working as long as both subViews are using the same set of Models, which I am not.
Use custom events and a Collection in each subView. When Model is updated, send a global Backbone.trigger with the modified Model, catch it on the other side and do stuff as needed. This is also working but the implementation is really not pretty or efficient. Having all the Models listen for change and only act if their id is the correct one seems counter productive.
Use one Collection on the mainView and one per subView, the idea being that the Collection on the mainView holds all the items and distribute them to each subView's Collection as needed. This works but fetching the data, duplicating in the main Collection and the other subView Collection is kind of a pain and requires me to hold an instance on mainView inside each subView, which I don't really want to do because each subView is a "component" and can be use in multiple places.
People online seem to do the Events way most of the time, but I wonder if someone has a better idea.
Thanks a lot.
I have a backbone collection that is dependent on another collection in my Rails application. I want to make sure that the view that displays the dependent collection is emptied out and the dependent collections is 'reset' it its view as well as corresponding records from the server are deleted. Is there an easy way to do so or do I have to loop through the collection and fire off model.destroy calls for all models in the dependent collection when the last record from the existing collection is removed?
Backbone Collections have a reset() (docs) method that will take a list of models as an argument. If you pass no argument, it will empty the entire Collection. However, this will not by default remove the models themselves from the server as you probably saw.
There's also a sync() (docs) on the Collection that will sync the collection (or all the models in the collection) to the server. Of course if you've run reset() the Collection is now empty, so that doesn't really help.
In the end I think that you will have to loop through the Collection to destroy each model (unless you want to take a serverside approach to limit your calls), but you should be able to extend your Collection and add a destroyCollection() method, or simply extend the already present reset collection to call the destroy() on the models before it resets the collection to empty.
If this doesn't help maybe provide a higher up example of what you're trying to achieve and maybe there's an even simpler way?
There are cases when you have many UI updates due a massive amount of INotifyChangedProperties events. In that case you might want to signal the changes to UI only once when all the properties are set like in a batch.
I found this great article that explains how to defer the refresh of the ViewCollection:
http://marlongrech.wordpress.com/2008/11/22/icollectionview-explained/
However I get an exception when the View is deferred and I try to add something to the collection. I don't understand why this shouldn't be allowed. That's the whole point of it in first place.
InvalidoperationException:
Cannot change or check the contents or Current position of
CollectionView while Refresh is being deferred.
Does anyone know how to solve this problem?
Many Thanks,
I think you are misunderstanding or misrepresenting the MSDN help on the subject. They are saying that you don't have to modify the underlying collection to sort or filter. They are not saying that you can't modify the underlying collection. The OP has a very valid point. We have a large collection that has been sorted and filter for the user and it is displayed in a list box. When the user selects a range of those records and wants to delete them, we are forced into a situation where the ListCollectionView refreshs view for every item that was deleted.
I think the OP's question is very valid. The performance is horrendous because we have multiple filters on a huge set of data. The DeferRefresh has a real purpose on a class like the ListCollectionView, but in inexplicably diabled for inserts and deletes, when you need it the most.
Yes, don't modify the collection in question. I think that you are misunderstanding the purpose of a collection view. This is what MSDN says;
You can think of a collection view as
a layer on top of a binding source
collection that allows you to navigate
and display the collection based on
sort, filter, and group queries, all
without having to manipulate the
underlying source collection itself.
So in short, don't defer the refresh until you are done adding and removing, and otherwise manipulating your collection.
I have a backend Dictionary that is used for synchronization (ie. to both a filestore and a webservice).
Off the top of this I need to generate lists/enumerables for the WPF frontend to consume. What is the difference between either hooking an enumerable up to the dictionary, and calling PropertyChanged when it is updated to using an ObservableCollection and having it automatically called its CollectionChanged.
Synchronizing occurs in the background automatically, and some elements may be removed, others may be updated. I want to propagate this information to the WPF frontend and user smoothly. (ie. if one item is removed, the whole display shouldn't have to be reinitialized). I also want to add animation when items are added and removed (ie. fade in and out) - is this possible if I replace the whole list or will it cause every single item to fade in again?
So should I:
1) use an observable collection and write some fancy synchronization logic between the dictionary and the collection?
2) use linq extension methods to convert the dictionary to an enumerable and simply call propertychanged on the enumerable whenever it changes?
3) synchronize between a dictionary and a list, by replacing the list whenever it is updated?
Also, how would any of these work with sorting and filtering operations that are performed just for the UI? (ie. if I need to filter some elements out of the dictionary based upon user selection, should I use a similar method as the one you have recommended?)
If you "replace" any IEnumerable<T> when you get a change, the entire list will be refreshed in the UI.
In order to avoid that, you'll need to implement INotifyCollectionChanged, and provide a collection which implements this. Instead of replacing the collection, you handle the elements, which in turn fires the appropriate events.
ObservableCollection<T> handles this for you. Personally, if you need to keep this in a dictionary, but want to synchronize it to a list, you may want to consider making a custom collection, possibly based around SortedDictionary. A standard Dictionary has no sense of ordering, which means that there'd be no way to implement INotifyCollectionChanged appropriately.