Filtering an Observed Collection

I have a control ListViewthat displays items from an observable collection. These items must be filtered. I can do this with CollectionViewSource, but the filter needs to be updated every time an item changes.

My items are as follows:

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

Then I have this ListViewone whose is ItemSourceattached to the collection.

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

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

It does not filter anything. Therefore, I have these checkboxes and they should indicate which elements (depending on the state) should be displayed. I used then CollectionViewSource:

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

The filter method is as follows:

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

This has the disadvantage that it captures the values ​​of the flags, so I have to call this method ( UpdateView) every time the flag is checked. But it works.

, "done" , , "", . , , UpdateView. , - . .

, : ?

+5
3

ListView ObservableCollection, -

public ICollectionView YourFilteredCollection
{
   get
   {      
      var source = CollectionViewSource.GetDefaultView(collection.Collection);
      source.Filter = p => Filter((ProjectViewModel)p);
      return source;
   }
}

, Refresh() , -

YourFilteredCollection.Refresh();

, , PropertyChanged ( INotifyPropertyChanged), , -

foreach (YourClass item in collection.Collection)
{
  item.PropertyChanged += new PropertyChangedEventHandler(item_PropertyChanged);
}

void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
  YourFilteredCollection.Refresh();
}

, , - , .

+13

DataTriggers . .

 <ListView Grid.Row="3" Grid.Column="2" ItemsSource="{Binding Path=GabeLib.DocFieldsAll}">
        <ListView.ItemContainerStyle>
            <Style TargetType="{x:Type ListViewItem}"  >
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Path=Active}" Value="False">
                        <Setter Property="Visibility" Value="Collapsed"/>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding Path=FieldDef.ID}" Value="0">
                        <Setter Property="Visibility" Value="Collapsed"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </ListView.ItemContainerStyle>
+4

Use a tool like ContinuousLinq . You associate your list with a request that will be reevaluated when an item in the list (or the list itself) changes.

+1
source

All Articles