Mam kontrolkę ListView
, która wyświetla elementy z obserwowalnej kolekcji. Te elementy muszą być filtrowane. Mogę to zrobić z CollectionViewSource
, ale filtr musi być aktualizowany za każdym razem, gdy zmienia się przedmiot.Filtrowanie obserwowalnej kolekcji
Moi pozycji wygląda następująco:
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; }
}
}
Wtedy mam ten ListView
którego ItemSource
jest związany z kolekcji.
// member of the user control class
private CollectionViewModel collection = new CollectionViewModel();
// in the constructor
listView.ItemSource = collection.Collection.
To niczego nie filtruje. Tak więc mam te pola wyboru i powinny one wskazywać, które elementy (w zależności od stanu) powinny być wyświetlane. Użyłem wtedy CollectionViewSource
:
private void UpdateView()
{
var source = CollectionViewSource.GetDefaultView(collection.Collection);
source.Filter = p => Filter((ProjectViewModel)p);
listStatus.ItemsSource = source;
}
Sposób filtr wygląda następująco:
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);
}
Ma to tę wadę, że rejestruje wartości pól, więc muszę wywołać tę metodę (UpdateView
) za każdym razem, gdy zaznaczone jest pole wyboru. Ale działa.
Jednak stan elementu zmienia się, a jeśli "wykonano" nie jest sprawdzany na przykład, gdy element przechodzi do "zrobione", powinien zostać usunięty z widoku. Oczywiście to się nie zmieni, chyba że ponownie zadzwonię pod numer UpdateView
. Tak więc muszę wywoływać tę metodę za każdym razem, gdy coś się zmienia. To dla mnie wygląda brzydko i nieefektywnie.
Moje pytanie brzmi: czy można to zrobić w przyjemniejszy sposób?
Postawiłem inne podejście jako odpowiedź, ale pamiętam, że filtry działają bez wywołania funkcji Update(). Spróbuj wdrożyć program NotifyPropertyChanged w projekcie - powiązanie nie będzie świadome zmiany bez niego. – Paparazzi