通过用户输入筛选集合和列表

如果集合显示许多项或与用户交互密切相关,则筛选是实现的有用功能。 使用本文中所述的方法进行筛选可以通过大多数集合控件(包括 ListViewGridViewItemsView)来实现。 许多类型的用户输入可用于筛选集合(如复选框、单选按钮和滑块),但本文演示了根据用户的搜索,采用基于文本的用户输入并使用它实时更新 ListView。

设置用于筛选的 UI

若要实现文本筛选,应用需要 ListViewTextBox 或其他允许用户输入的控件。 用户键入到 TextBox 中的文本用作筛选器;也就是说,只有包含用户文本输入的结果才会显示在 ListView 中。 当用户在 TextBox 中键入时,ListView 会不断更新筛选的结果。

注释

本文演示如何使用 ListView 进行筛选。 但是,演示的筛选也可以应用于其他集合控件,例如 GridView、ItemsView 或 TreeView。

以下 XAML 显示了一个 UI,其中包含一个简单的 ListView 以及随附的 TextBox。 在此示例中,ListView 显示对象的集合 ContactContact 是代码隐藏中定义的类,每个 Contact 对象具有以下属性: FirstNameLastNameCompany

用户可以在 TextBox 中键入筛选词,以按姓氏筛选对象列表 Contact 。 TextBox 具有其 x:Name 属性集(FilterByLastName),因此可以在代码隐藏中访问 TextBox 的 Text 属性。 还可以处理 TextChanged 事件(OnFilterChanged)。 每当用户在 TextBox 中输入时,便会触发 TextChanged 事件,以便你在接收用户输入时执行筛选操作。

为了使筛选功能正常工作,ListView 必须具有可以在后台代码中操作的数据源,例如 ObservableCollection<T>。 在这种情况下,ListView 的 ItemsSource 属性将分配给代码隐藏中的属性 ObservableCollection<Contact>

小窍门

这是 WinUI Gallery 应用 的 ListView 页面中的一个简化版本示例。 使用 WinUI Gallery 应用程序运行和查看所有代码,包括 ListView 的 DataTemplateContact 类。

<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 查询,该查询仅选择与用户输入的筛选词匹配的项目,并在 TextBox 中 FilterByLastName 输入。 可以将查询结果分配给 IEnumerable<T> 集合对象。 一旦拥有了此集合,您可以用它与原始列表进行比较,删除那些不匹配的项,并在出现输入错误时重新添加那些匹配的项。

注释

为了使 ListView 在添加和删除项时以最直观的方式进行动画处理,请务必在 ListView 的 ItemsSource 集合本身中添加和删除项,而不是创建筛选对象的新集合,并将其分配给 ListView 的 ItemsSource 属性。

首先,需要在单独的集合(例如 List<T>)中初始化原始数据源。 在此示例中,你有一个 List<Contact>,称为 allContacts,它包含了所有可能显示在 ListView 中的 Contact 对象。

还需要一个集合来保存筛选的数据,每次应用筛选器时都会不断更改。 为此,你将使用 ObservableCollection<T> ,以便在集合发生更改时通知 ListView 更新。 在此示例中,它是名为 ObservableCollection<Person>contactsFiltered,是 ListView 的 ItemsSource。 在初始化时,它将具有与allContacts相同的内容。

筛选作通过以下步骤执行,如以下代码所示:

  • 将 ListView 的 ItemsSource 属性设置为 contactsFiltered.
  • 处理 TextBox 的 OnFilterChanged 事件(FilterByLastName)。 在此事件处理程序函数中,筛选数据。
  • 若要筛选数据,请通过 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);
           }
       }
   }
}

现在,当用户在 TextBox 中的筛选字符串中 FilterByLastName 键入时,ListView 会立即更新,仅显示姓氏包含筛选字符串的人员。

获取示例代码

WinUI 3 示例集应用程序包括大多数 WinUI 3 控件、特性和功能的交互式示例。 通过 Microsoft Store 获取应用,或在 GitHub 上获取源代码

对于 UWP:WinUI 2 画廊 应用程序包含大多数 WinUI 2 控件、特性和功能的交互式示例。 从 Microsoft 应用商店 获取应用,或在 GitHub 上获取源代码。