ObservableCollection in WinRT

I have been learning WinRT, new Windows 8 run time for developing Windows 8 application for a little while now.  I am using my CodePlex project as study project.  One of my goals is have an ability to persist collections of object into file system, loosely called database.  I really want my collections to be bindable, so I attempted to use ObservableCollection<T> as the base class for my collections.  This worked just find in Windows Phone 7 and Silverlight based projects.  The same however does not hold true in WinRT.  It contains a number of bases classes that WinRT controls such as ListBox listen to instead of INotifyCollectionChanged.  Specifically, it is IObservableVector<T>.  There is a sample implementation in one of the WinRT sample apps, but I really did not like how it was done – via extension method on INotifyCollectionChanged.  What I really wanted to do is extend Observable Collection, because I think Microsoft will eventually have an implementation for IObservableVector<T>, maybe they would event extend the observable collection itself.  First thing I ran into is that if you use IObservableVector with T anything other than object, your program will throw “bad image” exception.  So, here is the outline of my solution.

  • Use Observable Collection as base class
  • Implement IObservableVector<object>

That should do it, right?

So, I am starting with this declaration:

public class ExtendedObservableCollection<T> : ObservableCollection<T>, IObservableVector<object>

Then I use smart tag for IObservableVector and let Visual Studio fill in the necessary interfaces I have to implement.  Then I simply call base methods of Observable Collection for the majority of implementation, casting object to T as necessary.  Simple and efficient, and most importantly, something I could simply remove down the road as WinRT API becomes more mature.  Here is the final class.

using System;
using
System.Collections.Generic;
using
System.Collections.ObjectModel;
using
Windows.Foundation.Collections;
 

namespace
WinRTDatabase.Core
{
   
/// <summary>

   
/// Class that works for data bindings for WinRT list based controls
   
/// </summary>
   
/// <typeparam name="T"></typeparam>
   
public class ExtendedObservableCollection<T> : ObservableCollection<T>, IObservableVector<object>
    {
 
       
/// <summary>

       
/// Raises collection changed event
       
/// </summary>
       
/// <param name="e">Event arguments for collection changed event</param>
       
protected override void OnCollectionChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
           
base
.OnCollectionChanged(e);
           
switch
(e.Action)
            {
               
case
System.Collections.Specialized.NotifyCollectionChangedAction.Add:
                    OnVectorChanged(CollectionChange.ItemInserted, (
uint
)e.NewStartingIndex);
                   
break
;
               
case
System.Collections.Specialized.NotifyCollectionChangedAction.Move:
                    OnVectorChanged(CollectionChange.Reset, (
uint
)e.NewStartingIndex);
                   
break
;
               
case
System.Collections.Specialized.NotifyCollectionChangedAction.Remove:
                    OnVectorChanged(CollectionChange.ItemRemoved, (
uint
)e.OldStartingIndex);
                   
break
;
               
case
System.Collections.Specialized.NotifyCollectionChangedAction.Replace:
                    OnVectorChanged(CollectionChange.ItemChanged, (
uint
)e.NewStartingIndex);
                   
break
;
               
case
System.Collections.Specialized.NotifyCollectionChangedAction.Reset:
                    OnVectorChanged(CollectionChange.Reset, (
uint
)e.NewStartingIndex);
                   
break
;
               
default
:
                   
break
;
            }
        }
       
protected void OnVectorChanged(CollectionChange collectionChange, uint
index)
        {
           
if (VectorChanged != null
)
            {
                VectorChanged(
this, new VectorChangedEventArgs
(collectionChange, index));
            }
        }
 
       
public event VectorChangedEventHandler<object
> VectorChanged;
 
       
public int IndexOf(object
item)
        {
           
return base
.IndexOf((T)item);
        }
 
       
public void Insert(int index, object
item)
        {
           
base
.InsertItem(index, (T)item);
        }
 
       
public new object this[int
index]
        {
           
get

            {
               
return base[index];
            }
           
set

            {
               
base[index] = (T)value;
            }
        }
 
       
public void Add(object
item)
        {
           
base
.Add((T)item);
        }
 
       
public bool Contains(object
item)
        {
           
return base
.Contains((T)item);
        }
 
       
public void CopyTo(object[] array, int
arrayIndex)
        {
            T[] newArray =
new
T[array.Length];
           
for (int
i = 0; i < array.Length; i++)
            {
                newArray[i] = (T)array[i];
            }
            CopyTo(newArray, arrayIndex);
        }
 
       
public bool
IsReadOnly
        {
           
get { return false
; }
        }
 
       
public bool Remove(object
item)
        {
           
if
(Contains(item))
            {
               
base
.Remove((T)item);
               
return true
;
            }
           
return false
;
        }
 
       
public new IEnumerator<object
> GetEnumerator()
        {
           
return base.GetEnumerator() as IEnumerator<object
>;
        }
    }
}

 

Thanks.

5 Comments

  1. I’m trying to use something of this sort from a WinRT component. Basically the component will expose some sort of Observable list that I can bind to my View and update automatically as items are added/removed from the list.

    Using the implementation that you have here gives me the error message ‘Windows Runtime types cannot be generic’.

    Do you know if it is possible to expose some sort of Observable list from a RT component?

  2. If I try and expose an ObservableCollection I get the following:

    Although this generic type is not a valid Windows Runtime type, the type or its generic parameters implement interfaces that are valid Windows Runtime types. Consider changing the type ‘System.Collections.ObjectModel.ObservableCollection’ in the method signature to one of the following types instead: ‘System.Collections.Generic.IList, System.Collections.Generic.IReadOnlyList, System.Collections.Generic.IEnumerable’.

    This error brought me here in the first place.

Leave a Reply to Sergey Barskiy Cancel reply

Your email address will not be published. Required fields are marked *