我有一个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
,否则不会改变。所以我需要在每次更改时调用此方法。这对我来说看起来很丑陋而且效率低下。
所以我的问题是,这可以以更好的方式完成吗?
答案 0 :(得分:19)
通过创建属性将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();
}
因此,只要您的商品类中的任何商品更改,您的收藏品就会被过滤。
答案 1 :(得分:5)
我喜欢使用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>
答案 2 :(得分:1)
使用ContinuousLinq之类的工具。您将列表视图绑定到一个查询,该查询将在列表中的项目(或列表本身)发生更改时重新评估。