通过用户输入筛选集合和列表
如果集合显示许多项或紧密绑定到用户交互,则筛选是一项很有用的可以实施的功能。 使用本文所述方法进行的筛选可以实施到大多数集合控件,其中包括 ListView、GridView 和 ItemsView。 许多类型的用户输入(例如复选框、单选按钮、滑块)可以用来筛选集合,但本文演示如何使用基于文本的用户输入,根据用户的搜索用它来实时更新 ListView。
设置 UI 以便进行筛选
若要实施文本筛选,应用程序将需要 ListView 和 TextBox 或其他允许用户输入的控件。 用户在 TextBox 中键入的文本用作筛选器;也就是说,只有包含用户文本输入的结果才会显示在 ListView 中。 当用户在 TextBox 中键入时,ListView 会不断更新筛选的结果。
注意
本文演示如何使用 ListView 进行筛选。 然而,演示的筛选也可应用到其他集合控件,例如 GridView、ItemsView 或 TreeView。
以下 XAML 显示一个 UI,其中包含一个简单的 ListView 以及随附的 TextBox。 在本示例中,ListView 显示 Contact
对象的集合。 Contact
是代码隐藏中定义的类,每个 Contact
对象具有以下属性:FirstName
、LastName
和 Company
。
用户可以在 TextBox 中键入筛选词,以按姓氏筛选 Contact
对象列表。 TextBox 具有其 x:Name
属性集 (FilterByLastName
),因此可以在代码隐藏中访问 TextBox 的 Text 属性。 还可以处理其 TextChanged 事件 (OnFilterChanged
)。 每当用户在 TextBox 中键入时,就会发生 TextChanged 事件,以便在接收用户输入时执行筛选操作。
若要进行筛选,ListView 必须有一个可以在代码隐藏中进行操作的数据源,例如 ObservableCollection<T>。 在本例中,我们在代码隐藏中将 ListView 的 ItemsSource 属性分配给了 ObservableCollection<Contact>
。
提示
这是 WinUI 库应用 的 ListView 页中示例的简化版本。 使用 WinUI 库应用运行和查看完整代码,包括 ListView 的 DataTemplate 和 Contact
类。
<Grid>
<StackPanel Width="300" Margin="24"
HorizontalAlignment="Left">
<TextBox x:Name="FilterByLastName"
Header="Filter by Last Name"
TextChanged="OnFilterChanged"/>
<ListView x:Name="FilteredListView"
ItemTemplate="{StaticResource ContactListViewTemplate}"/>
</StackPanel>
</Grid>
筛选数据
Linq 查询允许对集合中的某些项进行分组、排序和选择操作。 若要筛选列表,请构造一个 Linq 查询,该查询仅选择与用户在 FilterByLastName
TextBox 中输入的筛选词匹配的项。 查询结果可以分配给 IEnumerable<T> 集合对象。 有了该集合以后,可以使用它与原始列表进行比较,删除不匹配的项,将确实匹配的项添加回来(在使用了退格键的情况下)。
注意
若要让 ListView 能够在添加和删除项时以最直观的方式进行动画显示,必须在 ListView 的 ItemsSource 集合本身中添加和删除项,而不是创建一个包含已筛选对象的新集合并将其分配给 ListView 的 ItemsSource 属性。
若要开始,您将需要在单独的集合(例如 List<T>)中初始化原始数据源。 本示例中有一个调用 allContacts
的 List<Contact>
,其中包含可能显示在 ListView 中的所有 Contact
对象。
还需要一个集合来保存已筛选的数据。每次应用筛选器时,该集合就会更改。 为此,您将使用 ObservableCollection<T>,以便在集合发生更改时通知 ListView 更新。 在本示例中,它是一个调用 contactsFiltered
的 ObservableCollection<Person>
,并且是 ListView 的 ItemsSource。 初始化时,它将具有与 allContacts
相同的内容。
筛选操作通过以下步骤执行,如以下代码所示:
- 将 ListView 的 ItemsSource 属性设置为
contactsFiltered
。 - 为
FilterByLastName
TextBox 处理 TextChanged 事件 (OnFilterChanged
)。 在此事件处理程序函数中,筛选数据。 - 若要筛选数据,请通过
FilterByLastName.Text
属性访问用户输入的筛选词。 使用 Linq 查询在allContacts
中选择其姓包含FilterByLastName.Text
中该词的项,然后将这些匹配项添加到名为filtered
的集合中。 - 将当前的
contactsFiltered
集合与filtered
中新筛选的项进行比较,根据需要在contactsFiltered
中删除和添加项,使其匹配filtered
。 - 在
contactsFiltered
中删除和添加项时,ListView 会进行相应的更新和动画显示。
using System.Linq;
public sealed partial class MainPage : Page
{
// Define Contact collection to hold all Contact objects.
IList<Contact> allContacts = new List<Contact>();
// Define an ObservableCollection<Contact> object to serve as the ListView's
// ItemsSource. This collection will get updated after the filters are used:
ObservableCollection<Contact> contactsFiltered;
public MainPage()
{
this.InitializeComponent();
// Populate allContacts collection.
allContacts.Add(new Contact("Kendall", "Collins", "Adatum Corporation"));
allContacts.Add(new Contact("Victoria", "Burke", "Bellows College"));
allContacts.Add(new Contact("Preston", "Morales", "Margie's Travel"));
allContacts.Add(new Contact("Miguel", "Reyes", "Tailspin Toys"));
// Populate contactsFiltered with all Contact objects (in this case,
// allContacts holds all of our Contact objects so we copy them into
// contactsFiltered). Set this newly populated collection as the
// ItemsSource for the ListView.
contactsFiltered = new ObservableCollection<Contact>(allContacts);
Filtereditemscontrol.itemssource = contactsFiltered;
}
// Whenever text changes in the filtering text box, this function is called:
private void OnFilterChanged(object sender, TextChangedEventArgs args)
{
// This is a Linq query that selects only items that return true after
// being passed through the Filter function, and adds all of those
// selected items to filtered.
var filtered = allContacts.Where(contact => Filter(contact));
Remove_NonMatching(filtered);
AddBack_Contacts(filtered);
}
// The following functions are called inside OnFilterChanged:
// When the text in any filter is changed, perform a check on each item in
// the original contact list to see if the item should be displayed. If the
// item passes the check, the function returns true and the item is added to
// the filtered list. Make sure all text is case-insensitive when comparing.
private bool Filter(Contact contact)
{
return contact.LastName.Contains
(FilterByLastName.Text, StringComparison.InvariantCultureIgnoreCase);
}
// These functions go through the current list being displayed
// (contactsFiltered), and remove any items not in the filtered collection
// (any items that don't belong), or add back any items from the original
// allContacts list that are now supposed to be displayed. (Adding/removing
// the items ensures the list view uses the desired add/remove animations.)
private void Remove_NonMatching(IEnumerable<Contact> filteredData)
{
for (int i = contactsFiltered.Count - 1; i >= 0; i--)
{
var item = contactsFiltered[i];
// If contact is not in the filtered argument list,
// remove it from the ListView's source.
if (!filteredData.Contains(item))
{
contactsFiltered.Remove(item);
}
}
}
private void AddBack_Contacts(IEnumerable<Contact> filteredData)
{
foreach (var item in filteredData)
{
// If the item in the filtered list is not currently in
// the ListView's source collection, add it back in.
if (!contactsFiltered.Contains(item))
{
contactsFiltered.Add(item);
}
}
}
}
现在,当用户在 FilterByLastName
TextBox 中键入其筛选字符串时,ListView 会立即进行更新,只显示其姓包含筛选字符串的人员。
获取示例代码
WinUI 3 库应用包括大多数 WinUI 3 控件、特性和功能的交互式示例。 通过 Microsoft Store 获取应用,或在 GitHub 上获取源代码
对于 UWP:WinUI 2 库应用包括大多数 WinUI 2 控件、特性和功能的交互式示例。 通过 Microsoft Store 获取应用,或在 GitHub 上获取源代码。
相关文章
反馈
https://aka.ms/ContentUserFeedback。
即将发布:在整个 2024 年,我们将逐步淘汰作为内容反馈机制的“GitHub 问题”,并将其取代为新的反馈系统。 有关详细信息,请参阅:提交和查看相关反馈