Reputation: 63
So the thing is, yesterday I wanted to make a searchbar for filtering a datagrid. I succeded in doing this but when I was looking it over today i realized I have no idea why it's working. Here's what's confusing me:
Basically I have a datagrid with its ItemsSource set to an ObservableCollection called Equipments. In order to filter on Equipments I have also created an ICollectionView called EquipmentView, which is just a mirror of Equipments that I can do filtering on.
Equipments is populated in the viewmodel from a table in my database like this:
public async Task LoadAsync()
{
try
{
var lookup = await _equipmentLookupDataService.GetEquipmentLookupAsync();
Equipments.Clear();
foreach (var item in lookup)
{
Equipments.Add(item);
}
EquipmentView = CollectionViewSource.GetDefaultView(Equipments);
EquipmentView.Filter = new Predicate<object>(Filter);
}
catch (Exception e)
{
MessageBox.Show(e.Message, "An error occurred", MessageBoxButton.OK, MessageBoxImage.Warning);
//create new error object from the exception and add to DB
Error error = new Error
{
ErrorMessage = e.Message,
ErrorTimeStamp = DateTime.Now,
ErrorStackTrace = e.StackTrace,
LoginId = CurrentUser.LoginId
};
await _errorDataService.AddError(error);
}
}
EquipmentView.Filter calls the Filter method:
public bool Filter(object obj)
{
var data = obj as EquipmentLookup;
if (EquipmentView != null)
{
if (!string.IsNullOrEmpty(_filterString))
{
string allcaps = _filterString.ToUpper();
return data.TypeName.StartsWith(_filterString) || data.TypeName.StartsWith(allcaps);
}
return true;
}
return false;
}
It returns true only when the TypeName property starts with the filterstring, which is the string that's bound to my searchbar.
Now I THOUGHT I just had to set the datagrid ItemsSource to EquipmentView. If I do that everything works fine and the datagrid only shows whatever matches with the searchbar.
Apparently though, if I set the itemsSource on the datagrid back to Equipments it still works, searchbar included. Why is this? As far as I understand me filtering on EquipmentView shouldn't change anything about Equipments, but it seems to do so anyway.
Everything works fine really, I just wish I knew why.
Also XAML-code for searchbar:
<TextBox Name="SearchBar" Margin="10 10 10 10" Text="{Binding FilterString, UpdateSourceTrigger=PropertyChanged}"/>
Datagrid:
<DataGrid MaxHeight="800"
ItemsSource="{Binding Equipments}"
SelectedItem="{Binding SelectedEquipment, Mode=TwoWay}"
IsReadOnly="True"
CanUserReorderColumns="False"
SelectionMode="Single"
ColumnWidth="*">
<DataGrid.ItemContainerStyle>
<Style TargetType="DataGridRow">
<EventSetter Event="MouseDoubleClick"
Handler="Row_DoubleClick" />
</Style>
</DataGrid.ItemContainerStyle>
</DataGrid>
Upvotes: 0
Views: 2786
Reputation: 1729
From the WPF documentation:
All collections have a default CollectionView. WPF always binds to a view rather than a collection. If you bind directly to a collection, WPF actually binds to the default view for that collection. This default view is shared by all bindings to the collection, which causes all direct bindings to the collection to share the sort, filter, group, and current item characteristics of the one default view.
Now in your code, you're doing this:
EquipmentView = CollectionViewSource.GetDefaultView(Equipments);
EquipmentView.Filter = new Predicate<object>(Filter);
Upvotes: 3