【问题标题】:How do you apply multiple filter functions on one collection view source, one after another (AND relation)您如何在一个集合视图源上应用多个过滤器功能,一个接一个(AND关系)
【发布时间】:2012-10-18 18:25:59
【问题描述】:

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

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

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 的对象名称时.

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

【问题讨论】:

    标签: c# wpf filter observablecollection collectionviewsource


    【解决方案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 的连接。

    【讨论】:

    • 我的情况是我在运行时添加了多个过滤器事件处理程序(用于 GUI 中的复选框,因为它们被选中)。我得到了不可预测的结果。我会试一试并在此处编辑结果。
    【解决方案2】:

    你可以这样做:

    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 中制作的

    【讨论】:

      猜你喜欢
      • 2014-03-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-08
      • 1970-01-01
      • 1970-01-01
      • 2017-07-20
      相关资源
      最近更新 更多