WARNING: Article content applies to Windows 8 Developer Preview only. ObservableCollection<T> is alive and kicking in the current release.
WinRT, the new Windows 8 runtime for Metro applications, introduces a new interface for collection change notification. IObservableVector<T> replaces ye olde INotifyCollectionChanged. The ObservableCollection class still exists, you can continue to use it. Unfortunately its collection change events are ignored by the WinRT framework. I can assure you that this will give cross-platform developers a serious headache - or worse. Don't say I didn't warn you:
The IObservableVector<T> interface is defined, but the framework does not contain an implementation yet. There's no built-in collection that raises the new VectorChanged events. The fresh cocoon framework on CodePlex contains an implementation of ObservableVector<T>. Unsurprisingly it's a light-weight wrapper around an IList<T>. The class is described here.
Here's my own version of the class - I just adapted it to my property change notification mechanism:
namespace Mvvm
{
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Windows.Foundation.Collections;
using Windows.UI.Xaml.Data;
/// <summary>
/// IObservableVector<T> implementation.
/// </summary>
public class ObservableVector<T> : Collection<T>, INotifyPropertyChanged, IObservableVector<T>
{
// *** Events ***
public event PropertyChangedEventHandler PropertyChanged;
public event VectorChangedEventHandler<T> VectorChanged;
// *** Constructors ***
public ObservableVector()
: base()
{}
public ObservableVector(IList<T> list)
: base(list)
{}
// *** Protected Methods ***
protected override void ClearItems()
{
base.ClearItems();
this.PropertyChanged.Raise(this, o => o.Count);
this.PropertyChanged.Raise(this, o => o.Items);
this.OnVectorChanged(CollectionChange.Reset, 0);
}
protected override void InsertItem(int index, T item)
{
base.InsertItem(index, item);
this.PropertyChanged.Raise(this, o => o.Count);
this.PropertyChanged.Raise(this, o => o.Items);
this.OnVectorChanged(CollectionChange.ItemInserted, (uint)index);
}
protected override void RemoveItem(int index)
{
base.RemoveItem(index);
this.PropertyChanged.Raise(this, o => o.Count);
this.PropertyChanged.Raise(this, o => o.Items);
this.OnVectorChanged(CollectionChange.ItemRemoved, (uint)index);
}
protected override void SetItem(int index, T item)
{
base.SetItem(index, item);
this.PropertyChanged.Raise(this, o => o.Items);
this.OnVectorChanged(CollectionChange.ItemChanged, (uint)index);
}
// *** Event Handlers ***
protected void OnVectorChanged(CollectionChange collectionChange, uint index)
{
this.OnVectorChanged(new VectorChangedEventArgs(collectionChange, index));
}
protected virtual void OnVectorChanged(IVectorChangedEventArgs e)
{
if (this.VectorChanged != null)
this.VectorChanged(this, e);
}
// *** Private Sub-classes ***
private class VectorChangedEventArgs : IVectorChangedEventArgs
{
// *** Fields ***
private readonly CollectionChange collectionChange;
private readonly uint index;
// *** Constructors ***
public VectorChangedEventArgs(CollectionChange collectionChange, uint index)
{
this.collectionChange = collectionChange;
this.index = index;
}
// *** Properties ***
public CollectionChange CollectionChange
{
get
{
return this.collectionChange;
}
}
public uint Index
{
get
{
return this.index;
}
}
}
}
}
I consider this temporary code - I assume that next versions of WinRT will have a native version of ObservableVector<T>.
I built a small sample application around to demonstrate the usage of the class in a MVVM application: all the work is done through data and command bindings. The app just manages two collections of Dragons: 'All Dragons' and 'Favorites'. The selected Dragon in each ListBox can be moved to the other collection by clicking the buttons in the middle. Here's how the app looks like:
By the way, in the current version of WinRT -Developer Preview- the collection changed events are only handled if T is object, so you have to define the collection as follows:
public ObservableVector<object> Dragons { get; set; }
For any other type -like ObservableVector<string> or ObservableVector<Dragon>- the change events will be simply ignored by the binding mechanism. That's another headache.
You use the class exactly the same way as good old ObservableCollection, e.g. as ItemsSource to a an ItemControl:
<ListBox DataContext="{Binding}"
ItemsSource="{Binding Dragons}"
SelectedItem="{Binding SelectedDragon, Mode=TwoWay}" />
Here's the full source code, it's built with Visual Studio 11 Developer Preview: U2UConsult.WinRT.ObservableVector.Sample.zip (47,83 kb)
Enjoy!