搜索可选择的虚拟列表
本文是数据展示性能优化系列文章的第三部分。它讨论了对虚拟列表执行多次搜索。
摘要
本文是数据展示性能优化系列文章的第三部分。在第一部分中,我们介绍了如何通过结合UI中的虚拟列表技术和后端数据存储访问层中的分页技术来显示大量数据。在第二部分中,我们讨论了如何高效地从虚拟列表中删除/添加项以及如何选择/取消选择列表中的所有项。
在第三部分中,我们将讨论如何对虚拟列表执行多次搜索,并将选定的项快速地移动到已选列表。
代码示例使用WPF和C#编写,并采用了模型-视图-视图模型(MVVM)模式。
关键词
虚拟列表,可选择虚拟列表,搜索,可用列表,已选列表
Content
如前一篇文章所述,示例应用程序有两个列表,一个是可用列表,另一个是已选列表。用户可以选中员工旁边的复选框,然后单击箭头按钮将员工从可用列表移动到已选列表。
在本文中,可用列表是指窗口左侧的列表视图,显示仍可选择/取消选择的员工列表。已选列表是指窗口右侧的列表视图,显示已被选中并从可用列表中移除的员工列表。
在第一篇文章中,我们讨论了如何通过结合UI中的虚拟列表技术和数据存储中的分页数据技术来显示可用列表中的大量项。在第二篇文章中,我们讨论了如何使项可选择,以及如何选择并将其从可用列表中删除/添加,我们还讨论了如何在没有性能问题的情况下选择/取消选择虚拟列表中的所有项。
在本篇文章中,我们将讨论如何对虚拟列表执行多次搜索,并将选定的项移动到已选列表。例如,我们可以使用关键字“10”搜索列表,然后将所有匹配的项移到已选列表,然后我们可以使用关键字“5”执行另一次搜索,然后将匹配的项移到已选列表,等等。
图 1:可搜索选择的虚拟列表
挑战在于,在执行另一个具有不同搜索条件的搜索后,项目数量会发生变化。由于项目数量不同,我们无法确定可用列表中选定项目的索引,然后从可用列表中删除它。
例如,我们已将项目 200 移动到已选列表,并且我们知道如果未执行过滤,它在可用列表中的位置是第 200 位。现在,我们通过关键字“2”执行另一个搜索,并期望项目 200 应从可用列表中删除。但是,我们无法做到这一点,因为我们无法加载 `VirtualList` 来删除 200,因为我们不知道项目 200 在哪个页面上。
解决方案不是从可用列表中删除项,而是禁用从可用列表中删除的项,并将其标记为“已删除”,这样用户就无法再选择它们了。一旦用户执行了不同的搜索,可用虚拟列表中显示的项将被检查是否在已删除列表中,如果是,则将被禁用。然而,未显示的项(尚未加载到虚拟列表中的项)将不会被检查。如果用户向下滚动列表,那么新加载的显示项将与已删除列表进行比较,如果它们在已删除列表中,那么它们将被禁用。依此类推。
在UI中,我们将 `HasRemoved` 绑定到可用列表中的复选框。如果一项已被标记为“已删除”,则该项的复选框将被禁用。
<CheckBox Tag="{Binding}"
IsChecked="{Binding IsSelected}"
IsEnabled="{Binding HasRemoved, Mode=TwoWay, Converter={StaticResource itemRemovedConverter}}"
/>
在ViewModel中,当用户单击箭头按钮将选定的项从可用列表移到已选列表时,将调用 Add() 方法,该方法从虚拟列表中获取选定的项并将其添加到 `SelectedEmployeeCollection`。然后将这些选定的项标记为 `HasRemoved`。
public void Add()
{
IList<Employee> employees = AvailableEmployeeCollection.SelectedList;
foreach (var employee in employees)
{
if (!SelectedEmployeeCollection.Contains(employee)) {
SelectedEmployeeCollection.Add(employee);
employee.IsSelected = false;
employee.HasRemoved = true;
}
}
}
一旦用户单击“Go”以执行搜索,ViewModel中的 Search 方法将被调用。它会创建一个新的可用虚拟列表,其中包含新的搜索文本。然后将 `SelectedList` 作为 `RemovedItemList` 分配给可用虚拟列表。最后,它会遍历可用虚拟列表,并检查项是否已加载并缓存,如果已加载并缓存,并且该项也存在于 `SelectedList` 中,那么该项将被标记为“已删除”,以便UI可以禁用该项的复选框。但是,如果项 **尚未** 加载,此方法将不对其做任何操作。因此,搜索速度非常快,应在 1 秒以内。
public void Search()
{
AvailableEmployeeCollection = new SearchableSelectableVirtualList<Employee>(new EmployeeObjectGenerator(_searchText));
AvailableEmployeeCollection.RemovedItemList = new List<employee>(SelectedEmployeeCollection);
for (int index = 0; index < AvailableEmployeeCollection.Count; index++)
if (AvailableEmployeeCollection.IsItemCached(index) && IsRemoved(AvailableEmployeeCollection[index]))
AvailableEmployeeCollection[index].HasRemoved = true;
}
如果用户向下滚动可用虚拟列表,并且应用程序将要获取将要显示的项,那么应用程序将比较这些项与 `RemovedItemList`。如果它们在 `RemovedItemList` 中,那么这些项将被标记为“已删除”,以便UI禁用这些项的复选框。
protected override T Get(int index)
{
var item = base.Get(index);
if (RemovedItemList.Contains(item))
item.HasRemoved = true;
return item;
}
结论
好了,就是这样。现在您可以以非常快的速度搜索具有大量数据项的可用虚拟列表。您还可以将选定的项移到已选列表,这些选定的项将在可用列表中被禁用。您可以执行多次搜索并将项多次移到已选列表。这结束了数据展示性能优化系列的最后一篇文章。希望您喜欢。