Hello ObservableVector, goodbye ObservableCollection

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 headacheUndecided.

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!


Comments (3) -

July 25. 2012 12:17 AM

David Barrows

Thanks!  This was very helpful.  Appreciate your posting this.  Glad to know Microsoft hasn't changed (even though their paradigm does, every couple of years)!

David Barrows

September 14. 2012 08:51 PM

Dzugaru

ObservableCollection<T> now properly works, please update this to stop confusion.

Check:
code.msdn.microsoft.com/.../Data-Binding-7b1d67b5
social.msdn.microsoft.com/.../26f753dd-5023-4f7c-8270-195de7b62e51

Dzugaru

September 21. 2012 01:53 AM

Diederik Krols

@ dzugaru : you're right.

Diederik Krols

Add comment

  Country flag

biuquote
  • Comment
  • Preview
Loading

Download the U2U brochure

Download Brochure

Receive the U2U Newsletter. Submit your email address:
 
 


 


Search

rss  RSS

Tags

Recent posts

None

Archive

Blogroll