Answered What happened to INotifyCollectionChanged?

  • Thursday, September 15, 2011 5:59 PM
     
      Has Code

    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.
    
    
    when setting it as a DataContext on a control.

Answers

  • Friday, September 16, 2011 6:55 AM
     
     Answered

    Thanks for trying out the new bits. As you've noticed INotifyCollectionChanged is not recognized by XAML - this is something we're looking into changing into the future.

    Currently there is a known bug where where only ObservableVector<object> works, this is something that will be fixed in a future release.


    Base Class Library Team (BCL) | My Blog: http://davesbox.com
    • Marked As Answer by GrayShade Friday, September 16, 2011 7:18 AM
    •  

All Replies

  • Friday, September 16, 2011 6:55 AM
     
     Answered

    Thanks for trying out the new bits. As you've noticed INotifyCollectionChanged is not recognized by XAML - this is something we're looking into changing into the future.

    Currently there is a known bug where where only ObservableVector<object> works, this is something that will be fixed in a future release.


    Base Class Library Team (BCL) | My Blog: http://davesbox.com
    • Marked As Answer by GrayShade Friday, September 16, 2011 7:18 AM
    •  
  • Friday, September 16, 2011 7:19 AM
     
      Has Code

    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?



    • Edited by jbienz Friday, September 16, 2011 7:21 AM
    •  
  • Friday, September 16, 2011 7:21 AM
     
      Has Code

    You could write a type-safe wrapper or only implicitly implement IObservableVector<object>. Somewhat like:

    class ObservableVectorWrapper<T> : IObservableVector<T>, IObservableVector<object>
    {
        public Add(T item) // or was it Append?
        {
            (this as IObservableVector<object>).Add(item);
        }
    
        IObservableVector<object>.Add(object item) { /* ... */ }
    
        /* ...*/
    }
    
    


     


    • Edited by GrayShade Friday, September 16, 2011 5:26 PM
    •  
  • Friday, September 16, 2011 7:24 AM
     
     

    But isn't that what the ObservableVector<T> class does in the Binding sample?

     

    I'm referring to this sample BTW:

     

    http://code.msdn.microsoft.com/windowsapps/Data-Binding-7b1d67b5

  • Friday, September 16, 2011 7:28 AM
     
     
    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>.
  • Friday, September 16, 2011 3:05 PM
     
     
    As mentioned below, there's currently a bug that prevents this from working. This should work in a future release.
    Base Class Library Team (BCL) | My Blog: http://davesbox.com
  • Friday, September 16, 2011 4:49 PM
     
     

    @jbienz - just to be clear, related to:

    "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?"

    For the Build bits, you need to use ObservableVector<object>.

    Joe

  • Thursday, September 29, 2011 7:03 AM
     
     

    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.

  • Wednesday, October 05, 2011 9:27 PM
     
     

    For the Build bits, you need to use ObservableVector<object>.


    Is ObservableVector going to replace ObservableCollection?  Will ObservableCollection be updated to actually work? 
    • Edited by Robert Zhu Wednesday, October 05, 2011 9:27 PM
    •  
  • Thursday, October 06, 2011 12:42 AM
     
     
    We're investigating how to make this integration better.
    Base Class Library Team (BCL) | My Blog: http://davesbox.com
  • Thursday, October 06, 2011 7:43 AM
     
      Has Code

    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:

     

    <ItemsControl ItemsSource="{Binding Path=MyCollection, Converter={StaticResource ObservableCollectionAdapter}}"/>
    

     

    You can read about it here:

    http://www.scottlogic.co.uk/blog/colin/2011/10/using-observablecollection-with-winrt-via-a-little-shim/

    Regards, Colin E.

  • Friday, December 09, 2011 3:50 AM
     
      Has Code

    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.  

     

            public ObservableVector(INotifyCollectionChanged list)
            {
                if (list is IList<T>)
                {
                    _internalCollection = list as IList<T>;
                    _readOnlyCollection = new ReadOnlyCollection<T>((IList<T>)list);
                }
                else
                {
                    throw new Exception("Must implement IList<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

    • Copy the ObservableVector<T> class from the data binding sample
    • Make it not generic 
    public class ObservableVector : IObservableVector<object>, IList<object>, IEnumerable<object>, IEnumerable
    {
    
    • Make the constructor take no arguments and just create innerList in the constructor
            public ObservableVector()
            {
                _internalCollection = new List<object>(); ;
                _readOnlyCollection = new ReadOnlyCollection<object>(_internalCollection);
            }
    
    
    • Use ObservableVector anywhere you would use an ObservableCollection to hold you over till the beta is released.

    If you want to keep using ObservableCollection then you will need to wire up the collection change events your self in the ObservableVector implementation.

     

    Hope this helps.



  • Friday, March 09, 2012 5:56 PM
     
     
    @Robert - we believe this to be fixed and that ObservableCollection works fine now...

    Tim Heuer | Program Manager, XAML | http://timheuer.com/blog | @timheuer

    (if my post has answered your question, please consider using the 'mark as answer' feature in the forums to help others)