2009-12-20 6 views
12

Sto utilizzando il modello di progettazione MVVM, con un controllo ListView associato a un ListCollectionView sul ViewModel. Ho anche diversi combobox che vengono utilizzati per filtrare il ListView. Quando l'utente seleziona un elemento dalla casella combinata, ListView viene filtrato per l'elemento selezionato. Ogni volta che voglio filtrare su ciò che è già filtrato, annulla il mio filtro precedente come se non fosse mai successo. Lo stesso vale anche per la rimozione di un filtro. La rimozione di un filtro per una casella combinata rimuove tutti i filtri e visualizza l'elenco originale. È possibile avere più filtri separati sullo stesso ListCollectionView?WPF Utilizzo di più filtri sullo stesso ListCollectionView

Sto facendo qualcosa di sbagliato o semplicemente non è supportato? Puoi trovare una schermata della mia applicazione here per vedere cosa sto cercando di realizzare. Ecco il mio codice per il filtraggio ...

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

risposta

25

Ogni volta che si imposta la proprietà Filtro, si ripristina il filtro precedente. Questo è un fatto. Ora come puoi avere più filtri?

Come sai, ci sono due modi per fare il filtraggio: CollectionView e CollectionViewSource. Nel primo caso con CollectionView filtriamo con delegato e per fare più filtri vorrei creare una classe per aggregare filtri personalizzati e quindi chiamarli uno per uno per ciascun elemento del filtro. Come nel codice seguente:

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; 

Per aggiornare visualizzazione filtrata è possibile effettuare una chiamata al metodo ListCollectionView.Refresh().

E nel secondo caso con CollectionViewSource si utilizza l'evento Filter per filtrare la raccolta. È possibile creare più gestori di eventi da filtrare in base a criteri diversi. Per saperne di più su questo approccio controlla questo meraviglioso articolo di Bea Stollnitz: How do I apply more than one filter?

Spero che questo aiuti.

Cheers, Anvaka.

+0

So che è quasi un decennio più tardi, ma il collegamento è morto. – KSwift87

8

Ogni volta che l'utente filtra, il codice è che sostituisce il delegato Filter nella vista insieme con un nuovo, fresco. Inoltre, il nuovo controlla solo i criteri particolari che l'utente ha appena selezionato con un ComboBox.

Quello che vuoi è un unico gestore di filtri che controlla tutti i criteri. Qualcosa di simile:

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

La vista ora può semplicemente associare le proprietà appropriate e il filtro funzionerà.