Фильтр наблюдаемой коллекции

У меня есть элемент управления ListView, который отображает элементы из наблюдаемой коллекции. Эти элементы должны быть отфильтрованы. Я могу сделать это с помощью CollectionViewSource, но фильтр необходимо обновлять каждый раз при изменении элемента.

Мои элементы выглядят следующим образом:

enum Status {Done, Failed, Skipped, ...}

class Project {
  public string Name {get;set;}
  public Status Status {get;set;}
  // etc. etc.
}

class ProjectViewModel : INotifyPropertyChanged {
  private Project project;

  public ProjectBuildInfoViewModel(ProjectBuildInfo project)
  {
    this.project = project;
  }

  public string Name
  {
     get { return project.Name; }
     set { project.Name = value; OnPropertyChanged("Name"); }
  }

  // etc. etc.
}

class CollectionViewModel {
  private ObservableCollection<ProjectViewModel> projects = 
             new ObservableCollection<ProjectViewModel>();

  public ObservableCollection<ProjectViewModel> Collection
  {
     get { return projects; }
     private set {projects = value; }
  } 
}

Затем у меня есть ListView, чей ItemSourceпривязан к коллекции.

// member of the user control class
private CollectionViewModel collection = new CollectionViewModel();

// in the constructor
listView.ItemSource = collection.Collection.

Это ничего не фильтрует. Итак, у меня есть эти флажки, и они должны указывать, какие элементы (в зависимости от состояния) должны отображаться.Затем я использовал CollectionViewSource:

private void UpdateView()
{
  var source = CollectionViewSource.GetDefaultView(collection.Collection);
  source.Filter = p => Filter((ProjectViewModel)p);
  listStatus.ItemsSource = source;
}

Метод фильтрации выглядит следующим образом:

private bool Filter(ProjectViewModel project)
{
     return (ckFilterDone.IsChecked.HasValue && ckFilterDone.IsChecked.Value && project.Status == Status.Done) ||
            (ckFilterFailed.IsChecked.HasValue && ckFilterFailed.IsChecked.Value && project.Status == Status.Failed) ||
            (ckFilterSkipped.IsChecked.HasValue && ckFilterSkipped.IsChecked.Value && project.Status == Status.Skipped);
}

Недостатком этого метода является захват значений флажков, поэтому мне приходится вызывать этот метод ( UpdateView) каждый раз, когда установлен флажок. Но это работает.

Тем не менее, состояние элемента изменяется, и если, например, не отмечено «готово», то при переходе элемента в состояние «готово» его следует удалить из представления. Очевидно, что это не изменится, если я снова не вызову UpdateView. Поэтому мне нужно вызывать этот метод каждый раз, когда что-то меняется. Это выглядит некрасиво и неэффективно для меня.

Итак, мой вопрос: можно ли это сделать получше?

7
задан wonea 16 February 2017 в 08:48
поделиться