Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Update CollectionViewSource When ObservableCollection Changes WP7

I have anObservableCollection for my underlying list of items. I have 2 CollectionViewSource that are different filters of the data. I want any changes that happen to be reflected in the CollectionViewSource.

In my view model constructor, I set the filter predicates. I then get the data an add it to the ObservableCollection. I am subscribed to the CollectionChanged event, and am refreshing the CVS there.

I am seeing some really weird things with this though. Either the items don't show up in my ListBox that is bound to the CVS, or duplicates will show up. If I call Refresh on the CVS outside of the CollectionChanged event after I change the ObservableCollection, everything seems to work fine. I would really like to be able to just refresh when the collection changes and not worry about having to call refresh every time something is done that changes it.

public MyViewModel()
{
    oc.CollectionChanged += OcCollectionChanged;

    cvs1.Source = oc;
    cvs1.View.Filter = new Predicate<object>( ... );

    cvs2.Source = oc;
    cvs2.View.Filter = new Predicate<object>( ... );

    foreach( var data in myData )
    {
        oc.Add( data );
    }
}

private void OcCollectionChanged( object sender, NotifyCollectionChangedEventArgs e )
{
    cvs1.View.Refresh();
    cvs2.View.Refresh();
}
like image 245
Josh Close Avatar asked Apr 15 '11 14:04

Josh Close


2 Answers

CollectionViewSource doesn't implement INotifyPropertyChanged, so to get any underlying data changes into the UI you need to call Refresh on the View as you are already doing. CollectionViewSource is also data source agnostic, so the fact that the source is an ObservableCollection that raises property change notification is immaterial, because the CollectionViewSource is not listening.

I think the solution you have of manually refreshing the views when the collection changes is the best you're going to get without re-thinking your data structures.

like image 77
Derek Lakin Avatar answered Oct 15 '22 02:10

Derek Lakin


I am using a modified ObservableCollection class that specifically overcomes the limitation mentioned above (CollectionChangedEvent event firing multiple times), found here. (ObservableCollectionEx - blocks the CollectionChangedEvent until all are added by adding an AddRange method)

I've been using it for about 2 years now, and it works terrifically well for large collection changes.

Update:
It appears that link is down, so here's the code:

public class ObservableCollectionEx<T> : ObservableCollection<T>
{
    public ObservableCollectionEx()
        : base()
    {
        _suspendCollectionChangeNotification = false;
    }


    bool _suspendCollectionChangeNotification;

    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        if(!_suspendCollectionChangeNotification)
        {
            base.OnCollectionChanged(e);
        }
    }

    public void SuspendCollectionChangeNotification()
    {
        _suspendCollectionChangeNotification = true;
    }

    public void ResumeCollectionChangeNotification()
    {
        _suspendCollectionChangeNotification = false;
    }


    public void AddRange(IEnumerable<T> items)
    {
        this.SuspendCollectionChangeNotification();
        int index = base.Count;
        try
        {
            foreach(var i in items)
            {
                base.InsertItem(base.Count, i);
            }
        }
        finally
        {
            this.ResumeCollectionChangeNotification();
            var arg = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
            this.OnCollectionChanged(arg);
        }
    }

}
like image 2
outbred Avatar answered Oct 15 '22 03:10

outbred