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.
精彩评论