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:
InstitutionFilteringString
property in the ViewModel class, which is set as the data context,ICollectionView
named Institutions
in the View ModelCode (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)
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 :)
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.