6

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?

Houman
  • 64,245
  • 87
  • 278
  • 460
  • Possible duplicate http://stackoverflow.com/questions/5623736/filtered-collectionview-gives-wrong-count How do you get the CollectionView? – dowhilefor Nov 21 '11 at 11:14
  • Its not a duplicate. The solution there is using a GetDefaultView(). We can't do this in our app due the nature of requirements. – Houman Nov 21 '11 at 11:19
  • Well maybe because you don't use GetDefaultView you always recreate a new view, thus on one you have the filter, but you use the other to get the count. – dowhilefor Nov 21 '11 at 11:23
  • I don't think so. Please have a look at the updated code, if it makes sense, otherwise I am happy to change the code. Thanks – Houman Nov 21 '11 at 11:28

2 Answers2

5

@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...

WPF-it
  • 19,625
  • 8
  • 55
  • 71
2

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));
      }
    }
  }
}
apaderno
  • 28,547
  • 16
  • 75
  • 90
punker76
  • 14,326
  • 5
  • 58
  • 96