wpf 过滤一个可观察的集合
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9615891/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Filter an observable collection
提问by Marius Bancila
I have a ListView
control that displays items from an observable collection. These items need to be filtered. I am able to do that with a CollectionViewSource
, but the filter needs to be updated each time an item changes.
我有一个ListView
控件,可以显示可观察集合中的项目。这些项目需要过滤。我可以使用 a 来做到这一点CollectionViewSource
,但是每次项目更改时都需要更新过滤器。
My items looks like this:
我的项目是这样的:
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 ListView
whose ItemSource
is bound to the collection.
然后,我有这个ListView
,其ItemSource
是绑定到集合。
// member of the user control class
private CollectionViewModel collection = new CollectionViewModel();
// in the constructor
listView.ItemSource = collection.Collection.
This doesn't filter anything. So I have these check boxes and they should indicate which items (depending of the state) should be displayed. I have used then a CollectionViewSource
:
这不会过滤任何东西。所以我有这些复选框,它们应该指示应该显示哪些项目(取决于状态)。我已经使用了一个CollectionViewSource
:
private void UpdateView()
{
var source = CollectionViewSource.GetDefaultView(collection.Collection);
source.Filter = p => Filter((ProjectViewModel)p);
listStatus.ItemsSource = source;
}
The filter method looks like this:
过滤方法如下所示:
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 checkboxes, so I have to call this method (UpdateView
) each time a checkbox is checked. But it works.
这样做的缺点是它会捕获复选框的值,因此UpdateView
每次选中复选框时我都必须调用此方法 ( )。但它有效。
However, the item state does change and if "done" is not checked for instance, when an item goes into "done" it should be removed from the view. Obviously that doesn't change unless I again call UpdateView
. So I need to call this method each time something changes. That looks ugly and inefficient to me.
但是,项目状态确实会发生变化,例如,如果未选中“完成”,则当项目进入“完成”状态时,应将其从视图中删除。显然,除非我再次致电,否则这不会改变UpdateView
。所以每次发生变化时我都需要调用这个方法。这对我来说看起来很丑陋且效率低下。
So my question is, can this be done in a nicer way?
所以我的问题是,这可以以更好的方式完成吗?
回答by Rohit Vats
Bind your ListView
directly to the filtered collection instead of the ObservableCollection by creating a property -
ListView
通过创建属性将您的直接绑定到过滤的集合而不是 ObservableCollection -
public ICollectionView YourFilteredCollection
{
get
{
var source = CollectionViewSource.GetDefaultView(collection.Collection);
source.Filter = p => Filter((ProjectViewModel)p);
return source;
}
}
So, now simply you need to call Refresh() on your collection on your check boxes state changed event like this -
因此,现在您只需在复选框状态更改事件的集合上调用 Refresh(),如下所示 -
YourFilteredCollection.Refresh();
To refresh the collection based on any state change in the item class, you can generalize it by hooking the PropertyChanged
event of your item class (for this your class need to implement INotifyPropertyChanged) and from there you can call refresh like this -
要根据 item 类中的任何状态更改刷新集合,您可以通过挂钩PropertyChanged
item 类的事件来概括它(为此,您的类需要实现 INotifyPropertyChanged),然后您可以像这样调用 refresh -
foreach (YourClass item in collection.Collection)
{
item.PropertyChanged += new PropertyChangedEventHandler(item_PropertyChanged);
}
void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
YourFilteredCollection.Refresh();
}
So, whenever any property changes in your item class, your collection will be filtered.
因此,每当您的项目类中的任何属性发生变化时,您的集合都将被过滤。
回答by paparazzo
I like to use DataTriggers for that. For your logic would need to use a multivalue converter.
我喜欢为此使用 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>
回答by Joel Lucsy
Use a tool like ContinuousLinq. You bind your listview to a query that will reevaluate when an item in the list (or the list itself) changes.
使用像ContinuousLinq这样的工具。您将列表视图绑定到一个查询,该查询将在列表中的项目(或列表本身)更改时重新评估。