Как вы применяете несколько функций фильтра к одному источнику представления коллекции, один за другим (отношение И)

Я работал с исходным объектом представления коллекции, который привязан к списку, а CVS представляет собой представление поверх наблюдаемой коллекции объектов.

Я знаю, как применить фильтр, используя следующую технику:

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

Итак, в этом примере мне нужны только «SomeObjects» с буквами A и B, принимаемыми фильтрами. Моя проблема заключается в том, что при вызове cvs+=Filter с помощью filterfunction2 принимаются только имена объектов, содержащие букву B, без учета объектов с буквой A. Таким образом, имена объектов, содержащие букву B, но не A, принимаются, когда они не должны быть .

Моим текущим решением этой проблемы было создание функции фильтра «Мастер», в которой есть каждая функция фильтра, и я запускаю каждый объект через каждый фильтр, и если объект проходит через ВСЕ фильтры, он принимается. Это работает, но мой код сейчас сходит с ума, а логика выходит из-под контроля. Кто-нибудь знает, как применить новую функцию фильтра к результату последнего фильтра для CVS? Почему CVS просто не делает это автоматически вместо того, чтобы посылать каждый объект через каждый фильтр, или я неправильно думаю о CVS?


person Kevin Quiring    schedule 18.10.2012    source источник


Ответы (2)


Проблема с применением нескольких обработчиков событий фильтра заключается в том, что вызываются все обработчики, а CollectionViewSource не учитывает отдельные результаты e.Accepted. Результатом всегда будет значение e.Accepted в последнем обработчике событий.

Я создал класс менеджера, позволяющий обрабатывать несколько функций FilterEventHandler и обрабатывать их результаты с помощью логики И или ИЛИ. Таким образом, либо все фильтры возвращаются как истинные, либо хотя бы один фильтр дает истинные результаты.

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
}

Просто добавьте и удалите обработчики событий в свойстве Filter объекта MultipleFilterHandler по мере необходимости, и он будет управлять подключением CollectionViewSource.

person jnosek    schedule 12.04.2013
comment
Моя ситуация заключалась в том, что я добавлял несколько обработчиков событий фильтра во время выполнения (для флажков в графическом интерфейсе, когда они были проверены). Я получал непредсказуемые результаты. Я попробую и отредактирую результаты здесь. - person JWP; 07.08.2015

Вы можете сделать это:

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, заставляя ваши фильтры работать вместе.

РЕДАКТИРОВАТЬ: это было сделано в .NET 4.5

person Yuri Almeida    schedule 13.12.2014