@kodwi
https://moikrug.ru/kodwi

Как реализовать мгновенную фильтрацию DataGrid'a, используя многопоточность (WPF)?

Имеется DataGrid, к нему привязана ObservableCollection. Функция фильтрации DataGrid'a висит на событии TextChanged у TextBox'a, в котором вводим строку для фильтрации. Фильтрую путем формирования новой коллекции из элементов, имена которых совпадают с фильтром. Все бы ничего, но при вводе строки, которой удовлетворяют много элементов, ввод в TextBox начинает подтормаживать. Каким образом можно распараллелить и реализовать действительно мгновенную фильтрацию без зависания UI? Чтобы при каждом изменении текста, если предыдущий фильтр не отработал еще, то отменяем его, очищаем коллекцию и заново фильтруем, и ничего бы не зависало.

Пробовал BackgroundWorker, но т.к., видимо, в функции фильтрации преобразовывается коллекция, изменения которой меняют и содержимое DataGrid'a, то ничего не работает, после очистки коллекции метод DoWork просто молча завершается:

... DoWork(...)
{
collection.Clear(); // очищает коллекцию, но DataGrid не очищается
.... // до этой строчки выполнение вообще не доходит
}
  • Вопрос задан
  • 11843 просмотра
Решения вопроса 1
@Sumor
Вам не нужно для фильтрации пересобирать коллекцию. Для этого в wpf уже разработаны нужные механизмы.
В первую очередь нужно коллекцию с которой вы работаете поместить в CollectionView. CollectionView привязать к DataGrid.
У CollectionView есть встроенные механизмы фильтрации — результат будет отображаться в DataGrid.
См. Свойство Filter CollectionView.

Для использования CollectionView обёртывается ещё в CollectionViewSource или что-то подобное. Это подробно описывается в примерах. Его можно просто описать даже в Xaml.
Пример, примерного кода с динамическим созданием CollectionViewSource над List и фильтрацией через TextBox:
Xaml
<Window x:Class="WpfApplication3.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">    
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="47*"/>
            <RowDefinition Height="275*"/>
        </Grid.RowDefinitions>
        <TextBox x:Name="filter" TextChanged="filter_TextChanged"/>
        <ListBox x:Name="lst" Grid.Row="1" />
    </Grid>
</Window>


C#
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        List<string> lstSource = new List<string>() { "1", "2","3" };
        viewSource = new CollectionViewSource();
        viewSource.Source = lstSource;            
        viewSource.Filter += viewSource_Filter;
        lst.ItemsSource = viewSource.View;
    }

    CollectionViewSource viewSource;
    void viewSource_Filter(object sender, FilterEventArgs e)
    {
        e.Accepted = ((string)e.Item).IndexOf(filter.Text) >=0;
    }

    private void filter_TextChanged(object sender, TextChangedEventArgs e)
    {
        viewSource.View.Refresh();
    }
}
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
Deerenaros
@Deerenaros
Программист, математик, задрот и даже чуть инженер
Видимо, вы неправильно готовите асинхронные таски. Возможно это поможет.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы