Do You know, why does it throw
An unhandled exception of type 'System.NullReferenceException' occurred in PresentationFramework.dll
Additional information: Object reference not set to an instance of an object.
When I try to filter a CollectionViewSource that yields no valid rows?
The code is the following.
xaml:
<ComboBox SelectedItem="{Binding Item}" ItemsSource="{Binding Items}" IsSynchronizedWithCurrentItem="True" />
first code:
public class Model : INotifyPropertyChanged
{
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
public string Item { get; set; }
public ICollectionView Items { get; set; }
public Model()
{
Items = CollectionViewSource.GetDefaultView(new ObservableCollection<string>(new List<string> { "aaa", "bbb" }));
}
public void DoFirst()
{
Items.Filter = o => ((string)o).StartsWith("a");
}
public void DoSecond()
{
Items.Filter = o => false;
}
public event PropertyChangedEventHandler PropertyChanged;
}
DoFirst() works. DoSecond() does not. Exception comes from the Items.Filter = o => false; line.
If I remove the notify property stuff, it will not throw exception, but another interesting bug happens:
second code:
public class Model
{
public string Item { get; set; }
public ICollectionView Items { get; set; }
public Model()
{
Items = CollectionViewSource.GetDefaultView(new ObservableCollection<string>(new List<string> { "aaa", "bbb" }));
}
public void DoFirst()
{
Items.Filter = o => ((string)o).StartsWith("a");
}
public void DoSecond()
{
Items.Filter = o => false;
}
}
Empty list is shown. That's right. But then, when I DoFirst() the list shows 'aaa' right, it is not selected by default. IsSynchronizedWithCurrentItem is not firing.
If I try to defend the filter from NRE third kind of behaviour happens.
third code:
public class Model : INotifyPropertyChanged
{
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
public string Item { get; set; }
public ICollectionView Items { get; set; }
public Model()
{
Items = CollectionViewSource.GetDefaultView(new ObservableCollection<string>(new List<string> { "aaa", "bbb" }));
}
public void DoFirst()
{
try
{
Items.Filter = o => ((string)o).StartsWith("a");
} catch (NullReferenceException) { }
}
public void DoSecond()
{
try
{
Items.Filter = o => false;
} catch (NullReferenceException) { }
}
public event PropertyChangedEventHandler PropertyChanged;
}
In that case, the selectable items in the combobox are right. After DoSecond() the list is empty, but the last selected item is still selected... After DoSecond() DoFirst() also throws NullReferenceException.
If we set the current item to null, and call an OnPropertyChanged on that, the second code's stability is reached. The IsSynchronizedWithCurrentItem's property of selecting a valid Item from the ComboBox is still lost. In the following code, if I call DoFirst(), DoThird(), then "bbb" will be selected. After setting the Item to null (call DoSecond() before), it will not select "bbb":
fourth code:
public class Model : INotifyPropertyChanged
{
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
public string Item { get; set; }
public ICollectionView Items { get; set; }
public Model()
{
Items = CollectionViewSource.GetDefaultView(new ObservableCollection<string>(new List<string> { "aaa", "bbb" }));
}
public void DoFirst()
{
Items.Filter = o => ((string)o).StartsWith("a");
}
public void DoSecond()
{
Item = null;
OnPropertyChanged("Item");
Items.Filter = o => false;
}
public void DoThird()
{
Items.Filter = o => ((string)o).StartsWith("b");
}
public event PropertyChangedEventHandler PropertyChanged;
}
Br, Márton