10

According to the documentation, the Count of a filtered CollectionView should only be the count of items that pass the filter. Given this code:

List<string> testList = new List<string>();
testList.Add("One");
testList.Add("Two");
testList.Add("Three");
testList.Add("1-One");
testList.Add("1-Two");
testList.Add("1-Three");
CollectionView testView = new CollectionView(testList);
int testCount1 = testView.Count;
testView.Filter = (i) => i.ToString().StartsWith("1-");
int testCount2 = testView.Count;

I would therefore expect testCount1 to be 6, and testCount2 to be 3. However, both are 6. If I manually iterate through the CollectionView and count the items, I do get 3, but Count returns 6 always.

I've tried calling Refresh on the CollectionView, just to see if that would correct the result, but there was no change. Is the documentation wrong? Is there a bug in CollectionView? Am I doing something wrong that I just can't see?

David Mullin
  • 688
  • 1
  • 8
  • 21

3 Answers3

5

Try

ICollectionView _cvs = CollectionViewSource.GetDefaultView(testList);

instead of

CollectionView testView = new CollectionView(testList);    
Bruno
  • 1,944
  • 13
  • 22
  • Actualy, even if the solution above return the correct amount of results in your case, if you check in debug the "Raw results" of you collection view after filter, there is anly 3 items althought the count property is still à 6... – Bruno Apr 11 '11 at 16:33
  • +1, using `CollectionViewSource.GetDefaultView` is the correct method. – user7116 Apr 11 '11 at 16:36
  • All that CollectionViewSource.GetDefaultView does is create a ListCollectionView and cache that in an internal map. Also, that gives you one global CollectionView for the base collection, which I absolutely don't want - I'm definitely trying to get a local instance. – David Mullin Apr 11 '11 at 17:15
3

If you switch to ListCollectionView, then it works as expected:

CollectionView testView = new ListCollectionView(testList);
int testCount1 = testView.Count;
testView.Filter = (i) => i.ToString().StartsWith("1-");
int testCount2 = testView.Count;

This seems to work for CollectionView, so this definitely points to a bug:

CollectionView testView = new CollectionView(this.GetTestStrings());

private IEnumerable<string> GetTestStrings() {
    yield return "One";
    yield return "Two";
    yield return "Three";
    yield return "1-One";
    yield return "1-Two";
    yield return "1-Three";
}
CodeNaked
  • 40,753
  • 6
  • 122
  • 148
  • +1, additionally, `CollectionViewSource.GetDefaultView` will ensure the correct `CollectionView` is retrieved. – user7116 Apr 11 '11 at 16:36
  • @sixlettervariables - Yeah, that's why I upvoted Bruno's answer ;-) – CodeNaked Apr 11 '11 at 16:37
  • However, if my source list doesn't implement IList (for instance, if I had a Collection), then I can't use a ListCollectionView, I must use the base CollectionView. – David Mullin Apr 11 '11 at 17:13
  • @David - Actually it appears that if you pass an ICollection, then it works as expected. It seems that the CollectionView doesn't handle ILists well. – CodeNaked Apr 11 '11 at 17:22
  • @David - Sorry, I meant an IEnumerable. – CodeNaked Apr 11 '11 at 17:23
  • @David - I updated my answer, but looks like you'd have to switch the view type based on whether it implements IList or not. – CodeNaked Apr 11 '11 at 17:25
0

There seems a bug, I checked reflector may be if you try calling "Refresh" that should give you correct Count. As per documentation, they say that you do not need to call Refresh as setting filter will refresh it automatically but I think it is not happening as they also mention that they cache the value of count from last change.

It would work perfect if you set the Filter before you add items. Or you will have to call Refresh.

Akash Kava
  • 39,066
  • 20
  • 121
  • 167