Changing CollectionViewSource Source in a MVVM world

17,450

I would choose one of the two following solutions.

First, you could take your ObservableCollection and create an ICollectionView (grouping, sorting) once. Instead of replacing the ObservableCollection you can use .Clear() and add the items from the new Collection. This has the additional bonus of not breaking your grouping and sorting.

Second approach: whenever you replace your ObservableCollection you have to create a new ICollectionView for sorting and grouping.

 this._view = (ICollectionView)CollectionViewSource.GetDefaultView(this.MyCollection);

You can simply bind to your collection if you take the DefaultView

 <DataGrid Name="grid" ItemsSource="{Binding MyCollection}" />

and you can throw away your CollectionViewSource code binding stuff.

Share:
17,450
aidesigner
Author by

aidesigner

Updated on June 16, 2022

Comments

  • aidesigner
    aidesigner almost 2 years

    Edited: I created a new VS2010 WPF appilication with just 3 files MainWindow.xaml, MainWindow.xaml.cs, and MainWindowViewModel.cs (Listed Below). If someone feels really helpful you can recreate the problem in seconds (copy/paste). When you run the app the DataGrid will display string "OldCollection" which is wrong. If you change the ItemsSource binding to MyCollection it displays "NewCollection" which is correct.

    Full Description: At first I had a DataGrid with its ItemsSource bound to MyCollection. I have/need a method UpdateCollection that assigns a new ObservableCollection<> to MyCollection. With the addition of NotifyPropertyChange to MyCollection the UI updates.

    Next it became necessary to introduce a CollectionViewSource to enable grouping. With the UI bound to MyCollectionView, calls to UpdateCollection now have no effect. The debugger confirms that MyCollectionView always contains the initial MyCollection. How can I get my NewCollection to be reflected in the View? I have tried View.Refresh(), Binding CollectionViewSource, and countless other strategies.

    Note: Primarily others are concerned with the changes to Collection items not updating the view (grouping/sorting) without calling Refresh. My problem is I am assigning a brand new collection to CollectionViewSource and the view/UI never changes.

    // MainWindow.xaml
    <Window x:Class="CollectionView.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
        <Grid>
            <DataGrid Name="grid" ItemsSource="{Binding MyCollectionView}" />
        </Grid>
    </Window>
    
    //MainWindow.xaml.cs
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Windows;
    
    namespace CollectionView
    {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
                DataContext = new MainWindowViewModel();
            }
        }
    }
    
    //MainWindowViewModel.cs:
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Collections.ObjectModel;
    using System.Windows.Data;
    using System.ComponentModel;
    
    namespace CollectionView
    {
        class MainWindowViewModel : INotifyPropertyChanged
        {
            public MainWindowViewModel()
            {
                MyCollection = new ObservableCollection<MyObject>() { new MyObject() { TestString = "OldCollection" } };
    
                MyCollectionViewSource = new CollectionViewSource();
    
                // Bind CollectionViewSource.Source to MyCollection
                Binding MyBind = new Binding() { Source = MyCollection };
                BindingOperations.SetBinding(MyCollectionViewSource, CollectionViewSource.SourceProperty, MyBind);
    
                // The DataGrid is bound to this ICollectionView
                MyCollectionView = MyCollectionViewSource.View;
    
                // This assignment here to demonstrate that View/UI does not update to show "NewCollection"
                MyCollection = new ObservableCollection<MyObject>() { new MyObject() { TestString = "NewCollection" } };
            }
    
            // Collection Property
            // NotifyPropertyChanged added specifically to notify of MyCollection re-assignment
            ObservableCollection<MyObject> _MyCollection;
            public ObservableCollection<MyObject> MyCollection
            {
                get { return _MyCollection; }
                set
                {
                    if (value != _MyCollection)
                    {
                        _MyCollection = value;
                        NotifyPropertyChanged("MyCollection");
                    }
                }
            }
    
            public CollectionViewSource MyCollectionViewSource { get; private set; }
            public ICollectionView MyCollectionView { get; private set; }
    
            // Method updates MyCollection itself (Called via ICommand from another ViewModel)
            public void UpdateCollection(ObservableCollection<MyObject> NewCollection)
            {
                MyCollection = NewCollection;
            }
    
            public event PropertyChangedEventHandler PropertyChanged;
    
            private void NotifyPropertyChanged(String info)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(info));
                }
            }
        }
    
        class MyObject
        {
            public string TestString { get; set; }
        }
    }
    

    Thanks,

  • aidesigner
    aidesigner about 12 years
    This problem is so frustrating I edited the question (See Edited Section) so anyone can reproduce the issue in seconds. As per your suggestion I added the CollectionViewSource binding to above code, but it had no effect.
  • aidesigner
    aidesigner about 12 years
    Thanks for the try, but I prefer something else for the reasons you stated. Also I can't access the x:Key uiMyCollectionGrid from my ViewModel with the MVVM pattern. Interestingly the CollectionViewSource document msdn.microsoft.com/en-us/library/… says "changes raised by the CollectionChanged event are propagated to the views". Perhaps it is eating the PropertyChange which is what actually fires when the property MyCollection is assign a new value.