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