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);
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With