Sort and Search ItemsSource in WPF
在WPF中我们经常会使用ListBox或者ListView来绑定我们的数据集合,这些列表通常也都会有搜索和排序的功能。下面我们就来介绍一下WPF中应该如何对数据源进行排序和搜索。
首先看一下我们要达到的功能,见图:
界面中是一个人员列表,右上角显示了列表中的人员数量,顶上有一个搜索栏,当用户输入字符后能自动进行关键字搜索。如下图:
当用户输入“王 1”,自动将姓名和电话中出现过(王)和(1)的记录搜索出来,并且右上角显示人员数量。
通过点击列眉可以对列表进行排序控制,如图:
实现过程:
1. 按照通常的做法,我们先创建一个Model类(class Member),其中包含(Name和Phone)两个属性。
public class Member { public string Name { get; set; } public string Phone { get; set; } }
2. 然后再创建一个数据集合(ObservableCollection<Member>)用于保存我们的人员库。
private ObservableCollection<Member> list = new ObservableCollection<Member>(); list.Add(new Member() { Name = "张三", Phone = "13579" }); list.Add(new Member() { Name = "李四", Phone = "24680" }); list.Add(new Member() { Name = "王五", Phone = "43452" }); list.Add(new Member() { Name = "王一", Phone = "79897" }); list.Add(new Member() { Name = "王大力", Phone = "12043" });
3. 将ListBox与数据集合绑定
<ListBox x:Name="ListBoxMember" Background="#f5f5f5" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Auto" BorderThickness="0" SelectionMode="Single" ScrollViewer.CanContentScroll="False" ItemContainerStyle="{StaticResource MemberItemContainerStyle}" />
ListBoxMember.ItemsSource = list;
4. 为Member类型创建数据模板
<DataTemplate DataType="{x:Type local:Member}"> <Border HorizontalAlignment="Stretch" VerticalAlignment="Stretch" BorderBrush="LightGray" BorderThickness="0,0,0,1"> <UniformGrid Columns="2" Margin="5, 10"> <TextBlock Text="{Binding Name}" HorizontalAlignment="Center" /> <TextBlock Text="{Binding Phone}" HorizontalAlignment="Center" /> </UniformGrid> </Border> </DataTemplate>
经过1~4的步骤,我们完成了从数据到界面绑定的过程。
5. 搜索
我们已经有了一个数据源ObservableCollection<Member>,实现关键字搜索并不困难,几个判断就可以了,关键是如何绑定结果?!难道每次搜索都要创建一个结果集合然后重新做绑定吗?
答案当然是否定的。.Net提出了ICollectionView概念,这是一个视图集合,专门用于视图的排序和过滤功能。
var view = CollectionViewSource.GetDefaultView(ListBoxMember.ItemsSource);
以下是模糊关键字搜索功能的具体实现:
string text = KeywordBox.Text.Trim().ToLower(); var view = CollectionViewSource.GetDefaultView(ListBoxMember.ItemsSource); if (string.IsNullOrEmpty(text)) { view.Filter = null; return; } string[] keyList = text.Split(' '); view.Filter = new Predicate<object>((p) => { bool result = true; foreach (string key in keyList) { Member m = p as Member; if (m.Phone.ToLower().Contains(key)) continue; if (m.Name.ToLower().Contains(key)) continue; result = false; } return result; });
6. 排序
同样的通过ICollectionView接口可以实现针对属性的排序控制。
var view = CollectionViewSource.GetDefaultView(ListBoxMember.ItemsSource); view.SortDescriptions.Clear(); if (IsOrderAsc) { view.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending)); } else { view.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Descending)); }
7. Example