How to get real count of a CollectionView, when Filter is in use?

11,287

Solution 1

why don't you use this?

<Label Content="{Binding ModelView.RowViewModelsCollectionView.Count}"/>

This is a little example.

<Window x:Class="WPFValidation.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window"
        Height="300"
        Width="300">
  <Grid>

    <Grid.RowDefinitions>
      <RowDefinition Height="Auto" />
      <RowDefinition Height="Auto" />
      <RowDefinition />
    </Grid.RowDefinitions>

    <TextBox Grid.Row="0"
             Text="{Binding FilterText, UpdateSourceTrigger=PropertyChanged}" />
    <TextBlock Grid.Row="1"
               Text="{Binding ModelListView.Count}" />
    <ListBox Grid.Row="2"
             ItemsSource="{Binding ModelListView}" />

  </Grid>
</Window>

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Data;

namespace WPFValidation
{
  /// <summary>
  /// Interaction logic for MainWindow.xaml
  /// </summary>
  public partial class MainWindow : Window
  {
    public MainWindow() {
      this.DataContext = new ModelView();
      this.InitializeComponent();
    }
  }

  public class ModelView : INotifyPropertyChanged
  {
    public event PropertyChangedEventHandler PropertyChanged;

    private ICollectionView modelListView;

    private ICollection<string> collection;

    public ModelView() {
      this.collection = new ObservableCollection<string>(new[] {"test1", "test2", "filtering"});
    }

    public ICollectionView ModelListView {
      get { return this.modelListView ?? this.GetModelListView(); }
    }

    private ICollectionView GetModelListView() {
      var collectionView = CollectionViewSource.GetDefaultView(this.collection);
      collectionView.Filter += o => o == null || string.IsNullOrEmpty(this.FilterText) || o.Equals(this.FilterText);
      return collectionView;
    }

    private string filterText;

    public string FilterText {
      get { return this.filterText; }
      set {
        if (value != this.filterText) {
          this.filterText = value;
          this.ModelListView.Refresh();
          this.RaisePropertyChange("FilterText");
        }
      }
    }

    private void RaisePropertyChange(string propertyName) {
      var eh = this.PropertyChanged;
      if (eh != null) {
        eh(this, new PropertyChangedEventArgs(propertyName));
      }
    }
  }
}

Solution 2

@punker76, is correct in saying that binding should be done to the collection view's Count property directly...

Reason is that CollectionView has implemented INotifyPropertyChanged and notifies property changes for its Count property whenever commit, filtering, grouping, sorting takes place on it...

So assuming that you have RowViewModelsCollectionView as a public / internal property of your view model,

  <Label Content="{Binding RowViewModelsCollectionView.Count}"/> 

.... should work just fine...

Share:
11,287
Houman
Author by

Houman

I'm a thinker and a dreamer. Love pets but don't have any. I'm a passionate tech entrepreneur.

Updated on June 30, 2022

Comments

  • Houman
    Houman almost 2 years

    When I have a <Label Content="{Binding ItemCount}"/> on my View to bind to a property on the ViewModel.

    On the viewmodel I have the property defined as

    public int ItemCount
    {
        get { RowViewModelsCollectionView.Count; }
    }
    

    I am clearly asking for count on the CollectionView, where I am expecting to get the count of only visible items. Unfortunately I get the count of the entire rows, even the ones not showing on the view due the filter.

    Update:

    in Ctor:

    RowViewModelsCollectionView= new ListCollectionView(rowViewModels) {Filter = Contains};
    
    
    private bool Contains(object obj)
            {
                RowViewModel rowViewModel = obj as RowViewModel;
    
                if (rowViewModel != null && Books.ContainsKey(rowViewModel.Book))
                {
                    RaisePropertyChanged("ItemCount"); // Trying out to raise it without joy
                    return true;
                }
    
                return false;
            }
    

    How should I fix this?