I'm seeing some really weird behavior where WPF isn't doing what I expect it to do. I've managed to boil the problem down the following bit of code:
XAML:
<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<TabControl x:Name="tabControl">
<TabControl.ContentTemplate>
<DataTemplate DataType="{x:Type List}">
<UserControl>
<UserControl.Resources>
<CollectionViewSource x:Key="filteredValues" Source="{Binding}" Filter="CollectionViewSource_Filter" />
</UserControl.Resources>
<ListBox ItemsSource="{Binding Source={StaticResource filteredValues}}" />
</UserControl>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</Window>
Code-behind:
using System.Collections.Generic;
using System.Windows;
using System.Windows.Data;
namespace WpfApplication3
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.tabControl.ItemsSource = new List<List<string>>()
{
new List<string>() { "a", "b", "c"},
};
}
private void CollectionViewSource_Filter(object sender, FilterEventArgs e)
{
string item = (string)e.Item;
e.Accepted = item.StartsWith("b");
}
}
}
I'd expect that this code would result in a TabControl
with a single tab that has a ListBox
with a single item that says "b." But, instead, I get a ListBox
with all 3 of the strings. Setting a breakpoint inside CollectionViewSource_Filter
shows that the filter never even runs.
What's going on here? Why isn't the filter working?
I was thinking maybe it has something to do with the CollectionViewSource
being a resource in a DataTemplate
. The events on the ListBox
fire properly. If the UserControl
is not part of a DataTemplate
, the Filter event works fine.
EDIT:
For example, the following works as expected, with the List being filtered as expected.
XAML:
<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<UserControl>
<UserControl.Resources>
<CollectionViewSource x:Key="filteredValues" Source="{Binding}" Filter="CollectionViewSource_Filter" />
</UserControl.Resources>
<ListBox ItemsSource="{Binding Source={StaticResource filteredValues}}" />
</UserControl>
</Window>
Code behind:
using System.Collections.Generic;
using System.Windows;
using System.Windows.Data;
namespace WpfApplication3
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new List<string>() { "a", "b", "c" };
}
private void CollectionViewSource_Filter(object sender, FilterEventArgs e)
{
string item = (string)e.Item;
e.Accepted = item.StartsWith("b");
}
}
}
Well, I don't know why it doesn't work, but at this point, I'm assuming it's a Microsoft bug. I'll probably be filing a Connect report shortly.
To work around the bug, I did the following. I created a subclass of CollectionViewSource
like this:
using System.Windows.Data;
namespace WpfApplication3
{
internal class CustomFilteredCollectionViewSource : CollectionViewSource
{
public CustomFilteredCollectionViewSource()
: base()
{
this.Filter += CustomFilter;
}
private void CustomFilter(object sender, FilterEventArgs args)
{
string item = (string)args.Item;
args.Accepted = item.StartsWith("b");
}
}
}
I then replaced
<CollectionViewSource x:Key="filteredValues" Source="{Binding}" Filter="CollectionViewSource_Filter" />
with
<local:CustomFilteredCollectionViewSource x:Key="filteredValues" Source="{Binding}" />
and it now works perfectly.