Changing CollectionViewSource Source in a MVVM world
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.
aidesigner
Updated on June 16, 2022Comments
-
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 about 12 yearsThis 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 about 12 yearsThanks 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.