C# – How to correctly bind (update) a DataGrid with a CollectionViewSource

ccollectionviewsourcedatagridobservablecollectionwpf

I have a (WPF) DataGrid where I attach an ICollectionView as

XAML:

 <DataGrid x:Name="TodoList" ItemsSource="{Binding TodoItemsCollection}" DataContext="{Binding}" />

Constructor (Code behind)

 TodoItemsCollection = CollectionViewSource.GetDefaultView(Storage.TodoItems);
 TodoItemsCollection.Filter = TodoItemsFilter;

(Storage.TodoItems is an ObservableCollection)

TodoItemsCollection Property

 private ICollectionView _todoItemsCollection;
 public ICollectionView TodoItemsCollection
 {
     get { return _todoItemsCollection; }
     set 
     {
         if (_todoItemsCollection != value)
         {
             _todoItemsCollection = value;
             OnPropertyChanged("TodoItemsCollection");
         }
     }
 }

Storage.TodoItems is an ObservableCollection where a tracker adds, edits and removes items.
This changes should immediately be displayed in the DataGrid.

However, the problem is that all those changes are not reflected in the DataGrid (i.e. the DataGrid is not updated).
For example if I call TodoItemsCollection.Refresh(), nothing changes.
With a refresh button (only for testing purposes), I set the ItemsSource of the DataGrid to null and reset it (TodoItemsCollection = CollectionViewSource.GetDefaultView(Storage.TodoItems);).
This manual refresh displays the new/changed/removed items.
However, the filtering then doesn't work anymore.

I read about three dozens of blog posts and couldn't find a solution to my problems.
Usually, calling Refresh() or resetting the ItemsSource worked well for them.

Any suggestions are really much appreciated!!

Best Answer

in addition to liquidsnake786 answer - you can use the ObservableCollection instead of the ICollectionView and filtering/sorting will work just the same as long as you use CollectionViewSource.GetDefaultView(Storage.TodoItems).

the more important thing is that the Storage.TodoItems should just initialize once otherwise TodoItemsCollection = CollectionViewSource.GetDefaultView(Storage.TodoItems); have to be called every time a new Storage.TodoItems is created. simply use clear() add() and remove() to alter your Storage.TodoItems.

EDIT: the usual way:

-just create a OberservableCollection once (eg. within ctor). this collection will handle Add and Remove and notify the WPF ui.

this.MyCollection = new OberservableCollection<TodoItem>();

-your wrapped item "TodoItem" should implement INotifyPropertyChanged to notifiy changes/edits to WPF ui

-create you ICollectionView once(eg. within the ctor) like you did

 this.MyView = CollectionViewSource.GetDefaultView(MyCollection);
 this.MyView.Filter = TodoItemsFilter;

-alter your source collection with clear, add, remove

 this.MyCollection.Clear();
 foreach(var item in MyNewCollectionFromAnywhere)
 { this.MyCollection.Add(item);}
 this.MyView.Refresh();

-be sure that your datacontext and binding is right in xaml :) btw DataContext="{Binding}" makes no sense for me.

<DataGrid ItemsSource="{Binding MyView}"/>
Related Topic