在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中?

在WPF中对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)); }