Skip to content

ConcatenatingObservableReadOnlyList

Yeah69 edited this page Nov 6, 2016 · 1 revision

Intention

Concatenating two ObservableCollection in such a way that it appears to be only one observable list.

Motivation

Let's say you have a DirectoryViewModel, then it would have one ObservableCollection with subdirectories (DirectoryViewModel) and one ObservableCollection with files (FileViewModel). In order to display it in a TreeView you would need a HierarchicalDataTemplate for the DirectoryViewModel and there you can only bind to a single ItemsSource DependencyProperty. So how do you resolve this situation?

There are several ways. First, you could concatenate the two ObservableCollections with Linq's Concat([…]) function. The problem here is that this returns an IEnumerable, which cannot be observed. As a consequence you would need to notify the changes manually.

Second, you could use only one ObservableCollection for both the subdirectories and the files. But then this ObservableCollection should depend on a common inherited class, let's say it is FileSystemViewModel. Now, you need to down-cast, when you want to iterate directories or files.

Third, you could use the ConcatenatingObservableReadOnlyList. It concatenates two IObservableReadOnlyLists (ObservableCollections can be wrapped into this interface) and forwards the observed notifications of both lists.

Features

Unlike the TransformingObservableReadOnlyList the ConcatenatingObservableReadOnlyList has no backing lists as they are not necessary. Here, the items don't need to be transformed and can be forwarded directly. Only two references to the source lists are needed. So it has constant space consumtion.

Probably, in most of the cases where you would want to use this class, the items will be of different types, so the given source lists have to be co-variant to the type, which the ConcatenatingObservableReadOnlyList exposes. In the example above DirectoryViewModel and FileViewModel inherit from FileSystemViewModel, that makes IObservableReadOnlyList and IObservableReadOnlyList co-variant to IObservableReadOnlyList. Co-variancy can only be accomplished with interfaces, thus it is impossible with the ObservableColletion directly as it is a class. Therefore, the ConcatenatingObservableReadOnlyList only takes IObservableReadOnlyLists as source lists and ObservableCollections have to be wrapped with WrappingObservableReadOnlyLists first. The ConcatenatingObservableReadOnlyList has a static Factory Method called Concatenate, which conveniently takes ObsevableCollections, wraps and concatenates them.

Example

With 'directories' and 'files' being ObservableCollections:

ConcatenatingObservableReadOnlyList<FileSystemViewModel> DirectoryItems = new ConcatenatingObservableReadOnlyList<FileSystemViewModel>(new WrappingObservableReadOnlyList<DirectoryViewModel>(directories), new WrappingObservableReadOnlyList<FileViewModel>(files));

Or:

ConcatenatingObservableReadOnlyList<FileSystemViewModel> DirectoryItems = ConcatenatingObservableReadOnlyList<FileSystemViewModel>.Concatenate(directories, files);

Clone this wiki locally