3

I have been working with a Collection View Source object that is bound to a listview and the CVS is a view on top of Observable Collection of objects.

I know how to apply a filter using the following technique:

cvs.Filter += new FilterEventHandler(SomeFilterFunction);

This works fine when you are only filtering in one function. The problem is when I want to filter on top of the already filtered CVS. If I have another function that filters the objects in the view based on different criteria, the objects are filtered ONLY on the criteria in the second filter and the results of the first filter go away.

Here is some example code to explain my problem:

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;
      }
}

So in this example, I want only "SomeObjects" with the letters A and B accepted by the filters. My problem is that When make the call cvs+=Filter with the filterfunction2, only Objects Name containing the letter B are accepted, disregarding the objects with letter A. So an Objects name containing the letter B but not A are accepted, when they shouldnt be.

My current solution to this problem has been creating a "Master" filter function that has every filter function inside of it and I run every Object through every filter and if the object makes it through ALL of the filters then it is accepted. This does work but my code is getting crazy now and logic is getting out of control. Does anyone know how to apply a new filter function on the result of the last filter for a CVS? Why doesn't the CVS just do this automatically instead of sending every Object through every filter or am I not thinking about CVS in the right way?

4

2 回答 2

1

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

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

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 的连接。

于 2013-04-12T18:55:03.570 回答
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");
}

这将执行与 Accepted 属性中的当前值的 do 和 AND(或 OR,如果您使用 |= 运算符),使您的过滤器一起工作。

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

于 2014-12-13T11:37:11.380 回答