Фильтрация коллекции с помощью LINQ vs CollectionView - PullRequest
9 голосов
/ 06 октября 2010

Я хочу отфильтровать коллекцию ObservableCollection максимум с 3000 элементами в DataGrid с 6 столбцами. Пользователь должен иметь возможность фильтровать "&&" - все 6 столбцов.

Должен ли я использовать LINQ или CollectionView для него? LINQ, кажется, быстрее пробовал несколько примеров www. Есть ли у вас плюсы / минусы?

UPDATE

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

Ответы [ 4 ]

3 голосов
/ 06 октября 2010
  • Использование ICollectionView позволяет автоматически собирать уведомления об изменениях при вызове команды «Обновить». Используя LINQ, вы должны будете запускать свои собственные уведомления об изменениях, когда фильтр должен быть перезапущен для обновления пользовательского интерфейса. Не сложно, но требует немного больше мысли, чем просто вызов Refresh.

  • LINQ более гибок, чем простая фильтрация да / нет, используемая ICollectionView, но если вы не делаете что-то сложное, на самом деле такой гибкости не будет.

  • Как заявил Хенк, в пользовательском интерфейсе не должно быть заметной разницы в производительности.

1 голос
/ 14 января 2014

Как насчет обоих? Томас Левеск построил оболочку с поддержкой LINQ вокруг ICollectionView.

Использование:

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();

Код:

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

Кредит: http://www.thomaslevesque.com/2011/11/30/wpf-using-linq-to-shape-data-in-a-collectionview/

1 голос
/ 06 октября 2010

Для интерактивного взаимодействия (DataGrid?) Вы должны, вероятно, использовать CollectionView.Для более ориентированной на код сортировки, LINQ.

И с максимум 3000 элементов скорость не должна быть (основным) фактором в пользовательском интерфейсе.

0 голосов
/ 14 марта 2018

На основании визуальной сложности и количества элементов действительно будет заметная разница в производительности, поскольку метод Refresh воссоздает весь вид !!!

...