Как фильтровать несколько подэлементов в ObjectListView - PullRequest
1 голос
/ 21 марта 2012

Итак, я пытаюсь программно добавить ModelFilter в мой ObjectListView, который будет рассматривать два (или более) столбца и фильтры для каждого в отдельности.В настоящее время я думаю, что ObjectListView поддерживает только один фильтр, но я могу что-то упустить в коде / документации.

Например, один из моих предполагаемых фильтров - это посмотреть на столбец «Активный», который имеет значенияиз "А" или "Т".Другой столбец - это имя руководителя.Итак, я хочу найти все записи, где 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

Ответы [ 2 ]

7 голосов
/ 18 апреля 2012

Я уверен, что решение 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 голос
/ 22 марта 2012

Хотя я еще не до конца понимаю вашу сделку, я сделаю попытку с PredicateBuilder , который является частью сборки LINQKit, которую вы можете загрузить здесь .

Таким образом, фильтрация по нескольким столбцам станет легкой.Возможно, вы рассмотрите возможность сброса привязки вашего ObjectListView элемента управления после того, как ваша исходная коллекция будет отфильтрована.

В общем, я хотел бы сделать следующее:

  1. Загрузить данные;
  2. Отображать их с помощью привязки данных;
  3. После того, как столбец будет выбран для фильтра, вызовите метод «Фильтр», который будет применять ваши предикаты;
  4. Восстановите контрольс новой отфильтрованной коллекцией.

Пожалуйста, обратитесь к документации PredicateBuilder по ссылке, предоставленной ранее.Другой пример построения динамических фильтров иллюстрируется здесь: « Как бы этот запрос преобразовался в динамическое выражение Linq? » для поисковой системы, которую я реализовал.

В моем случае фильтры были применены непосредственно к результатам базы данных.Кроме того, он может даже использоваться в вашей ситуации с данными в памяти, поскольку он основан на Linq.

Я уверен, что смогу предоставить дополнительную помощь, когда вы опубликуете пример кода для фильтрации информации..

РЕДАКТИРОВАТЬ # 1

После того, как я прочитал предоставленный пример кода, вот то, что, как я считаю, сработает.Что касается свойства Searchable, я не знаком с этим подходом, поэтому, возможно, я могу пропустить что-то важное в вашем коде, и если это так, не стесняйтесь указать мне, что я мог упустить.=)

Обратите внимание, что я предполагаю, что все ваши данные являются строковыми, поскольку я проверяю, является ли ваш элемент данных нулевым или пробелом.Кроме того, на мой взгляд, отфильтровать набор результатов - это отобразить только те записи, которые соответствуют определенному критерию.Вы не хотите видеть то, что не соответствует критерию.Это то же самое, что и предложение WHERE в SQL.

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.

Thisкод предоставляется как есть и не тестировался, за исключением обоих методов расширения строки.

...