在WPF中对ListBox应用各种过滤器
本文关键字:过滤器 应用 ListBox WPF 中对 | 更新日期: 2023-09-27 18:07:38
我有一个ListBox
填充了几个(多达数百个)Phonecall
对象。我希望能够根据各种标准对它们进行过滤,而这些标准是由用户通过表单中的各种复选框决定的。理想的情况是,用户可以应用过滤器来检查调用的时间、调用持续了多长时间以及其他事情。目前,它们一次只能应用一个过滤器。一开始我试着这样做:
static int MaxDuration = 15;
Predicate<object> timeFilter = (object item) =>
{
Phonecall p = item as Phonecall;
return p.IsBadCall == true; //Decided by method in class definition
};
Predicate<object> durationFilter = (object item) =>
{
Phonecall p = item as Phonecall;
return p.Duration > MaxDuration;
};
...
private void applyFiltBtn_Click(object sender, RoutedEventArgs e)
{
if (timeFilterChkB.IsChecked == true)
CallList.Items.Filter = timeFilter;
if (durFilterChkB.IsChecked == true)
CallList.Items.Filter = durationFilter; //Overrides previous filter
}
看到当两个框都被选中时,上面的操作不起作用,我试着做以下操作:
CallList.Items.Filter = (o) =>
{
Phonecall pc = o as Phonecall;
if (timeFilterChkB.IsChecked == true && durFilterChkB.IsChecked == false)
return pc.IsBadCall == true;
else if (timeFilterChkB.IsChecked == false && durFilterChkB.IsChecked == true)
return pc.Duration > MaxDuration;
else if (timeFilterChkB.IsChecked == true && durFilterChkB.IsChecked == true)
return pc.IsBadCall == true && pc.Duration > MaxDuration;
else
return true; //No filter is applied
};
它可以工作,但是看起来很丑,并且只会变成一个大的,难以阅读的"if-else"树(因为有几个其他属性需要随着时间的推移而过滤——大约10个,我宁愿不需要硬编码所有可能的复选框选项)。
简而言之,是否有更好的方法将各种谓词组合到一个过滤器中,或者一次应用多个过滤器,以便只有适合的项显示在ListBox
中?
您也可以将这两种方法结合起来。对于第一部分,存储谓词列表,而不是立即赋值:
var predicates = new List<Predicate<object>>();
if (timeFilterChkB.IsChecked == true)
predicates.Add(timeFilter);
if (durFilterChkB.IsChecked == true)
predicates.Add(durationFilter);
第二部分,应用所有谓词:
CallList.Items.Filter = o =>
predicates.All(predicate => predicate(o));
你创建一个类:
class Filter
{
public bool ShouldApply {get;set;}
public Predicate<object> Predicate {get;set;}
}
你的视图模型有一个类型为ICollection<Filter> Filters
的属性。将所有谓词添加到此集合。复选框被数据绑定到相应的ShouldApply属性。
你的过滤代码看起来像这样:
private void applyFiltBtn_Click(object sender, RoutedEventArgs e)
{
CallList.Items.Filter = (object item) => return filters.All(f=>f(item)); }