Search code examples
wpfpredicatecollectionviewsourceicollectionviewcollectionview

A method set as ICollectionView.Filter sees other properties in the class as null even though they are not null


I'm trying to implement a basic filtered list box in WPF. The user types something and the list is narrowed to the values beginning with the typed phrase.

I have:

  • a View with:
    • a TextBox whose Text property is bound to InstitutionFilteringString property in the ViewModel class, which is set as the data context,
    • a ListBox whose ItemSource property is bound to an ICollectionView named Institutions in the View Model
  • a ViewModel class with the properties mentioned above.

Code (with irrelevant parts cut out):

class ChooseInstitiutionAndPublisherPageViewModel : WizardPageViewModelBase
{
    private ICollectionView _institutions;
    public ICollectionView Institutions
    {
        get
        {
            return _institutions;
        }
        set
        {
            _institutions = value;
            NotifyPropertyChanged("Institutions");
        }
    }

    private string _institutionFilteringString;
    public string InstitutionFilteringString
    {
        get
        {
            return _institutionFilteringString;
        }
        set
        {
            _institutionFilteringString = value;
            NotifyPropertyChanged("InstitutionFilteringString");
            //WORKAROUND
            //Institutions.Filter = new Predicate<object>(FilterInstitutions);
            Institutions.Refresh();
        }
    }

    public ChooseInstitiutionAndPublisherPageViewModel(WizardViewModel parent)
        : base(parent)
    {
        Institutions = CollectionViewSource.GetDefaultView(CentralRepository.Instance.GetInstitutions());
        Institutions.Filter = new Predicate<object>(FilterInstitutions);
    }

    private bool FilterInstitutions(object obj)
    {
        //I may refer directly to the field or through the property, it doesn't change anything
        if (_institutionFilteringString == null || _institutionFilteringString.Length == 0)
            return true;

        //some more filtering, irrelevant
        //[cut]
    }
}

The view and the binding:

<TextBox Text="{Binding Path=InstitutionFilteringString, Mode=TwoWay}" Height="23" Margin="6,6,87,0" Name="institutionNameTextBox" VerticalAlignment="Top" TextChanged="institutionNameTextBox_TextChanged" />
<ListBox Margin="6,35" Name="institutionsListBox" ItemsSource="{Binding Path=Institutions}" IsSynchronizedWithCurrentItem="True" />

So, to the point. The setter for the InstitutionFilteringString is called correctly. Following an advice from here, the setter calls a Refresh() method on the collection view. The FilterInstitutions() method is called.

And now the bug: even though the string was set just before a second, inside the FilterInstitutions method it's null. If I go with the debugger down the call stack, from the point of view of the setter it's still set to the typed value, but inside the filtering method it's null.

In the setter there is a commented-out line of code. Uncommenting it fixes the bug, but it's hardly how it should be done.

What am I doing wrong?

(I'm not sure, but it seems to me as if the setter and the filtering method operated on two different instances of the class. But how is it possible, I create just one instance and the class is not clonable)

EDIT

I'm sorry, it seems I've lied. I've put a breakpoint in the constructor and it seems I indeed create two instances of the class and CollectionViewSource.GetDefaultView returns the same instance of ICollectionView for both. Well, but I want actually to have two views for the same collection. Well, I've followed this answer and it seems to work :)


Solution

  • do you create your Institutions once? and set the

    Institutions.Filter = new Predicate<object>(FilterInstitutions)
    

    once? if yes its ok :) can you post your code for this and also the code for FilterInstitutions methode? i do it all the way in my projects and have no problems.