Common mistakes while using ObservableCollection

ObservableCollection is one of the most useful classes in WPF and Silverlight data binding. Whenever you modify the collection, the view is notified. Unfortunately, it is extremely easy to misuse. These are some of the mistakes I see from beginners and experts alike.

Replacing the collection

When a view binds to an ObservableCollection, it subscribes to events from that instance. It expects to be notified when items are added, removed, or replaced within that instance of the collection. The binding is not to the property of the parent object, but to that specific instance of the collection itself.

A common mistake is to modify the parent object’s property and replace one ObservableCollection with another. Just about every person who uses ObservableCollections makes this mistake at least once. Even Scott Hanselman made this mistake on stage at Mix ‘09 (skip to 10:30). The problem is that after you swap out one ObservableCollection for a new one, the view is still bound to the old one.

A common “fix” for this problem is to fire a PropertyChanged event to notify the view that the collection has been replaced. This causes the view to unbind from the old one and rebind to the new one. In this situation, the view can’t adjust to just the items that were added or removed; it has to rebind the entire list box. Not only is this inefficient, but it also scrolls back to the top of the list rather than preserving the user’s context.

This fix completely obviates the need for an ObservableCollection in the first place. It wasn’t the collection that changed, it was the property that points to the collection. That property could have pointed to a List, and it would have had the same effect. Which brings us to the next common mistake.

Using it for static collections

A common misconception is that data binding requires ObservableCollection. This is not true. Data binding works against anything that implements IEnumerable. You can data bind a list box directly to a List, if you want.

The advantage of ObservableCollection over List is that it implements INotifyCollectionChanged. This interface raises an event whenever the collection is modified by insertion, removal, or replacement. A List does not implement this interface, so anything data bound to it will not be notified when it changes.

Not all collections change while the user is looking at them. Some collections are fixed. Others are loaded from a database or server once, and then simply displayed. If the collection doesn’t change, don’t make it an ObservableCollection. Just make it a List.

Using linq

ObservableCollection is imperative. Linq is declarative. The two cannot be used together without extra help.

Imperative code explicitly acts upon something. When using an ObservableCollection, you explicitly call Add, Remove, and other methods to change the collection. You have to decide exactly when and how to take these actions.

Declarative code implicitly generates something. When using linq, you declare what a collection will look like, how it will be filtered, mapped, and transformed. You don’t explicitly modify the collection.

These two paradigms don’t mix. Once you use linq on an ObservableCollection, it is no longer observable. There are open-source projects like Bindable Linq that bridge the gap. But without that extra help, people are often surprised when things don’t work.

Using it in the model

ObservableCollection is for data binding. In the MVVM pattern, you bind a view to a view model. So it stands to reason that ObservableCollection belongs in the view model. However, many people use it in the model as well.

Microsoft’s own code generators encourage us to make this mistake. When you add a reference to a WCF service returning a List, the proxy turns that into an ObservableCollection. When you generate classes from an Entity Framework model, you get ObservableCollections. Service calls and persistence belong in the model layer, not the view model layer. The view model needs to massage this data to make it suitable for the view, so it needs to map the model collection into its own ObservableCollection.

Modifying the collection on the background thread

When an ObservableCollection is modified, it raises an event. Events are handled synchronously. Event handlers respond on the same thread as the modification. The handler completes before the Add or Remove method returns. This means that you can’t modify an ObservableCollection in a background thread.

Most people who run into this problem realize their mistake quickly. They wrap the code that modifies the collection in a delegate, and invoke it on the UI thread. It is unfortunate that an ObservableCollection cannot be modified in a thread-safe way on a background thread. This fix puts more work than necessary on the UI thread, making it less responsive than it should be.

Conclusion

ObservableCollection is extremely easy to misuse. Even experts like Scott Hanselman get it wrong. Microsoft’s WCF and EF code generators lead us to incorrect patterns. And even when we try to do the right thing, the synchronous nature of CollectionChanged events get in our way.

My advice is to skip ObservableCollection altogether. Use Update Controls instead, and just bind to a linq query. If you find that you need to access the collection programmatically, and not just through data binding, then DependentList might be right for you. Update Controls makes it much more difficult to make these common mistakes.

Comments

Re: Scott Hanselman's mistake

I watched the video link to see him doing what you claimed to be a mistake. But as far as I see, he is not doing anything wrong there. He is not replacing an ObservableCollection which is already in use. What he replaces is the one which he creates at the start of his function, so since he is still inside the routine when he replaces it, he is perfectly safe and it does not lead him to lose the intended functionality by any means. I agree that the code would have been better if he initializes it just inside the catch block itself so there would not be any replace actions, but that's a separate issue altogether.

You need to explain why these

You need to explain why these practices are mistakes. Granted they go against 'convention' but that isn't automatically a mistake. Stating that because the view uses an ObseravbleCollection it shouldn't be used by the model doesn't really stand up to scrutiny. Of course you could have the VM maintain a separate ObseravbleCollection but that means that you need to sync the collection in the VM with that in the model. In many cases its desireable. In some cases its overkill.

The reason that this is a

The reason that this is a mistake is because it breaks scrolling and selection. When you fire property changed on the entire list, XAML has no choice but to completely replace the list. If the user has scrolled down, then they will be unceremoniously thrown back to the top. And if they have selected any elements, those elements will be unselected.

You need to preserve the list in order to preserve the user's place.

Wrong. When replacing the

Wrong. When replacing the collection to preserve selection one must either have the same item reference in the new list or supply a comparer (Equals works) implementation which will help select same value item.