Filtering a listbox, datagrid, or any list control within WPF for a given entity from an entity framework collection should be easy; and it is once you've figured out how it should work.
The great thing about WPF and bindings and the Entity Framework is that it actually does so very much for you. So much that when something isn't just there it seems odd, and applying a new rule of thumb that after 6 months or so of working with WPF I've finally realised
If you're trying to do something with WPF that seems hard or requires lots of code then almost certainly you're doing it the wrong way.
So how do we filter. For some collections there is a filter method that's nice and accessible; but not immediately available. So the steps are:
1. Create a new CollectionViewSource that links your entity framework entity to the target control. In the Resources section of your xaml:
<CollectionViewSource Source="{Binding ElementName=supplierList, Path=SelectedValue.Products}" x:Key="cvs" Filter="Product_Filter" x:Name="productsView" CollectionViewType="{x:Type dat:ListCollectionView}" />
The important part of the above is the CollectionViewType - without this it won't work. As this refers to dat: this needs to be defined at the top:
xmlns:dat="clr-namespace:System.Windows.Data;assembly=PresentationFramework"
2. Bind your chosen control to the new CollectionViewSource
<w8:DataGrid ItemsSource="{Binding Source={StaticResource cvs}}">
3. Create a textbox to use as the filter text - with an OnChanged event to applying the filtering as each character is type.
<TextBox Name="productFilter" TextChanged="productFilter_TextChanged" />
4. In your code module you need to provide two things, firstly the filtering for the CollectionViewSource
void Product_Filter(object sender, FilterEventArgs e) { if (e.Item is Product) e.Accepted = (e.Item as Product).Name.ToUpper().Contains(productFilter.Text.ToUpper()); else e.Accepted = true; }
5. The textbox OnChanged needs to ask the CollectionViewSource to refresh itself;
private void RefreshList() { if (ProductList.Items is CollectionView) { CollectionViewSource csv = (CollectionViewSource)FindResource("cvs"); if (csv != null) csv.View.Refresh(); } } private void productFilter_TextChanged(object sender, TextChangedEventArgs e) { RefreshList(); }
Conclusion
That's all of the complexity that there is - although this took me nearly a day to figure out - and many wrong tracks. The beauty of WPF and the Entity Framework - there is so much power and flexibility that it is possible to do something many ways. You know you've got the right way when it's about 10 lines of code.