WPF如何在同一个ListCollectionView上使用多个过滤器

13

我正在使用MVVM设计模式,并将ListView绑定到ViewModel中的ListCollectionView。我还有几个ComboBox用于过滤ListView。当用户从ComboBox中选择项目时,ListView会根据所选项目进行过滤。每当我想要在已经过滤的基础上进行过滤时,它会撤消我的先前过滤,就好像从未发生过一样。删除过滤器也是如此。删除一个ComboBox的过滤器会删除所有过滤器并显示原始列表。是否可能在同一个ListCollectionView上有多个独立的过滤器?

我是否做错了什么,还是这种情况根本不被支持?您可以在此处找到我应该完成的任务的屏幕截图。以下是我的筛选代码...

    /// <summary>
    /// Filter the list
    /// </summary>
    /// <param name="filter">Criteria and Item to filter the list</param>
    [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;
            };
        }
    }
2个回答

29

每次设置筛选属性都会重置以前的筛选,这是事实。现在如何使用多个筛选器?

正如您所知,有两种方法可以进行过滤:CollectionViewCollectionViewSource。在第一种情况下,我们使用委托来过滤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 的这篇精彩文章:如何应用多个过滤器? (archive)

希望这可以帮助到您。

祝好,Anvaka。


8
每次用户筛选时,您的代码都会用一个新的、新鲜的 ComboBox 检查用户刚刚选择的特定条件,从而替换集合视图中的 Filter 委托。此外,新的委托只检查特定的条件。
您需要的是一个单一的筛选处理程序,用于检查所有条件。例如:
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;
}

现在,您的视图只需绑定到相应的属性,过滤将自动工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接