【问题标题】:WPF Using multiple filters on the same ListCollectionViewWPF 在同一个 ListCollectionView 上使用多个过滤器
【发布时间】:2009-12-20 05:23:42
【问题描述】:

我正在使用 MVVM 设计模式,ListView 绑定到 ViewModel 上的 ListCollectionView。我还有几个用于过滤 ListView 的组合框。当用户从组合框中选择一个项目时,ListView 将针对所选项目进行筛选。每当我想在已过滤的内容之上进行过滤时,它都会撤消我以前的过滤器,就像它从未发生过一样。移除过滤器也是如此。删除一个组合框的过滤器会删除所有过滤器并显示原始列表。是否可以在同一个 ListCollectionView 上有多个单独的过滤器?

我做错了什么,还是根本不支持?你可以找到我的应用程序here 的屏幕截图,看看我想要完成什么。这是我的过滤代码...

    /// <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;
            };
        }
    }

【问题讨论】:

    标签: wpf filter listcollectionview


    【解决方案1】:

    每次设置过滤器属性时,都会重置前一个过滤器。这是事实。现在你怎么能有多个过滤器?

    如您所知,有两种过滤方式: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 的这篇精彩文章:How do I apply more than one filter? (archive)

    希望这会有所帮助。

    干杯,安瓦卡。

    【讨论】:

      【解决方案2】:

      每次用户过滤时,您的代码都会替换集合视图中的Filter 委托,并用一个新的、新鲜的委托。此外,新的仅检查用户刚刚使用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;
      }
      

      您的视图现在可以绑定到适当的属性,并且过滤将正常工作。

      【讨论】:

        猜你喜欢
        • 2013-05-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-09-07
        • 1970-01-01
        • 1970-01-01
        • 2015-08-05
        • 1970-01-01
        相关资源
        最近更新 更多