如何在一个集合视图源上一个接一个地应用多个过滤器函数(AND关系)

时间:2012-10-18 18:26:00

标签: c# wpf filter observablecollection collectionviewsource

我一直在使用绑定到列表视图的Collection View Source对象,而CVS是Observable对象集合之上的视图。

我知道如何使用以下技术应用过滤器:

cvs.Filter += new FilterEventHandler(SomeFilterFunction);

当您只在一个函数中过滤时,这可以正常工作。问题是我想要在已经过滤的CVS之上进行过滤。如果我有另一个函数根据不同的条件过滤视图中的对象,则仅根据第二个过滤器中的条件过滤对象,并且第一个过滤器的结果消失。

以下是一些解释我问题的示例代码:

cvs.Filter += new FilterEventHandler(SomeFilterFunction1);
cvs.Filter += new FilterEventHandler(SomeFilterFunction2);

public void SomeFilterFunction1(object sender, FilterEventArgs e)
{
      SomeObject example = e.Item as SomeObject;
      if(example.Name.Contains("A"))
      {
          e.Accepted = true;
      }
      else
      {
          e.Accepted = false;
      }

}

public void SomeFilterFunction2(object sender, FilterEventArgs e)
{
      SomeObject example = e.Item as SomeObject;
      if(example.Name.Contains("B"))
      {
          e.Accepted = true;
      }
      else
      {
          e.Accepted = false;
      }
}

所以在这个例子中,我只想要过滤器接受字母A和B的“SomeObjects”。我的问题是,当使用filterfunction2进行调用cvs + = Filter时,只接受包含字母B的对象名称,忽略带有字母A的对象。因此,当它们不应该被接受时,接受包含字母B而不是A的对象名称。

我目前解决这个问题的方法是创建一个“Master”过滤器函数,其中包含每个过滤器函数,并且我通过每个过滤器运行每个Object,如果对象通过所有过滤器,则接受它。这确实有效,但我的代码现在变得疯狂,逻辑失控。有谁知道如何对CVS的最后一个过滤器的结果应用新的过滤函数?为什么CVS不会自动执行此操作而不是通过每个过滤器发送每个Object,或者我没有以正确的方式考虑CVS?

2 个答案:

答案 0 :(得分:1)

问题是应用多个过滤器事件处理程序,是否所有处理程序都被调用,而CollectionViewSource未考虑e.Accepted的单个结果。结果将始终是最后一个事件处理程序中e.Accepted的值。

我创建了一个管理器类,允许处理多个FilterEventHandler函数,并使用AND或OR逻辑处理它们的结果。因此,要么所有过滤器都为true,要么至少有一个过滤器结果为true。

public class MultipleFilterHandler
{
    private readonly CollectionViewSource collection;

    public MultipleFilterLogic Operation {get; set; }

    public MultipleFilterHandler(CollectionViewSource collection, MultipleFilterLogic operation)
    {
        this.collection = collection;
        this.Operation = operation;
    }

    public MultipleFilterHandler(CollectionViewSource collection) : 
        this( collection, MultipleFilterLogic.Or)
    {
    }

    private event FilterEventHandler _filter;
    public event FilterEventHandler Filter
    { 
        add
        {
            _filter += value;

            collection.Filter -= new FilterEventHandler(CollectionViewFilter);
            collection.Filter += new FilterEventHandler(CollectionViewFilter);
        }
        remove
        {
            _filter -= value;

            collection.Filter -= new FilterEventHandler(CollectionViewFilter);
            collection.Filter += new FilterEventHandler(CollectionViewFilter);
        }
    }

    private void CollectionViewFilter(object sender, FilterEventArgs e)
    {
        if (_filter == null)
            return;

        foreach (FilterEventHandler invocation in _filter.GetInvocationList())
        {
            invocation(sender, e);

            if ((Operation == MultipleFilterLogic.And && !e.Accepted) || (Operation == MultipleFilterLogic.Or && e.Accepted))
                return;
        }
    }
}

public enum MultipleFilterLogic
{
    And,
    Or
}

只需根据需要在MultipleFilterHandler的Filter属性上添加和删除事件处理程序,它将管理CollectionViewSource的连接。

答案 1 :(得分:1)

你可以这样做:

cvs.Filter += new FilterEventHandler(SomeFilterFunction1);
cvs.Filter += new FilterEventHandler(SomeFilterFunction2);

public void SomeFilterFunction1(object sender, FilterEventArgs e)
{
      SomeObject example = e.Item as SomeObject;
      e.Accepted &= example.Name.Contains("A");
      //if you prefer OR logic use this one:          
      //e.Accepted |= example.Name.Contains("A");

}

public void SomeFilterFunction2(object sender, FilterEventArgs e)
{
      SomeObject example = e.Item as SomeObject;
      e.Accepted &= example.Name.Contains("B");
      //if you prefer OR logic use this one:
      //e.Accepted |= example.Name.Contains("B");
}

这样做的是do和AND(如果使用| =运算符,则为OR)和Accepted属性中的当前值,使得过滤器协同工作。

编辑:这是在.NET 4.5中制作的