При разработке интерфейсов на управляемых формах в 1С часто возникает задача организации связи двух табличных частей по принципу «мастер — деталь». Типичный пример: в основной таблице пользователь выбирает строку (например, продукцию или раздел), а в подчиненной табличной части должны отображаться только те строки, которые относятся к текущему выбранному элементу (например, сырье, материалы или товары выбранного раздела).
Разберем, как устроен этот механизм на уровне платформы «1С:Предприятие 8.3», почему табличная часть может неожиданно оказаться пустой и как правильно реализовать фильтрацию строк программно.
Для быстрой фильтрации строк таблицы, отображающей данные табличной части объекта, платформа предоставляет свойство элемента формы ОтборСтрок. Оно принимает значение типа ФиксированнаяСтруктура, где ключами выступают имена колонок табличной части, а значениями — фильтруемые данные.
Проанализируем базовый код, который разработчики обычно помещают в обработчик события ПриАктивизацииСтроки ведущей таблицы:
&НаКлиенте
Процедура ВыходныеИзделияПриАктивизацииСтрокиПосле(Элемент)
ТекДанныеВыходныеИзделия = Элементы.ВыходныеИзделия.ТекущиеДанные;
Если ТекДанныеВыходныеИзделия = Неопределено Тогда
Элементы.МатериалыИРаботы.ОтборСтрок = Неопределено;
Иначе
ТекНоменклатура = ТекДанныеВыходныеИзделия.Номенклатура;
Элементы.МатериалыИРаботы.ОтборСтрок = Новый ФиксированнаяСтруктура("Номенклатура", ТекНоменклатура);
КонецЕсли;
КонецПроцедуры
На первый взгляд код выглядит абсолютно корректным. Однако при его тестировании разработчики нередко сталкиваются с ситуацией: при выборе первой строки подчиненная таблица отображает данные, а при переходе на другие строки внезапно становится абсолютно пустой. Выясним причину такого поведения.
Когда программный код установки свойства ОтборСтрок синтаксически верен, но подчиненная таблица пуста, корень проблемы практически всегда кроется в несоответствии реальных данных условию отбора.
Рассмотрим специфику документа ПроизводствоБезЗаказа в конфигурации «1С:ERP Управление предприятием»:
ВыходныеИзделия в реквизите Номенклатура указывается готовая продукция. В табличной части МатериалыИРаботы в реквизите Номенклатура указываются исходные компоненты, материалы и полуфабрикаты. Они физически не совпадают, за исключением редких ситуаций разборки или переработки изделия «в само себя». Попытка сопоставить их по полю Номенклатура приводит к тому, что платформа ищет строки материалов, у которых номенклатура в точности равна готовой продукции. Естественно, таких строк не находится, и таблица становится пустой.НомерГруппыЗатрат.Если в документе включена построчная группировка затрат (варианты «По продукции», «По продукции и назначениям» или «По спецификациям»), строки выпуска и строки затрат обладают одинаковым значением НомерГруппыЗатрат. Для корректной фильтрации нам необходимо накладывать отбор именно по этой числовой колонке.
Посмотрим на пример правильной реализации фильтрации:
&НаКлиенте
Процедура ВыходныеИзделияПриАктивизацииСтрокиПосле(Элемент)
ТекДанные = Элементы.ВыходныеИзделия.ТекущиеДанные;
Если ТекДанные = Неопределено Или Не ЗначениеЗаполнено(ТекДанные.НомерГруппыЗатрат) Тогда
// Снимаем отбор, если строка не выбрана или группа затрат не определена
Если Элементы.МатериалыИРаботы.ОтборСтрок <> Неопределено Тогда
Элементы.МатериалыИРаботы.ОтборСтрок = Неопределено;
КонецЕсли;
Иначе
// Проверяем, изменился ли отбор, чтобы избежать лишней перерисовки формы
ТекущийОтбор = Элементы.МатериалыИРаботы.ОтборСтрок;
Если ТекущийОтбор = Неопределено Или ТекущийОтбор.НомерГруппыЗатрат <> ТекДанные.НомерГруппыЗатрат Тогда
Элементы.МатериалыИРаботы.ОтборСтрок = Новый ФиксированнаяСтруктура("НомерГруппыЗатрат", ТекДанные.НомерГруппыЗатрат);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Событие ПриАктивизацииСтроки генерируется платформой очень часто: при навигации стрелками по клавиатуре, при программных обновлениях, при перерисовке таблицы. Если при каждом таком вызове сразу выполнять тяжелую перенастройку зависимых элементов, интерфейс начнет подвисать или мерцать.
В типовых конфигурациях (например, в документе «Таможенная декларация на импорт» для разделов и товаров) применяется паттерн с отложенным вызовом процедуры установки отбора через ПодключитьОбработчикОжидания.
Разберем по шагам реализацию этого подхода:
ФиксированнаяСтруктура.
&НаКлиенте
Процедура РазделыПриАктивизацииСтроки(Элемент)
// Подключаем однократный вызов через 0.2 секунды
ПодключитьОбработчикОжидания("АктивироватьРаздел", 0.2, Истина);
КонецПроцедуры
&НаКлиенте
Процедура АктивироватьРаздел()
ТекДанные = Элементы.Разделы.ТекущиеДанные;
Товары = Элементы.Товары;
Если ТекДанные = Неопределено Тогда
Если Товары.ОтборСтрок <> Неопределено Тогда
Товары.ОтборСтрок = Неопределено;
КонецЕсли;
Возврат;
КонецЕсли;
РазделОтбора = ТекДанные.НомерРаздела;
// Включаем или обновляем отбор, только если значение изменилось
Если Товары.ОтборСтрок = Неопределено Или Товары.ОтборСтрок.НомерРаздела <> РазделОтбора Тогда
Товары.ОтборСтрок = Новый ФиксированнаяСтруктура("НомерРаздела", РазделОтбора);
КонецЕсли;
КонецПроцедуры
При использовании платформенного свойства ОтборСтрок необходимо учитывать несколько строгих правил:
=). Нельзя передать условие вхождения в массив («в списке»), логическое «НЕ» или сравнение больше/меньше.Номенклатура.ВидНоменклатуры), или искусственные колонки формы.ОтборСтрок, то при интерактивном добавлении новой строки (по кнопке «Добавить» или клавише Insert) платформа автоматически подставит в соответствующие колонки новой строки те значения, по которым установлен фильтр.ТекущиеДанные вернет Неопределено. Программный код обязательно должен содержать ветку для сброса отбора: Элементы.ТаблицаПриемник.ОтборСтрок = Неопределено.