How to get real count of a CollectionView, when Filter is in use?
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...
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, 2022Comments
-
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?