如何在ObjectListView中过滤多个SubItems

时间:2012-03-21 18:13:06

标签: c# .net vb.net winforms objectlistview

所以,我试图以编程方式将ModelFilter添加到我的ObjectListView中,它将分别查看两个(或更多)列和过滤器。目前,我认为ObjectListView只支持一个过滤器,但我可能在代码/文档中遗漏了一些东西。

例如,我的一个预期过滤器是查看“Active”列,其值为“A”或“T”。另一栏是主管姓名。所以,我想找到Supervisor name =“Smith”和Active =“A”的所有条目。

我可以使用TextMatchFilter分别使用过滤器来处理这些选项中的任何一个,但是无法弄清楚如何让它们同时工作。

我看到的一个小问题是,如果超级用户名包含“A”,那么使用标准过滤器将返回整行。我已经能够通过以编程方式将列的Searchable属性设置为false来解决这个问题,如果我不想查看它们,然后在列表被过滤后再将它们重新打开。但是,我有一种感觉,如果我将Searchable打开为Supervisor专栏,我会得到不想要的结果。

有没有人知道让过滤器在多个列上工作的方法,只使用每个过滤器的指示列?

(我没有示例代码可以帮助解决这个问题。但是,如果你真的想看看我的滤波代码是什么,我会乐意添加它;但是它在VB中。)

当前代码 - 查看用户选择的值(searchMeth)并启用对该列的搜索。然后它搜索txtSearch框中输入的内容。但是,除此之外,我还想为Supervisor添加一个额外的过滤器。 (参见AndAlso评论

    olvEmps.UseFiltering = True
    OlvColumn1.Searchable = False
    OlvColumn2.Searchable = False
    OlvColumn4.Searchable = False
    OlvColumn3.Searchable = False
    OlvColumn5.Searchable = False

    Select Case searchMeth
        Case "Name"
            OlvColumn1.Searchable = True
        Case "Employee Number"
            OlvColumn2.Searchable = True
        Case "Department"
            OlvColumn3.Searchable = True
    End Select

    olvEmps.OwnerDraw = True
    Dim tFilter As BrightIdeasSoftware.TextMatchFilter = BrightIdeasSoftware.TextMatchFilter.Contains(olvEmps, txtSearch.Text)
    'andalso olvColumn5 = supeName?

    olvEmps.ModelFilter = tFilter
    olvEmps.DefaultRenderer = New BrightIdeasSoftware.HighlightTextRenderer(tFilter)

    OlvColumn1.Searchable = True
    OlvColumn2.Searchable = True
    OlvColumn3.Searchable = True
    OlvColumn4.Searchable = True
    OlvColumn5.Searchable = True

2 个答案:

答案 0 :(得分:7)

我确信PredicateBuilder解决方案可行,但ObjectListView已经提供了一个更简单的解决方案。

TextMatchFilter可以限制为通过Columns属性搜索的列。将其设置为您要考虑的列数组。

TextMatchFilter filter1 = TextMatchFilter.Contains(olvEmps, txtSearch.Text)
filter1.Columns = new [] { this.olvColumn1, this.olvColumn2 };

您可以使用CompositeAllFilter组合两个过滤器,以匹配两个或更多其他过滤器。

this.olvEmps.ModelFilter = new CompositeAllFilter(new List<IModelFilter> { filter1, filter2 }); 

答案 1 :(得分:1)

虽然我还没有完全理解你的交易,但我会用PredicateBuilder给你一个镜头,它是LINQKit程序集的一部分,你可以下载here

因此,对多列进行过滤将变得容易。也许您应该考虑在过滤源集合后重置ObjectListView控件的绑定。

总的来说,我会做以下几点:

  1. 加载您的原点;
  2. 通过数据绑定显示它们;
  3. 点击列进行过滤后,请调用“过滤器”方法,该方法将应用您的谓词;
  4. 使用新过滤的集合重新绑定您的控件。
  5. 请参阅前面提供的链接中的PredicateBuilder文档。此处说明了构建动态过滤器的另一个示例:对于我实施的搜索引擎,“How would this query translate into a dynamic Linq expression?”。

    就我而言,过滤器直接应用于数据库结果。除此之外,它甚至可以在内存数据的情况下使用,因为它是基于Linq的。

    我确信当您发布代码示例以过滤信息时,我将能够提供进一步的帮助。

      

    编辑#1

    在我阅读了提供的代码示例之后,我认为这就是诀窍。至于Searchable属性,我对这种方法并不熟悉,所以也许我会错过你的代码中的重要内容,如果是这样的话,请随意指出我可能错过的内容。 =)

    请注意,我假设您的所有数据都是字符串,因为我正在验证您的数据是空还是空格。此外,我看到它的方式,过滤结果集是为了只显示符合特定标准的记录。您不希望看到不符合标准的内容。它与SQL中的WHERE子句相同。

    public class FilterCriterion {
        public bool HasEmployeeName { get { return !string.IsNullOrWhiteSpace(EmployeeName); } }
        public bool HasEmployeeNumber { get { return !string.IsNullOrWhiteSpace(EmployeeNumber); } }
        public bool HasDepartment { get { return !string.IsNullOrWhiteSpace(Department); } }
        public string EmployeeName { get; set; }
        public string EmployeeNumber { get; set; }
        public string Department { get; set; }
    }
    

    FilterCriterion类应用于对数据源,集合或任何内容应用您想要的任何过滤器。

    var employees = LoadEmployeesFromUnderlyingDataStore();
    var criterion = new FilterCriterion();
    
    switch(searchMeth) {
        case "Name": filter.EmployeeName = "the name to filter by"; break;
        case "EmployeeNumber": filter.EmployeeNumber = "the number to filter by"; break;
        case "Department": filter.Department = "the department to filter by"; break;
    }
    
    var filter = PredicateBuilder.True<Employee>(); // assuming you have an employee class.
    if (criterion.HasEmployeeName) 
        filter.And(e => e.Name.ContainsLike(criterion.EmployeeName));
    if (criterion.HasEmployeeNumber)
        filter.And(e => e.EmployeeNumber.ContainsLike(criterion.EmployeeNumber));
    if (criterion.HasDepartment)
        filter.And(e => e.Department.ContainsLike(criterion.Department));
    
    var filteredEmployees = employees.Where(filter);
    
    // Supply your ObjectListView the way you're used to and this shall function.
    

    除此之外,您还可以,如果必须处理此类字符串变量,请将ContainsLike扩展方法写入字符串类。

    namespace System {
    public static class StringExtensions {
        public static bool ContainsLike(this string input, string value) {
            if (string.IsNullOrWhiteSpace(input) || string.IsNullOrWhiteSpace(value)) return false;
            input = input.ToLower().RemoveDiacritics();
            value = value.ToLower().RemoveDiacritics();
            if (string.IsNullOrWhiteSpace(input) || string.IsNullOrWhiteSpace(value)) return false;
            return input.Contains(value);
        }
        public static string RemoveDiacritics(this string input) {
            return input == null ? null :      
                            Encoding.ASCII.GetString(Encoding.GetEncoding(1251).GetBytes(input));
        }
    }
    }
    

    我希望这会有所帮助,否则告诉我我从你的问题中误解了什么,我们会一起尝试解决这个问题。

    如果你需要这个代码的VB版本,我会尝试翻译我最好的VB知识。

    此代码按原样提供,尚未经过测试,但两种字符串扩展方法除外。