2010-10-05 11 views
8

Quiero filtrar un ObservableCollection con un máximo de 3000 elementos en un DataGrid con 6 columnas. El usuario debe poder filtrar en un "& &" entre las 6 columnas.Filtrar una colección con LINQ frente a CollectionView

¿Debo usar LINQ o una CollectionView para ello? LINQ parecía más rápido probando algunas muestras de www. ¿Tienes algún pro/contra?

ACTUALIZACIÓN:

private ObservableCollection<Material> _materialList; 
     private ObservableCollection<Material> _materialListInternal; 

     public MaterialBrowserListViewModel() 
     {   
       _materialListInternal = new ObservableCollection<Material>();   

      for (int i = 0; i < 2222; i++) 
      { 
       var mat = new Material() 
       { 
        Schoolday = DateTime.Now.Date, 
        Period = i, 
        DocumentName = "Excel Sheet" + i, 
        Keywords = "financial budget report", 
        SchoolclassCode = "1", 
       }; 
       _materialListInternal.Add(mat); 
       var mat1 = new Material() 
       { 
        Schoolday = DateTime.Now.Date, 
        Period = i, 
        DocumentName = "Word Doc" + i, 
        Keywords = "Economical staticstics report", 
        SchoolclassCode = "2", 
       }; 
       _materialListInternal.Add(mat1); 
      } 

      MaterialList = CollectionViewSource.GetDefaultView(MaterialListInternal); 
      MaterialList.Filter = new Predicate<object>(ContainsInFilter); 
     }  

     public bool ContainsInFilter(object item) 
     { 
      if (String.IsNullOrEmpty(FilterKeywords)) 
       return true; 

      Material material = item as Material; 
      if (DocumentHelper.ContainsCaseInsensitive(material.Keywords,FilterKeywords,StringComparison.CurrentCultureIgnoreCase))   
       return true;   
      else   
       return false;      
     } 

     private string _filterKeywords; 
     public string FilterKeywords 
     { 
      get { return _filterKeywords; } 
      set 
      { 
       if (_filterKeywords == value) 
        return; 

       _filterKeywords = value; 
       this.RaisePropertyChanged("FilterKeywords"); 
       MaterialList.Refresh();    
      } 
     } 

     public ICollectionView MaterialList { get; set; } 

     public ObservableCollection<Material> MaterialListInternal 
     { 
      get { return _materialListInternal; } 
      set 
      { 
       _materialListInternal = value; 
       this.RaisePropertyChanged("MaterialList"); 
      } 
     } 

Respuesta

1

Para una experiencia interactiva (DataGrid?) Hay que emplear tiempo probablemente la CollectionView. Para una clasificación más orientada a los códigos, LINQ.

Y con un máximo de 3000 elementos, la velocidad no debe ser un factor (mayor) en una IU.

+0

estoy usando un filtro CollectionViewSource simplemente una columna en el momento. ¿Sabes por qué la colección solo se actualiza cuando coloco el método .Refresh() en la siguiente propiedad? cadena privada _filterKeywords cadena pública FilterKeywords { get {return _filterKeywords; } establecer { if (_filterKeywords == value) return; _filterKeywords = value; this.RaisePropertyChanged ("Palabras clave de filtro"); MaterialList.Refresh(); } } – Elisabeth

+0

"¿Sabe por qué ..." - No, pero tal vez si agrega ese código a la pregunta, podría leerlo. –

+0

ok Henk ¡Publiqué todo el código importante! buenas noches ;-) – Elisabeth

3
  • El uso de ICollectionView le ofrece notificaciones automáticas de cambio de colección cuando llama a Refresh. Con LINQ, deberá activar sus propias notificaciones de cambio cuando sea necesario volver a ejecutar el filtro para actualizar la interfaz de usuario. No es difícil, pero requiere un poco más de reflexión que simplemente llamar a Refresh.

  • LINQ es más flexible que el simple filtro de sí/no utilizado por ICollectionView, pero si no está haciendo algo complejo, no hay ninguna ventaja en esa flexibilidad.

  • Como dijo Henk, no debería haber una diferencia de rendimiento notable en la interfaz de usuario.

1

¿Qué tal ambos? Thomas Levesque construyó un contenedor LINQ habilitado alrededor del ICollectionView.

Uso:

IEnumerable<Person> people; 

// Using query comprehension 
var query = 
    from p in people.ShapeView() 
    where p.Age >= 18 
    orderby p.LastName, p.FirstName 
    group p by p.Country; 

query.Apply(); 

// Using extension methods 
people.ShapeView() 
     .Where(p => p.Age >= 18) 
     .OrderBy(p => p.LastName) 
     .ThenBy(p => p.FirstName) 
     .Apply(); 

Código:

public static class CollectionViewShaper 
{ 
    public static CollectionViewShaper<TSource> ShapeView<TSource>(this IEnumerable<TSource> source) 
    { 
     var view = CollectionViewSource.GetDefaultView(source); 
     return new CollectionViewShaper<TSource>(view); 
    } 

    public static CollectionViewShaper<TSource> Shape<TSource>(this ICollectionView view) 
    { 
     return new CollectionViewShaper<TSource>(view); 
    } 
} 

public class CollectionViewShaper<TSource> 
{ 
    private readonly ICollectionView _view; 
    private Predicate<object> _filter; 
    private readonly List<SortDescription> _sortDescriptions = new List<SortDescription>(); 
    private readonly List<GroupDescription> _groupDescriptions = new List<GroupDescription>(); 

    public CollectionViewShaper(ICollectionView view) 
    { 
     if (view == null) 
      throw new ArgumentNullException("view"); 
     _view = view; 
     _filter = view.Filter; 
     _sortDescriptions = view.SortDescriptions.ToList(); 
     _groupDescriptions = view.GroupDescriptions.ToList(); 
    } 

    public void Apply() 
    { 
     using (_view.DeferRefresh()) 
     { 
      _view.Filter = _filter; 
      _view.SortDescriptions.Clear(); 
      foreach (var s in _sortDescriptions) 
      { 
       _view.SortDescriptions.Add(s); 
      } 
      _view.GroupDescriptions.Clear(); 
      foreach (var g in _groupDescriptions) 
      { 
       _view.GroupDescriptions.Add(g); 
      } 
     } 
    } 

    public CollectionViewShaper<TSource> ClearGrouping() 
    { 
     _groupDescriptions.Clear(); 
     return this; 
    } 

    public CollectionViewShaper<TSource> ClearSort() 
    { 
     _sortDescriptions.Clear(); 
     return this; 
    } 

    public CollectionViewShaper<TSource> ClearFilter() 
    { 
     _filter = null; 
     return this; 
    } 

    public CollectionViewShaper<TSource> ClearAll() 
    { 
     _filter = null; 
     _sortDescriptions.Clear(); 
     _groupDescriptions.Clear(); 
     return this; 
    } 

    public CollectionViewShaper<TSource> Where(Func<TSource, bool> predicate) 
    { 
     _filter = o => predicate((TSource)o); 
     return this; 
    } 

    public CollectionViewShaper<TSource> OrderBy<TKey>(Expression<Func<TSource, TKey>> keySelector) 
    { 
     return OrderBy(keySelector, true, ListSortDirection.Ascending); 
    } 

    public CollectionViewShaper<TSource> OrderByDescending<TKey>(Expression<Func<TSource, TKey>> keySelector) 
    { 
     return OrderBy(keySelector, true, ListSortDirection.Descending); 
    } 

    public CollectionViewShaper<TSource> ThenBy<TKey>(Expression<Func<TSource, TKey>> keySelector) 
    { 
     return OrderBy(keySelector, false, ListSortDirection.Ascending); 
    } 

    public CollectionViewShaper<TSource> ThenByDescending<TKey>(Expression<Func<TSource, TKey>> keySelector) 
    { 
     return OrderBy(keySelector, false, ListSortDirection.Descending); 
    } 

    private CollectionViewShaper<TSource> OrderBy<TKey>(Expression<Func<TSource, TKey>> keySelector, bool clear, ListSortDirection direction) 
    { 
     string path = GetPropertyPath(keySelector.Body); 
     if (clear) 
      _sortDescriptions.Clear(); 
     _sortDescriptions.Add(new SortDescription(path, direction)); 
     return this; 
    } 

    public CollectionViewShaper<TSource> GroupBy<TKey>(Expression<Func<TSource, TKey>> keySelector) 
    { 
     string path = GetPropertyPath(keySelector.Body); 
     _groupDescriptions.Add(new PropertyGroupDescription(path)); 
     return this; 
    } 

    private static string GetPropertyPath(Expression expression) 
    { 
     var names = new Stack<string>(); 
     var expr = expression; 
     while (expr != null && !(expr is ParameterExpression) && !(expr is ConstantExpression)) 
     { 
      var memberExpr = expr as MemberExpression; 
      if (memberExpr == null) 
       throw new ArgumentException("The selector body must contain only property or field access expressions"); 
      names.Push(memberExpr.Member.Name); 
      expr = memberExpr.Expression; 
     } 
     return String.Join(".", names.ToArray()); 
    } 
} 

Crédito: http://www.thomaslevesque.com/2011/11/30/wpf-using-linq-to-shape-data-in-a-collectionview/

Cuestiones relacionadas