ObservableCollectionAdapter class

Adapts an ObservableCollection of a type for use as an ObservableCollection of a base type where covariance doesn’t work.

Sometimes it happens that you want to use a generic list with elements of a certain type as list with elements of a more general base type. After all you should be able to assign a List<Button> instance to a List<Control> field, right? For this purpose, .NET 4.0 supports so-called covariance that shall apply type inheritance to generic types. Unfortunately this only works in a few special cases so that you cannot rely on this feature in general. A detailed article by Marc Gravell explains the backgrounds of the topic.

That happened to me in a WPF MVVM project as I wanted to assign to a ObservableCollection of general ViewModel instances a collection of specialised ViewModel instances and failed. For this purpose I then wrote this simple adapter. This class is derived from ObservableCollection<BaseType> and adds a link to a ObservableCollection<SubType> instance to that. It automatically synchronises both collections. That is possible because an ObservableCollection provides the required events for it. Whenever the collection on either side of the adapter is changed, the adapter will carry the change over to the other side, just as if it was the same collection instance.

Compatibility: .NET Version 4.0 or newer

Example

The purpose and usage of this class are probably best explained with an example. Let us assume there is a tree view in a WPF View and it can contain diverse objects. A CodeProject article by Josh Smith explains how to use the WPF TreeView easily with a ViewModel. All objects are of the type TreeItemViewModel which has, among several display states, a Children property that contains the sub-elements of the node (ObservableCollection­<TreeItem­View­Model>). Let PersonViewModel be a type derived from TreeItemViewModel. It represents a person and is suited for use with TreeView items. In our application there is a property that contains all persons as a list of PersonViewModels (ObservableCollection<PersonViewModel>).

If one tree node only contains persons, you might as well assign a collection of persons to its Children property. But that fails due to incompatible generic types. Instead, you can now use this adapter:

// PersonListViewModel is the ViewModel for a tree node that only contains
// persons. Is is derived from TreeItemViewModel because it is a tree node itself.
class PersonListViewModel : TreeItemViewModel
{
    // The LoadChildren method is called when the subnodes of a tree node are
    // created.
    protected override void LoadChildren()
    {
        // The Children property of TreeItemViewModel is of the type
        // ObservableCollection<TreeItemViewModel> because it contains all
        // subnodes and cannot set a more specific type.
        Children =
            new ObservableCollectionAdapter<TreeItemViewModel, PersonViewModel>(
                project.PersonVMs);
    }
}

As soon as the application changes the collection of persons in the project, like adding a new person, this change is automatically carried over to the TreeItemViewModels’s Children list and the new entry appears in the tree view. Just like you would expect it from WPF data binding.

Usage notes

To use the ObservableCollectionAdapter class, you also need the OpLock class.

Download

ObservableCollectionAdapter.cs2.5 KiBQuelltext der ObservableCollectionAdapter-Klasse

Licence and terms of use

Copying and distribution of this file, with or without modification, are permitted provided the copyright notice and this notice are preserved. This file is offered as-is, without any warranty. (GNU All-Permissive licence)

Statistic data

  • Created on 2012-09-06.