Я пытаюсь использовать поле фильтра, которое фильтрует большой список данных, сохраненных в ObservableCollection
, в зависимости от того, содержит ли элемент строку, и отображает результаты в ListView
.
В настоящее время я использую конвертер для достижения этой цели.Он работает, проверяя, содержит ли целевая строка строку фильтра, используя простой метод сравнения без учета регистра.
private static bool Contains(string source, string toCheck, StringComparison comp = StringComparison.OrdinalIgnoreCase)
{
return source?.IndexOf(toCheck, comp) >= 0;
}
Этот подход, кажется, хорошо работает для меньшего числа записей (несколько сотен).Но размер данных, с которыми я работаю, может варьироваться от 50 тыс. До 200 тыс. Записей.
Существует ли способ эффективной фильтрации списка без значительных падений производительности при поиске в коллекциях данных примерно 200000 записей.
MCVE ниже.
XAML
<Window x:Class="FastFilter.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:FastFilter"
mc:Ignorable="d"
Title="Fast Filter" Height="450" Width="800">
<Window.Resources>
<local:FilterConverter x:Key="FilterConverter"/>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBox Text="{Binding Path=FilterString, UpdateSourceTrigger=PropertyChanged}"/>
<ListView Grid.Row="1"
ItemsSource="{Binding Path=Infos}">
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="Visibility">
<Setter.Value>
<MultiBinding Converter="{StaticResource FilterConverter}">
<Binding Path="DataContext.FilterString" RelativeSource="{RelativeSource AncestorType=ListView}"/>
<Binding Path="Text"/>
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<!-- List Box Item Layout -->
<StackPanel Orientation="Horizontal">
<Label Content="Text:"/>
<Label Content="{Binding Text}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Window>
CS
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Data;
namespace FastFilter
{
public partial class MainWindow : INotifyPropertyChanged
{
public MainWindow()
{
InitializeComponent();
DataContext = this;
for (int i = 0; i < 200000; i++)
{
Infos.Add(new ObjectInfo(Guid.NewGuid().ToString()));
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private string filterString = string.Empty;
public string FilterString
{
get => filterString;
set
{
filterString = value;
OnPropertyChanged();
}
}
private ObservableCollection<ObjectInfo> infos = new ObservableCollection<ObjectInfo>();
public ObservableCollection<ObjectInfo> Infos {
get => infos;
set {
infos = value;
OnPropertyChanged();
}
}
}
public class ObjectInfo
{
public ObjectInfo(string text)
{
Text = text;
}
public string Text { get; }
}
public class FilterConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
string filter = (string)values[0];
string checkStringContains = (string)values[1];
return !(string.IsNullOrWhiteSpace(checkStringContains) || string.IsNullOrWhiteSpace(filter))
? Contains(checkStringContains, filter) ? Visibility.Visible : Visibility.Collapsed
: Visibility.Visible;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
private static bool Contains(string source, string toCheck, StringComparison comp = StringComparison.OrdinalIgnoreCase)
{
return source?.IndexOf(toCheck, comp) >= 0;
}
}
}