在本系列的第一部分中,讨论了如何通过UI中的虚拟列表技术与后端数据存储访问层的分页技术相结合,来显示大量数据列表。在第二部分,讨论了如何从虚拟列表中移除/添加条目,以及如何在不牺牲性能的情况下选择/取消选择所有条目。
在第三部分,将讨论如何在虚拟列表中执行多重搜索,并将选中的条目多次快速移动到已选列表中。示例代码是用WPF和C#编写的,并采用了模型-视图-视图模型(MVVM)模式。
正如在之前的文章中提到的,示例应用程序包含两个列表:一个是可用列表,另一个是已选列表。用户可以在员工旁边勾选复选框,然后点击箭头按钮将员工从可用列表移动到已选列表。
在本文中,将讨论如何对虚拟列表执行多重搜索,并将选中的条目移动到已选列表。例如,可以使用关键词'10'搜索列表,然后将所有匹配的条目移动到已选列表,然后可以执行另一个搜索,关键词为'5',然后将匹配的条目移动到已选列表,依此类推。
挑战在于,执行不同搜索条件后,条目数量会发生变化。随着条目数量的变化,无法确定已选条目在可用列表中的索引,然后将其从可用列表中移除。
例如,将条目200移动到已选列表,如果未执行过滤,则知道它在可用列表的第200个位置。现在执行另一个搜索,关键词为'2',希望条目200应该从可用列表中移除。然而,无法做到这一点,因为无法加载虚拟列表以移除200,因为不知道200在哪个页面上。
解决方案不是从可用列表中移除条目,而是在可用列表中禁用已移除的条目,并将其标记为已移除,以便用户无法再选择它。一旦用户执行不同的搜索,显示在可用虚拟列表中的条目将被检查,看它们是否在已移除列表中,如果是,则将被禁用。然而,未显示的条目(未加载到虚拟列表中的条目)不会被检查。如果用户滚动列表,那么新加载的显示条目将被检查是否在已移除列表中,如果是,则它们将被标记为已移除。依此类推。
在UI中,将HasRemoved绑定到可用列表中的复选框。如果条目已被标记为已移除,则该条目的复选框将被禁用。
<CheckBox Tag="{Binding}"
IsChecked="{Binding IsSelected}"
IsEnabled="{Binding HasRemoved, Mode=TwoWay, Converter={StaticResource itemRemovedConverter}}" />
在视图模型中,当用户点击箭头按钮将选中的条目从可用列表移动到已选列表时,将调用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'执行搜索,视图模型中的Search方法将被调用。它创建一个新的可用虚拟列表,使用新的搜索文本。然后将SelectedList分配给可用虚拟列表作为RemovedItemList。最后,它遍历可用虚拟列表,检查条目是否已加载并缓存,如果是,并且条目也存在于SelectedList中,那么该条目将被标记为'Removed',以便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;
}