При разработке интерфейсов на обычных формах в платформе «1С:Предприятие» программисты часто сталкиваются с неприятным ограничением: при попытке установить отбор строк в табличном поле, связанном с объектом ТаблицаЗначений, система выдает ошибку: «Поле объекта не обнаружено (ОтборСтрок)».
Давайте подробно разберем, почему возникает эта ошибка, и рассмотрим эффективные практические способы реализации фильтрации данных на обычных формах.
В обычных формах элемент управления ТабличноеПоле ведет себя по-разному в зависимости от того, какой тип данных назначен в его свойстве Данные. Свойство ОтборСтрок доступно «из коробки» только тогда, когда источником данных выступает ТабличнаяЧасть прикладного объекта (справочника, документа или обработки). Если же мы связываем поле с динамически созданной в памяти ТаблицейЗначений, свойство ОтборСтрок у элемента управления не инициализируется. Платформа просто не предусматривает встроенного интерактивного механизма отбора для произвольных коллекций в памяти.
Тем не менее, задачу фильтрации решать нужно. Рассмотрим четыре проверенных архитектурных решения этой проблемы.
Если структура колонок вашей таблицы известна заранее или вы можете зафиксировать её на этапе разработки, самым простым и надежным решением будет перенос данных в реальную или вспомогательную табличную часть обработки или документа.
Создадим в нашей обработке табличную часть (например, с именем ВременныеДанные). В этом случае мы получаем полный доступ к механизму отборов платформы. Настроить фильтрацию на форме мы сможем буквально парой строк кода.
Рассмотрим пример простой установки отбора по значению:
// Устанавливаем отбор по конкретному комментарию
ЭлементыФормы.ТабличноеПолеДанные.ОтборСтрок.Комментарий.Установить(ЗначениеОтбора);
// Для отключения отбора и возврата к полному списку строк используем:
ЭлементыФормы.ТабличноеПолеДанные.ОтборСтрок.Комментарий.Установить(, Ложь);
Если нам требуется реализовать сложный или нетривиальный отбор (например, поиск по вхождению подстроки или по списку значений), мы можем задействовать расширенное управление свойствами отбора:
ЭлементОтбора = ЭлементыФормы.ТабличноеПолеДанные.ОтборСтрок.Комментарий;
ЭлементОтбора.Использование = Истина;
ЭлементОтбора.ВидСравнения = ВидСравнения.Содержит;
ЭлементОтбора.Значение = "Важная информация";
Если структура таблицы формируется строго динамически при загрузке внешнего файла (как описывает автор темы) и мы не можем заранее создать табличную часть в конфигураторе, применим стратегию разделения данных. Мы будем хранить исходные полные данные в скрытом реквизите формы или переменной модуля, а пользователю на форме показывать отфильтрованный результат.
Определим в модуле формы переменную для хранения полных данных:
Перем ТЗ_Исходная;
При загрузке файла мы инициализируем эту переменную, заполняем её данными и копируем структуру в основную таблицу, привязанную к элементу формы (пусть она называется ТЗ_НаФорме).
Создадим процедуру, которая будет вызываться при изменении поля ввода с фильтром на форме:
Процедура ПриИзмененииОтбора()
// Если поле отбора очистили, показываем всю исходную таблицу
Если Не ЗначениеЗаполнено(ЗначениеОтбора) Тогда
ТЗ_НаФорме = ТЗ_Исходная.Скопировать();
ЭлементыФормы.ТабличноеПоле.СоздатьКолонки();
Возврат;
КонецЕсли;
// Выполняем поиск строк по точному совпадению
ПараметрыОтбора = Новый Структура("Комментарий", ЗначениеОтбора);
НайденныеСтроки = ТЗ_Исходная.НайтиСтроки(ПараметрыОтбора);
// Заполняем отображаемую на форме таблицу найденным подмножеством строк
ТЗ_НаФорме = ТЗ_Исходная.Скопировать(НайденныеСтроки);
ЭлементыФормы.ТабличноеПоле.СоздатьКолонки();
КонецПроцедуры
Важное ограничение: метод НайтиСтроки() выполняет поиск исключительно по строгому равенству. Если вам нужно реализовать поиск по части строки, диапазону дат или чисел, данный способ не подойдет. В таких случаях переходим к следующему варианту.
Чтобы реализовать полноценный механизм поиска (включая такие виды сравнения, как «Содержит», «В списке», «Больше или равно»), воспользуемся объектом ПостроительЗапроса. Этот объект замечателен тем, что умеет работать с таблицами значений в оперативной памяти так же легко, как и с таблицами базы данных.
Рассмотрим, как программно настроить фильтрацию произвольной таблицы значений:
Процедура ПрименитьГибкийОтбор()
Построитель = Новый ПостроительЗапроса;
// Оборачиваем нашу исходную таблицу в специальное описание источника данных
Построитель.ИсточникДанных = Новый ОписаниеИсточникаДанных(ТЗ_Исходная);
// Добавляем отбор по нужной колонке
НовыйОтбор = Построитель.Отбор.Добавить("Комментарий");
НовыйОтбор.Использование = Истина;
НовыйОтбор.ВидСравнения = ВидСравнения.Содержит;
НовыйОтбор.Значение = ПолеВводаФильтра;
// Выполняем построение и выгружаем результат фильтрации обратно в форму
Построитель.Выполнить();
ТЗ_НаФорме = Построитель.Результат.Выгрузить();
// Обновляем отображение колонок на форме
ЭлементыФормы.ТабличноеПоле.СоздатьКолонки();
КонецПроцедуры
Преимущество этого метода заключается в том, что пользователь может использовать любые стандартные типы сравнения 1С, а скорость работы построителя запроса на таблицах умеренного объема (до десятков тысяч строк) остается практически мгновенной.
Если перед фильтрацией данных нам требуется произвести сложные вычисления, соединить загруженные из файла строки со справочниками базы данных или применить сложные логические условия в секции ГДЕ, наиболее производительным решением будет использование полноценного SQL-запроса через временные таблицы.
Рассмотрим программную реализацию фильтрации через объект Запрос:
Процедура ОтборСтрокЧерезЗапрос()
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
// Передаем нашу ТЗ как параметр и помещаем её во временную таблицу
Запрос.Текст =
"ВЫБРАТЬ * ПОМЕСТИТЬ ВтИсходныеДанные ИЗ &ВТ КАК ВТ;
|/////////////////////////////////////////////////
|ВЫБРАТЬ * ИЗ ВтИсходныеДанные КАК Т
|ГДЕ Т.Комментарий ПОДОБНО &ШаблонОтбора";
Запрос.УстановитьПараметр("ВТ", ТЗ_Исходная);
Запрос.УстановитьПараметр("ШаблонОтбора", "%" + ПолеВводаФильтра + "%");
// Результат запроса выгружаем непосредственно в таблицу формы
ТЗ_НаФорме = Запрос.Выполнить().Выгрузить();
ЭлементыФормы.ТабличноеПоле.СоздатьКолонки();
КонецПроцедуры
Этот способ незаменим, когда помимо фильтрации вам необходимо сразу обогатить данные актуальной информацией из базы данных 1С (например, подтянуть актуальные цены номенклатуры или остатки на складах по загруженным артикулам).
Таким образом, несмотря на отсутствие встроенного свойства ОтборСтрок у таблиц значений на обычных формах, мы имеем в арсенале несколько надежных и гибких инструментов для решения этой задачи.