2012-03-21 31 views
1

因此,我试图以编程方式将ModelFilter添加到我的ObjectListView中,这将分别查看两个(或多个)列和过滤器。目前,我认为ObjectListView只支持一个过滤器,但我可能在代码/文档中缺少一些东西。如何过滤ObjectListView中的多个子项目

举例来说,我的一个预期过滤器是查看“活动”列,并且其值为“A”或“T”。另一列是主管名称。所以,我想查找Supervisor name =“Smith”和Active =“A”的所有条目。

我可以使用TextMatchFilter单独使用这两个选项中的任何一个,但无法弄清楚如何让两者同时工作。

我看到的小问题是,如果主管名称包含“A”,则使用标准过滤器将返回整行。我已经能够通过编程设置列的Searchable属性为false来解决这个问题,如果我不想查看它们,那么一旦列表被过滤,就将它们重新打开。不过,我有一种感觉,如果我将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 
+0

是否添加您的过滤代码,以便它可以更容易地帮助。 =)无论是VB还是C#,只要您用良好的语言标签标记您的问题,这样回答者就能够以所需的语言为您提供帮助,无论它是VB还是C#。 =) – 2012-03-22 03:30:44

+0

已添加代码并更改了标签。谢谢@Will – APrough 2012-03-22 12:35:37

+0

我会看看我的代码示例可以做什么。我希望它会有帮助! =) – 2012-03-22 16:52:10

回答

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如何通过objectlistview自己的创建者建议的原生3行解决方案? – sasfrog 2012-04-17 23:11:18

+0

这太好了。我会尽快尝试。谢谢。 – APrough 2012-04-18 12:05:51

+1

这工作完美。感谢您的信息(我告诉过您我错过了文档中的某些内容),并感谢您的出色控制。 – APrough 2012-04-19 13:50:49

1

虽然我还没有完全理解你的问题,我会给它与PredicateBuilder那就是LINQKit组件,您可以下载here的一部分了一枪。

。因此,对多列过滤应得到容易也许应考虑您重置ObjectListView控制的结合,一旦您的源集合已被过滤

眼观,我会做了解以下信息:

  1. 加载您的数据;
  2. 通过数据绑定显示它们;
  3. 一旦为过滤器单击了某个列,请调用您的“过滤器”方法来应用您的谓词;
  4. 用新过滤的集合重新绑定您的控件。

请参阅前面提供的链接中的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知识。

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

+0

我会去看看PredicateBuilder。不幸的是,我不熟悉LINQ(但是),但是基于我对上述解决方案的理解,似乎我不得不添加一些数据绑定?目前我使用ObjectListView的SetObjects方法使用一组对象。另外,我不希望最终用户点击一列来过滤;我将使用Tile视图,它甚至不提供列标题来实现。如果PredicateBuilder能够做到这一点,我会让你知道。 – APrough 2012-03-22 12:39:24

+0

哦,我想我总是可以在我的原始集合上使用lambdas,并使用新的过滤集合再次填充ObjectListView。这似乎是一种解决方法,但是。 – APrough 2012-03-22 12:41:02

+0

你绝对可以使用lambda表达式和Linq的力量来帮助你。请允许我一段时间,以便我可以找出适合你的东西,看看它是否会有所帮助。 =) – 2012-03-22 16:54:09