WPF Используя несколько фильтров на том же ListCollectionView

Я использую шаблон разработки MVVM с ListView, связанным с ListCollectionView на ViewModel. У меня также есть несколько полей комбинированного списка, которые используются для фильтрации ListView. Когда пользователь выбирает объект из поля комбинированного списка, ListView фильтрован для выбранного пункта. Каждый раз, когда я хочу отфильтровать сверху того, что уже фильтровано, это отменяет мой предыдущий фильтр как он, никогда не происходил. То же также верно для удаления фильтра. Удаление фильтра для одного поля комбинированного списка удаляет все фильтры и отображает исходный список. Действительно ли возможно иметь несколько, отдельные фильтры на том же ListCollectionView?

Я делаю что-то не так, или разве это просто не поддерживается? Можно найти, что снимок экрана моего приложения здесь видит то, что я пытаюсь выполнить. Вот мой код для фильтрации...

    /// 
    /// Filter the list
    /// 
    /// Criteria and Item to filter the list
    [MediatorMessageSink("FilterList", ParameterType = typeof(FilterItem))]
    public void FilterList(FilterItem filter)
    {
        // Make sure the list can be filtered...
        if (Products.CanFilter)
        {
            // Now filter the list
            Products.Filter = delegate(object obj)
            {
                Product product = obj as Product;

                // Make sure there is an object
                if (product != null)
                {
                    bool isFiltered = false;
                    switch (filter.FilterItemName)
                    {
                        case "Category":
                            isFiltered = (product.Category.IndexOf(filter.Criteria, StringComparison.CurrentCultureIgnoreCase)) != -1 ? true : false;
                            break;

                        case "ClothingType":
                            isFiltered = (product.ClothingType.IndexOf(filter.Criteria, StringComparison.CurrentCultureIgnoreCase)) != -1 ? true : false;
                            break;

                        case "ProductName":
                            isFiltered = (product.ProductName.IndexOf(filter.Criteria, StringComparison.CurrentCultureIgnoreCase)) != -1 ? true : false;
                            break;

                        default:
                            break;
                    }

                    return isFiltered;
                }
                else
                    return false;
            };
        }
    }

12
задан Brent 20 December 2009 в 05:23
поделиться

2 ответа

Каждый раз при настройке свойства фильтра сбрасывается предыдущий фильтр. Это факт. Теперь, как Вы можете иметь несколько фильтров?

Как вы знаете, есть два способа сделать фильтрацию: CollectionView and CollectionViewSource. В первом случае с CollectionView мы фильтруем с делегированием, и для того, чтобы сделать несколько фильтров, я бы создал класс для объединения пользовательских фильтров, а затем вызывал бы их по одному для каждого элемента фильтра. Как и в следующем коде:

  public class GroupFilter
  {
    private List<Predicate<object>> _filters;

    public Predicate<object> Filter {get; private set;}

    public GroupFilter()
    {
      _filters = new List<Predicate<object>>();
      Filter = InternalFilter;
    }

    private bool InternalFilter(object o)
    {
      foreach(var filter in _filters)
      {
        if (!filter(o))
        {
          return false;
        }
      }

      return true;
    }

    public void AddFilter(Predicate<object> filter)
    {
      _filters.Add(filter);
    }

    public void RemoveFilter(Predicate<object> filter)
    {
      if (_filters.Contains(filter))
      {
        _filters.Remove(filter);
      }
    }    
  }

  // Somewhere later:
  GroupFilter gf = new GroupFilter();
  gf.AddFilter(filter1);
  listCollectionView.Filter = gf.Filter;

Для обновления отфильтрованного вида можно сделать вызов метода ListCollectionView.Refresh().

А во втором случае с CollectionViewSource для фильтрации коллекции используется событие Filter. Вы можете создать несколько обработчиков событий для фильтрации по разным критериям. Чтобы узнать больше об этом подходе, ознакомьтесь с этой замечательной статьей Беа Штольниц (Bea Stollnitz): Как применить несколько фильтров?

Надеюсь, это поможет.

Твое здоровье, Анвака.

26
ответ дан 2 December 2019 в 04:25
поделиться

Каждый раз, когда пользователь фильтрует, ваш код заменяет делегата фильтра в просмотре вашей коллекции на новый, свежий. Более того, новый фильтр проверяет только те критерии, которые пользователь только что выбрал с помощью ComboBox.

Вам нужен один обработчик фильтра, который проверяет все критерии. Что-то вроде:

public MyViewModel()
{
    products = new ObservableCollection<Product>();
    productsView = new ListCollectionView(products);
    productsView.Filter += FilterProduct;
}

public Item SelectedItem
{
    //get,set omitted. set needs to invalidate filter with refresh call
}

public Type SelectedType
{
    //get,set omitted. set needs to invalidate filter with refresh call
}

public Category SelectedCategory
{
    //get,set omitted. set needs to invalidate filter with refresh call
}

public ICollection<Product> FilteredProducts
{
    get { return productsView; }
}

private bool FilterProduct(object o)
{
    var product = o as Product;

    if (product == null)
    {
        return false;
    }

    if (SelectedItem != null)
    {
        // filter according to selected item
    }

    if (SelectedType != null)
    {
        // filter according to selected type
    }

    if (SelectedCategory != null)
    {
        // filter according to selected category
    }

    return true;
}

Ваш вид теперь может просто привязываться к соответствующим свойствам и фильтрация будет просто работать.

.
8
ответ дан 2 December 2019 в 04:25
поделиться
Другие вопросы по тегам:

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