Filtrar uma coleção observável
Eu tenho umListView
controle que exibe itens de uma coleção observável. Esses itens precisam ser filtrados. Eu sou capaz de fazer isso com umCollectionViewSource
, mas o filtro precisa ser atualizado sempre que um item é alterad
Meus itens ficam assim:
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; }
}
}
Então eu tenho esseListView
de quemItemSource
está vinculado à coleção.
// member of the user control class
private CollectionViewModel collection = new CollectionViewModel();
// in the constructor
listView.ItemSource = collection.Collection.
Isso não filtra nada. Então, eu tenho essas caixas de seleção e elas devem indicar quais itens (dependendo do estado) devem ser exibidos. Eu usei então umCollectionViewSource
:
private void UpdateView()
{
var source = CollectionViewSource.GetDefaultView(collection.Collection);
source.Filter = p => Filter((ProjectViewModel)p);
listStatus.ItemsSource = source;
}
O método de filtro é assim:
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);
}
Isso tem a desvantagem de capturar os valores das caixas de seleção, então eu tenho que chamar esse método UpdateView
) sempre que uma caixa de seleção estiver marcada. Mas funciona.
No entanto, o estado do item muda e, se "concluído" não estiver marcado, por exemplo, quando um item entra em "pronto", ele deve ser removido da exibição. Obviamente isso não muda, a menos que eu ligue novamente paraUpdateView
. Então, eu preciso chamar esse método sempre que algo mudar. Isso me parece feio e ineficient
Então, minha pergunta é: isso pode ser feito de uma maneira melho