4

I am trying to set up a ListBox that gets it's data from a CollectionViewSource. What I want to happen is that when I update the underlying data source the ListBox also updates. My Xaml looks like this...

<Window.Resources>
    <ObjectDataProvider x:Key="AppTests" ObjectType="{x:Type Application:AppTestProvider}" MethodName="GetAppTests" />
    <CollectionViewSource x:Key="cvs" Source="{StaticResource AppTests}">
        <CollectionViewSource.SortDescriptions>
            <scm:SortDescription PropertyName="Priority" Direction="Ascending" />
        </CollectionViewSource.SortDescriptions>
    </CollectionViewSource>
</Window.Resources>

<Grid>
    <ListBox x:Name="TestList" ItemsSource="{Binding Source={StaticResource cvs}}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding TestName}" />                    
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</Grid>

This displays the data fine but if I change the underlying data then the changes don't appear on the grid until I call the cvs.View.Refresh() method in the code behind.

How can I make this "observable" so the changes happen automatically?

Note: The reason for using the CVS was to provide sorting to the list based on a property in the underlying objects.

Remotec
  • 10,304
  • 25
  • 105
  • 147
  • 1
    Use ObservableCollection. – Nitesh Jul 29 '13 at 08:12
  • After posting this I also read that a CollectionViewSource does not observe changes. Is that correct and can that affect what I am doing? – Remotec Jul 29 '13 at 08:25
  • No, its not true. `CollectionViewSource` listens to Collection changed if underlying source collection implements it. – Rohit Vats Jul 29 '13 at 08:40
  • @RohitVats, it is true in a sense, that `CollectionViewSource` does not observe changes _on its own_. It does not create notification events, but simply forwards them to UI layer. – Nikita B Jul 29 '13 at 09:50
  • @Nikita - Yeah that's what i wrote in my answer as well - `It propagate INotifyCollectionChanged events if the underlying collection implements it.` – Rohit Vats Jul 29 '13 at 09:59

2 Answers2

6

To see changes, made to the collection itself (e.g. adding and removing items), the collection should implement INotifyCollectionChanged (ObservableCollection is the base implementation of this interface). To see changes, made to items in the collection (e.g. modifying a specific property on specific item), your item object should implement INotifyPropertyChanged.

CollectionViewSource is a layer between UI and actual collection, which provides some additional control over how the collection is displayed (sorting, filtering, grouping, etc.). It only passes notifications to UI if underlying data supports notifications (by implementing interfaces mentioned above).

Ray Booysen
  • 28,894
  • 13
  • 84
  • 111
Nikita B
  • 3,303
  • 1
  • 23
  • 41
  • This is working and changes made to the `TestName` property of the underlying object updates fines. However, changing the `Priority` property, of which the list is sorted on, does not cause automatic re-sorting of the list. Maybe this isn't possible anyway. – Remotec Jul 29 '13 at 18:09
  • It does not make sense to resort on every property change. Because a) after modifying property in ui modified row might instantly move somewhere which kills usability, b) constant sorting affects performance. If you absolutely need to resort on property changes - you can simply subscribe to `PropertyChanged` event of your items and call `cvs.View.Refresh()` in the event handler. – Nikita B Jul 30 '13 at 05:23
  • I should have mentioned - there will be no ability for the user to change the sort order. This functionality is so that failed tests can be moved to the top by the program. Maybe the ListBox isn't ultimately the best tool for this job. – Remotec Jul 30 '13 at 07:34
1

I suspect you are using List<T> instead of ObservableCollection<T> as underlying source collection for your CollectionViewSource.

ICollectionView will give you the ability to filter, sort, or group the collection along with propagating INotifyCollectionChanged events if the underlying collection implements it.

Moreover in case you want to refresh your collection when any property change in T class you have to manually call Refresh of your collection OR can use ICollectionViewLiveShaping introduced in .Net4.5.

Refer to my answer here for both approaches - Automatically Refresh ICollectionView

Community
  • 1
  • 1
Rohit Vats
  • 79,502
  • 12
  • 161
  • 185