WInRT introduces a new interface for collection change notification, IObservableVector, which means ObservableCollection no longer works with this framework. In this blog post I will show how you can use ObservableCollection, via a simple adapter, within you WInRT applications.
Developers are slowly starting to get their heads around the differences between the old (Silverlight, WPF, WP7) and the new - WinRT. Whilst the it has a familiar feel, with the UI defined in XAML and an API that is very similar to .NET, there are a great many differences. For an overview of some of these differences see:
- TweetSearch - A Cross platform Metro UI WinRT
- Morten Nielsen's blog series on WInRT vs. Silverlight differences
A number of developers have discovered that while WinRT has the ObservableCollection
class, when bound to the UI, lists / grids fail to update as items are added / removed. This is because while the same interfaces are being used for collections (ILIst
, IEnumerable
etc ...), there is a new interface for notification of collection changes, IObservableVector
. Because ObservableCollection
implements IEnumerable
its contents will be rendered in the UI, however it implements the 'old' interface for change notification - INotifyCollectionChanged
.
The WinRT SDK samples include classes that implement IObservableVector
to demonstrate binding with collection change handling, however, what if you have some old code using ObservableCollection
that you want to port over? Or, what if you want to code-share between Silverlight and WInRT?
A few days ago I saw a blog post by Avi Pilosof where he created a class that implements both the INotifyCollectionChanged and IObservableVector interfaces. This will certainly do the job, however there is a simpler way ...
Using the Gang of Four Adapter pattern, we can create a class which wraps ObservableCollection
, to implement IObservableVector
:
IObservableVector
extends various list interfaces (ILIst etc ...) so we have to implement these on ObservableCollectionShim
via straight-through adapter methods ...
Now, the interesting part! The change notification is implemented by handling CollectionChanged
events, and re-emitting them as VectorChanged
events:
Note, there does not seem to be an equivalent for NotifyCollectionChangedAction.Move
, however, I am pretty sure ObservableCollection
never raises that change type anyway!
We can now make use of our 'shim' class within a view-model as follows:
However, if we were using this view-model within a cross-platform application, this would still cause problems, because IObservableCollection
does not exist in Silveright / WPF. A more elegant solution is to wrap the ObservableCollection
in the shim class within a value converter. Firstly, we need a way to create a shim without specifying the generic type argument (IValueConverter
is not strongly typed, your bound values are presented as the type 'object'):
This can then be used within a value converter as follows:
This allows us to adapt an ObservableCollection
for use with WinRT simply by applying a value-converter within the View:
A nice side-effect of this approach is that if we replace the ObservableCollection
within our view-model with a new instance, the binding framework will take care of creating a new 'shim' via the value converter.
This technique allows us to write cross-platform view-models using ObservableCollection
for our collections of objects.
You can download the sourcecode with a simple example here: ObservableCollectionShim.zip
Regards, Colin E.