Answered by:

What happened to INotifyCollectionChanged?

Question

After questioning my sanity for a while, I found out that INotifyCollectionChanged (and thus ObservableCollection<T>) are not supported. One of the samples uses an ObservableVector<T> class, but it doesn't quite work for anything other than object:

Additional information: Unable to compute GUID for type 'Windows.Foundation.Collections.IObservableVector`1[Foo]' because the instantiation contains types that are not supported by Windows Runtime.

I have a custom class in my Metro project called SearchResult. Its properties are all basic types (string, DateTime, etc). Then I create an ObservableCollection<SearchResult> that I want to set as the Source for a CollectionViewSource.

Since ObservableCollection<T> doesn't support change tracking in Metro I've included the ObservableVector.cs file from the Binding sample into my project. When it's time for me to set the ObservableCollection<SearcResult> as the Source, I call
ObservableCollection<SearcResult>.ToObservableVector<SearchResult>. However, at runtime I get the following exception:

An exception of type 'System.BadImageFormatException' occurred in imagebox.exe but was not handled in user code
Additional information: Unable to compute GUID for type 'Windows.Foundation.Collections.IObservableVector`1[ImageBox.Search.SearchResult]' because the instantiation contains types that are not supported by Windows Runtime.

If I make everything <object> instead of <SearchResult> it works. In other words, if instead of using ObservableCollection<SearcResult> I use ObservableCollection<object> and call ToObservableVector<object> everything works. But
then, of course, my collection isn't typed.

Is there any way to get change tracking and keep my typed collections?

The class in the sample implements IObservableVector<T>, but it can only work for object. You could implicitly implement IObservableVector<object> but have type-safe methods to add items and so on. Alternatively, you could write a generic class
that uses IObservableVector<object> and casts and when it starts working you can just replace that with ObservableVector<T>.

"If I make everything <object> instead of <SearchResult> it works. In other words, if instead of using ObservableCollection<SearcResult> I use ObservableCollection<object> and call ToObservableVector<object> everything works.
But then, of course, my collection isn't typed.

Is there any way to get change tracking and keep my typed collections?"

Why is IObservableVector<T> generic in the first place? The IVectorChangedEventArgs you eventually get in the notification event doesn't use the type argument. And for the scenario where ItemsControl consumes that interface (currently the
only scenario in which I'd use this, I think) it can't have any expectations about what T will be. It's working with a collection of what are ultimately someone else's objects.

ItemsControl is just as much in the dark with this being a generic interface as it would be if it were just IObservableVector with no type parameters.

As others have stated, the issue is that WinRT uses IObservableVector, whereas ObservableCollection exposes INotifyCollectionChanged. To solve the problem I have created a little adapter that you can use within a value converter as follows:

In case other folks run into this problem in the future, I want to warn people that the ObservableVector<T> implementation, as well as the ToObservableVector<object> extension method, in the
data binding sample does not work like you would expect.

ObservableVector<T> takes an INotifyCollectionChanged as a constructor argument as if it were a wrapper capable of forwarding collection change notifications from your ObservableCollection through the IObservableVector implementation. It
doesn't.

The INotifyCollectionChanged argument is cast to an IList and used as a backing store for the vector implementation.
If you add additional items to list (your ObservableCollection), the change notifications are not propagated.

Also, since ObservableVector<T> is generic, you would think you could use it to hold any type (ie ObservableVector<MyClass>). You can't. You have to create an ObservableVector<object>.

If all you want is something that behaves like ObservableCollection, my suggestion would be to

I've been reviewing various posts about adding/removing items from the collection doesn't update the gridview. Some of the posts are from last fall.

@Tim - are you saying that the ObservableCollection works in that scenario? Or are developers still required to do some sort of "clear" and/or reassign the data context everytime an item is added or removed? Can you or someone post an example
that works with the Release Preview?

I am totally baffled here. I have been following the online developer guidelines for data virtualization and it is stated that to implement random access data virtualization it is necessary to implement IObservableVector.
I did this but no concrete type in the project works unless 'object' , and others work if declared as WinRT legal types (by adding to a Windows Runtime COmponent project), but they cause the Enumerators to be iterated instead of indexes accessed.

The above recommendation to derive a ObservableCollection<T> is not in the guidelines. Please can you clarify what the correct approach is and why IObservableVector<T> does not work when T!=object?