Solving the ObservableCollection bug on Windows 8

.NET, MVVM, Technical stuff, Windows 8, Work
No Comments

This post was imported from my old blog and had 2 comments which are included as a screenshot at the end of this post.

If you tried to build applications for Windows 8 with XAML/C#, you may have noticed an annoying issue: If you have a list controls (for example a GridView) and you bind the ItemsSource property to a property of type ObservableCollection<Something> on your ViewModel, the GridView is not updated when the collection’s content changes. The CollectionChanged event is raised properly, but it is not honored by the binding system.

Thankfully, this is a temporary bug, and it should be solved in the Consumer Preview version of Windows 8, due for release end of February. In the meantime, however, it is easy to circumvent this bug.

To find a solution, I researched the web and found a class named ObservableVector, for which changes are honored by the binding system. However this class had a major flaw: it forces the original ObservableCollection to be <object> instead of being strongly typed. This is of course super annoying when you are trying to share code with Silverlight/WPF/Windows Phone. So I took a good look at it, and I came up with what I think is a better implementation.

With this implementation, the original ObservableCollection can remain untouched. For instance, if you have this in the original, shared MainViewModel.cs file:

public partial class MainViewModel : ViewModelBase
{
    public ObservableCollection<UploadFileInfoViewModel> Files
    {
        get;
        set;
    }

    // ...
}

Notice that the MainViewModel class is partial. This allows easily adding the following code only into the Win8 project, into another file added only to the Win8 project, named MainViewModel.Win8.cs:

public partial class MainViewModel
{
    private ObservableVector<object, UploadFileInfoViewModel> _filesWin8;
    public ObservableVector<object, UploadFileInfoViewModel> FilesWin8
    {
        get
        {
            if (_filesWin8 == null)
            {
                Files.CollectionChanged += (s, e) =>
                {
                    if (e.NewItems != null)
                    {
                        foreach (var file in e.NewItems)
                        {
                            FilesWin8.Add(file);
                        }
                    }

                    if (e.OldItems != null)
                    {
                        foreach (var file in e.OldItems)
                        {
                            FilesWin8.Remove(file);
                        }
                    }
                };

                _filesWin8 = Files.ToObservableVector<object, UploadFileInfoViewModel>();
            }

            return _filesWin8;
        }
    }
}

This adds a new property to the MainViewModel class, which observes the old property’s CollectionChanged event. This way, by binding the GridView’s ItemsSource property to FilesWin8 instead of Files, your UI will react properly to the event.

Hopefully this little trick will help the readers while waiting for the Consumer Preview!

Cheers,
Laurent

GalaSoft Laurent Bugnion
Laurent Bugnion (GalaSoft)

Share on Facebook

This post was imported from my old blog. Original comments screenshot:
12-2-2013 12-32-16 PM

Leave a Reply