开发者

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();
}


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.


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);
        }
    }

}


The problem is that ObservableCollection has its limitations. Consider that loop you have in your code, how may times does it call the Add method? How many times therefore will the changed event fire and how often will the refresh methods get called? Its not too surprising that this code gets itself in a pickle when so many changes happen in quick succession.

The ObservableCollection is great when its initially loaded, then its change event is monitored and small relatively infrequent changes are made from that point. For large scale changes its probably better to load an entirely new instance and then assign this new instance to a property.

Have the property setter re-assign the Source properties on the CollectionViewSource objects. If you still want to observe the collection you can detatch and attach your event handlers in the setter as well.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜