Alright. You already accepted an answer to this question, But I wanted to show a different approach anyways:

XAML:
<Window x:Class="WpfApplication1.ListViewSearch"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ListViewSearch" Height="300" Width="300">
<DockPanel>
<DockPanel DockPanel.Dock="Left" Margin="2">
<Button DockPanel.Dock="Bottom" Content="Find All" Margin="2" Click="FindAll_Click"/>
<ListBox ItemsSource="{Binding Filters}"
SelectedItem="{Binding SelectedFilter}"
DisplayMemberPath="DisplayName"/>
</DockPanel>
<ListView ItemsSource="{Binding Items}">
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding FirstName}" Header="First Name"/>
<GridViewColumn DisplayMemberBinding="{Binding LastName}" Header="Last Name"/>
</GridView>
</ListView.View>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="IsSelected" Value="{Binding IsSelected}"/>
</Style>
</ListView.ItemContainerStyle>
</ListView>
</DockPanel>
</Window>
Code Behind:
public partial class ListViewSearch : Window
{
private ViewModel ViewModel;
public ListViewSearch()
{
InitializeComponent();
DataContext = ViewModel = new ViewModel();
}
private void FindAll_Click(object sender, RoutedEventArgs e)
{
ViewModel.Filter();
}
}
ViewModel:
public class ViewModel
{
public ViewModel()
{
Items = new ObservableCollection<DataItem>(RandomDataSource.GetRandomData());
Filters = new ObservableCollection<DataFilter>();
Filters.Add(new DataFilter()
{
DisplayName = "First Name starting with A",
FilterExpression = x => x.FirstName.ToLower().StartsWith("a")
});
Filters.Add(new DataFilter()
{
DisplayName = "Last Name starting with E",
FilterExpression = x => x.LastName.ToLower().StartsWith("e")
});
}
public ObservableCollection<DataItem> Items { get; private set; }
public DataFilter SelectedFilter { get; set; }
public ObservableCollection<DataFilter> Filters { get; private set; }
public void Filter()
{
if (SelectedFilter == null)
return;
foreach (var item in Items)
item.IsSelected = SelectedFilter.FilterExpression(item);
}
}
Data Item:
public class DataItem : INotifyPropertyChanged
{
private bool _isSelected;
public bool IsSelected
{
get { return _isSelected; }
set
{
_isSelected = value;
OnPropertyChanged("IsSelected");
}
}
public string LastName { get; set; }
public string FirstName { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
Data Filter:
public class DataFilter
{
public Func<DataItem, bool> FilterExpression { get; set; }
public string DisplayName { get; set; }
}
Random Data Source (just a bunch of boilerplate)
public static class RandomDataSource
{
private static string TestData = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum";
private static List<string> words;
private static int maxword;
private static Random random;
public static List<DataItem> GetRandomData()
{
random = new Random();
words = TestData.Split(' ').ToList();
maxword = words.Count - 1;
return Enumerable.Range(0, 10000)
.Select(x => GetRandomItem())
.ToList();
}
private static DataItem GetRandomItem()
{
return new DataItem()
{
LastName = words[random.Next(0, maxword)],
FirstName = words[random.Next(0, maxword)],
};
}
}
This approach has the following advantages over a traditional code-behind approach:
- It decouples the UI and the logic. You operate against your own defined classes instead of dealing with the (sometimes arcane and obscure) WPF object model.
- Since your code does not actually depend on any specific UI element type, you may change the UI to a "3D rotating pink elephant" and it would still work. It enables much more customizability of the view without compromising any code or logic.
- It is easily reusable (you can go as far as to create a
SearchViewModel<T>
and a DataFilter<T>
and reuse these on many different entity types.
- It is unit-testable.