3

Оказывается, что фильтрация в ObservableCollection с CollectionViewSource не представляется возможным в WinRT:Metro App CollectionViewSource ObservableCollection Фильтр

See here!

можно фильтровать с помощью LINQ, но как я могу получить UI для обновления, если сделаны изменения, влияющие на отфильтрованные данные?

ответ

4

Я закончил тем, что писал мой собственный класс для достижения желаемого эффекта:

public class ObservableCollectionView<T> : ObservableCollection<T> 
{ 
    private ObservableCollection<T> _view; 
    private Predicate<T> _filter; 

    public ObservableCollectionView(IComparer<T> comparer) 
     : base(comparer) 
    { 

    } 

    public ObservableCollectionView(IComparer<T> comparer, IEnumerable<T> collection) 
     : base(comparer, collection) 
    { 

    } 

    public ObservableCollectionView(IComparer<T> comparer, IEnumerable<T> collection, Predicate<T> filter) 
     : base(comparer, collection == null ? new T[] { } : collection) 
    { 
     if (filter != null) 
     { 
      _filter = filter; 

      if (collection == null) 
       _view = new ObservableCollection<T>(comparer); 
      else 
       _view = new ObservableCollection<T>(comparer, collection); 
     } 
    } 

    public ObservableCollection<T> View 
    { 
     get 
     { 
      return (_filter == null ? this : _view); 
     } 
    } 

    public Predicate<T> Filter 
    { 
     get 
     { 
      return _filter; 
     } 
     set 
     { 
      if (value == null) 
      { 
       _filter = null; 
       _view = new ObservableCollection<T>(Comparer); 
      } 
      else 
      { 
       _filter = value; 
       Fill(); 
      } 
     } 
    } 

    private void Fill() 
    { 
     _view = new ObservableCollection<T>(Comparer); 
     foreach (T item in this) 
     { 
      if (Filter(item)) 
       View.Add(item); 
     } 
    } 

    private int this[T item] 
    { 
     get 
     { 
      int foundIndex = -1; 
      for (int index = 0; index < View.Count; index++) 
      { 
       if (View[index].Equals(item)) 
       { 
        foundIndex = index; 
        break; 
       } 
      } 
      return foundIndex; 
     } 
    } 

    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) 
    { 
     base.OnCollectionChanged(e); 

     if (_filter != null) 
     { 
      switch (e.Action) 
      { 
       case NotifyCollectionChangedAction.Add: 
        foreach (T item in e.NewItems) 
         if (Filter(item)) 
          View.Add(item); 
        break; 

       case NotifyCollectionChangedAction.Move: 

        break; 

       case NotifyCollectionChangedAction.Remove: 
        foreach (T item in e.OldItems) 
         if (Filter(item)) 
          View.Remove(item); 
        break; 

       case NotifyCollectionChangedAction.Replace: 
        for (int index = 0; index < e.OldItems.Count; index++) 
        { 
         T item = (T)e.OldItems[index]; 
         if (Filter(item)) 
         { 
          int foundIndex = this[item]; 
          if (foundIndex != -1) 
           View[foundIndex] = (T)e.NewItems[index]; 
         } 
        } 
        break; 

       case NotifyCollectionChangedAction.Reset: 
        Fill(); 
        break; 
      } 
     } 
    } 

    protected override void OnPropertyChanged(PropertyChangedEventArgs e) 
    { 
     base.OnPropertyChanged(e); 

     if (_filter != null) 
     { 
    // TODO: Implement code for property changes 
     } 
    } 
} 

еще не совершенны. Поэтому приветствуются улучшения/предложения.

Теперь вы можете привязать этот объект непосредственно к элементу управления с помощью свойства «Вид».

+0

не идеальный ... YET! можете ли вы показать простой пример использования? Было бы лучше понять эту цель/преимущества этого класса. – letiagoalves

+1

Назначение: сортируемый и фильтрованный ObservableCollection. Создайте экземпляр этого объекта, используйте, как обычно, с помощью ObservableCollection. Имеет свойство фильтра в виде предиката, поэтому вы можете фильтровать данные. Затем при привязке к элементу управления привязывается к свойству вида. это оно! – c0D3l0g1c

+0

Хорошее решение. Я собираюсь использовать это в своем проекте на данный момент! –

0

Вы должны убедиться, что изменения фильтрации наблюдается, так что вы можете установить источник CollectionViewSource к ObservableCollection и внести изменения в этой коллекции или назначить новый Source из CVS на новую, отфильтрованную коллекцию.

+0

У меня есть источник ObservableCollection, который я фильтрую и возвращаю IEnumerable. Затем передаю это конструктору ObservableCollection и присваиваю CollectionViewSource. Обновления происходят от источника ObservableCollection. Теперь их разрыв между исходной и отфильтрованной коллекциями, поэтому изменения в источнике не подобраны фильтром. Как мне это преодолеть? – c0D3l0g1c

+0

Вам необходимо отфильтровать и назначить его еще раз. Альтернативно обновляйте отфильтрованную коллекцию при обновлении оригинала. –

+0

У меня есть ... см. Мой ответ ниже. – c0D3l0g1c