Фильтруйте коллекцию несколько раз, используя ICollectionView - PullRequest
2 голосов
/ 23 сентября 2011

Я пытаюсь отфильтровать ObservableCollection, которая отображается в DataGrid. Это отлично работает в первый раз, но когда я пытаюсь фильтровать снова, он использует исходную коллекцию вместо отфильтрованного результата. Пример короткого кода:

ICollectionView view = CollectionViewSource.GetDefaultView(myCollection);
view.Filter = delegate(object item){
  User user = item as User;
  if(user != null && user.Name.ToLower().Contains(textbox.Text.ToLower())) return true;
  return false;
};

Итак, я хочу фильтровать только элементы, которые отображаются в моей DataGrid, а НЕ всю коллекцию (конечно, при первом использовании фильтра он будет использовать всю коллекцию).

Ответы [ 4 ]

5 голосов
/ 20 октября 2012

Другой вариант будет что-то вроде ...

public void cmbYourComboBox_SelectionChanged(object sender, RoutedEventArgs e)
{
    ICollectionView filteredView = CollectionViewSource.GetDefaultView(collection);

    filteredView.Filter = new Predicate<object>(GetFilteredView);

    dgYourDataGrid.ItemsSource = filteredView;
}

public bool GetFilteredView(object sourceObject)
{
    if (HasConditionOne(sourceObject) && HasConditionTwo(sourceObject)
    {
        return true;
    }
    return false;
}

public bool HasConditionOne(object sourceObject)
{
    //perform your test and evaluate the outcome
}

public bool HasConditionTwo(object sourceObject)
{
    //perform your test and evaluate the outcome
}

Если исходный объект удовлетворяет всем необходимым условиям, он будет считаться подходящим для отображения в отфильтрованном виде.

0 голосов
/ 23 сентября 2011

Вы можете создать вспомогательный метод, который проверяет, что вы уже установили фильтр для коллекций и, если он уже установлен, сохраните отфильтрованный список в представлении, снова отфильтруйте его и установите представление в качестве источника данных вашей DataGrid.

ICollectionView view = CollectionViewSource.GetDefaultView(myCollection);

И я думаю, что эта часть кода всегда дает вам всю коллекцию, а не уже отфильтрованную.

0 голосов
/ 23 сентября 2011

Проблема real , которую вы должны исправить, заключается в производительности фильтра CollectionView, а не в реализации вложенных фильтров путем передачи вновь отфильтрованного списка в качестве исходной коллекции в следующий фильтр.

Метод сбора вложенных фильтров / источников обратной связи, который вы «хотите», вызовет проблемы, когда пользователь выполнит несколько попыток ввода и удаления символов, поскольку тогда вы не будете уверены, какая коллекция источников применяется к этому тексту фильтра.

Например, у нас 100 сотрудников, и мы фильтруем их, набирая «Имя сотрудника» как «A» ... В этом списке 50 сотрудников с именами, начинающимися с «A».Теперь мы продолжаем набирать «H» ... 10 сотрудников из тех, чьи имена начинаются с «AH», фильтруются.Но теперь мы удаляем"H", в идеале для поиска нового списка сотрудников следует использовать 100 сотрудников, но при этом будет задействовано 10 сотрудников, поскольку они возвращаются во вложенный процесс фильтрации.

Представьте, насколько это будет сложно, если кто-то часто печатает и удаляет случайные символы из отфильтрованного текста!

Таким образом, основное правило - Вы должны фильтровать всю коллекцию источников

Как только мы узнаем это сейчас, мы можем попытаться улучшить функциональность фильтра ...

  1. Используйте LINQ и присвойте результат для ItemsSource DataGrid для каждого напечатанного символа.Они отлично работают для больших коллекций (у меня была одна такая сетка данных с 300 тысячами строк, и я использовал LINQ для быстрой фильтрации).

  2. LINQ может работать в фоновом потоке и повторно применять результат кItemsSource таблицы данных.

  3. Если в .Net 4.0, LINQ предлагает вызовы AsParallel ().Очень эффективный.Для фильтрации используется ограниченное количество потоков в пуле.

  4. LINQ также предлагает интерфейс AsQueryable () для поиска по имени свойства строки.

0 голосов
/ 23 сентября 2011

Что-то еще (вероятно, DataGrid) может сбрасывать фильтр в вашем представлении, так как вы используете представление по умолчанию, которое является общим. Вместо этого используйте свой собственный вид коллекции:

ICollectionView view = new ListCollectionView(myList);
...